Opened 4 months ago

Last modified 7 weeks ago

#31506 assigned Bug

ExpressionWrapper() doesn't respect output_field when combining DateField and timedelta on PostgreSQL and MySQL.

Reported by: Matthieu Rigal Owned by: TapanGujjar
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Josh Smeaton, Sergey Fedoseev Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The problem actually exists since 1.11 to 2.2, probably also in 3.X. Lastly tested with Django 2.2.12 and psycopg2 2.8.3

Take the model

StartModel(models.Model):
    start = models.DateField()

When working on the queryset in this way:

next_segments = StartModel.objects.filter('start__gt': OuterRef('start')).order_by('start')
qs = StartModel.objects.annotate(
            end=ExpressionWrapper(
                Subquery(next_segments.values('start')[:1]) - datetime.timedelta(days=1),
                output_field=DateField(),
            )
        )

qs.first().end is of type datetime, not date...

Attachments (1)

test_31506.diff (1.1 KB) - added by felixxm 4 months ago.

Download all attachments as: .zip

Change History (5)

comment:1 Changed 4 months ago by felixxm

Cc: Josh Smeaton added
Summary: ExpressionWrapper on DateField + timedelta always returns DateTimeField, should DateFieldExpressionWrapper() doesn't respect output_field when combining DateField and timedelta on PostgreSQL and MySQL.
Triage Stage: UnreviewedAccepted
Version: 2.2master

Thanks for this ticket. I reproduced this issue on MySQL and PostgreSQL. I attached a simple test.

Reproduced at 060d9d4229c436c44cf8e3a301f34c4b1f9f6c85.

Changed 4 months ago by felixxm

Attachment: test_31506.diff added

comment:2 Changed 3 months ago by TapanGujjar

Owner: changed from nobody to TapanGujjar
Status: newassigned

comment:3 Changed 3 months ago by TapanGujjar

Hi, the issue is because the DateField has no field converter or db_converter to convert the value which we got from the database to the DateField type. I can implement the field converter for the data field but Is the DateField not having the field converter or db_converter by design?

comment:4 Changed 7 weeks ago by Sergey Fedoseev

Cc: Sergey Fedoseev added

ExpressionWrapper allows you to specify the type returned by backend and at least on PostgreSQL it's not date:

test=# SELECT pg_typeof('1999-01-08'::date - '1 days'::interval);
          pg_typeof          
-----------------------------
 timestamp without time zone
(1 row)

Instead you could use

ExpressionWrapper(
    Subquery(next_segments.values('start')[:1]) - 1,
    output_field=DateField(),
)
Note: See TracTickets for help on using tickets.
Back to Top