Opened 3 years ago

Closed 3 years ago

#20927 closed Bug (wontfix)

Include known related fields for subclassed "QuerySet.only"

Reported by: lvo@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.5
Severity: Normal Keywords: queryset, only, related manager, manager
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have a model like these:

class PNRSegment(models.Model):
    pnr = models.ForeignKey('booking.PassengerNameRecord', related_name="segments")
    arrival_datetime = models.DateTimeField()

    objects = PNRSegmentManager()

Also i wrote my own Manager with own QuerySet:

class PNRSegmentManager(models.Manager):
    use_for_related_fields = True

    def get_query_set(self):
        return PNRSegmentQuerySet(self.model, using=self._db)

    def latest_datetime(self):
        return self.get_query_set().latest_datetime()


class PNRSegmentQuerySet(QuerySet):
    def latest_datetime(self):
        try:
            return self.order_by('-arrival_datetime')[0].arrival_datetime
        except IndexError:
            return None

I noticed that QuerySet.only has strange behavior:

# When launching pdb into PNRSegmentQuerySet.latest_datetime:
(Pdb) pp self
[<PNRSegment: PNRSegment object>, <PNRSegment: PNRSegment object>]
(Pdb) pp self.count()
2
(Pdb) pp self[0]
<PNRSegment: PNRSegment object>
(Pdb) pp self.only('arrival_datetime').count()
2
(Pdb) pp self.only('arrival_datetime')[0]
*** IndexError: IndexError(("PNRSegment matching query does not exist. Lookup parameters were {'pk': None}",),)

After tracing of QuerySet.clone i found my error: when subclassing QuerySet for related manager, each QuerySet.only call should contain related field:

(Pdb) pp self.only('arrival_datetime', 'pnr')[0]
<PNRSegment_Deferred_airline_code_class_code_ ... cutted ...>

I think that this is not obvious behaviour. QuerySet.only should authomatically include all fields from QuerySet._known_related_objects.

Change History (4)

comment:1 Changed 3 years ago by sduveen

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset
Resolution: invalid
Status: newclosed

only() is about the fields returned. It's specifically used to limit fields and you use it so that it won't include additional ones. If you want defaults, then don't use only()

comment:2 Changed 3 years ago by sduveen

Resolution: invalid
Status: closednew

seeing if we can make a useful test

comment:3 Changed 3 years ago by sduveen

seems to be working in 1.6 and master.

This test shows we can do a query that has a manager and foreignkey object.
https://github.com/schuyler1d/django/commit/047c131bc96a844d2769f3a4c5612119330413a1

comment:4 Changed 3 years ago by sduveen

Resolution: wontfix
Status: newclosed
Note: See TracTickets for help on using tickets.
Back to Top