#24048 closed Bug (fixed)
only() doesn't override fields included in defer() as documented
Reported by: | Will Earp | Owned by: | Ryan Cheley |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | defer, only, QuerySet, DeferredAttribute |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The docs give the following example for the QuerySet
API's only
:
# Final result loads headline and body immediately (only() replaces any # existing set of fields). Entry.objects.defer("body").only("headline", "body")
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.only
I understand this to mean that "body" will be loaded i.e. not a deferred field. When testing this, however, "body" is still considered a DeferredAttribute
. Is this a possible bug or does the documentation need changing?
Change History (11)
follow-up: 3 comment:1 by , 10 years ago
Summary: | potential bug with defer() and only() → only() doesn't override fields included in defer() as documented |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 10 years ago
It looks as if the only()
's "problem" is caused by add_immediate_loading()
. Taking the example above, field_names.difference(existing)
in the method evaluates to set(["value", "name"]).difference(set["name"])
.
Cut a story short, self.deferred_loading
is set(["value"]), False
when it should be set(["name", "value"]), False
.
If the problem is to be fixed, is it best addressed in add_immediate_loading()
or only()
?
comment:3 by , 10 years ago
Replying to timgraham:
I checked back to 29050ef999e1931efb6c62471c7e07d2ea5e96ea where
defer()
was added and this assertion intests/defer
(or its equivalent in the original doc test) fails,self.assert_delayed(qs.defer("name").only("value", "name")[0], 1)
as "name" is indeed deferred despite its inclusion inonly()
. It seems expected to me thatonly()
would overridedefer()
so we should see about making that change, but if we can't due to backwards compatibility or implementation, we should definitely correct the docs.
Looking at the comment for only()
it says,
Only the fields passed into this method and that are not already specified as deferred are loaded immediately when the queryset is evaluated.
This would mean that the method behaves as intended and the documentation is incorrect. add_immediate_loading()
(which is called by only()
) also behaves in the same way, not overriding deferred fields passed to it.
comment:4 by , 9 years ago
The documentation was updated in the meantime, it seems this ticket can be closed.
comment:5 by , 9 years ago
What commit updated the documentation? The incorrect example quoted in the ticket description is still there as far as I see.
comment:6 by , 2 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:7 by , 2 years ago
In ticket:24048#comment:4 refers to the doc string for the docstring for the only()
method being updated, not the documentation.
The documentation referenced above is still in the docs. I'll be reviewing that shortly
comment:8 by , 2 years ago
It does appear that there is a contradiction in the only()
method doc string when compared to the documentation
Since the doc string for the method is correct AND making changes to the way that the defer()
and only()
function now may break things for code bases that are already in production, I believe that the documentation should be updated to clearly state what is happening, i.e. that the use of defer()
with only()
will result in defer()
overriding only()
for fields that are listed in both.
I'm still working out how to express that though. Once done, I'll submit a PR to update the docs and reference this ticket.
I checked back to 29050ef999e1931efb6c62471c7e07d2ea5e96ea where
defer()
was added and this assertion intests/defer
(or its equivalent in the original doc test) fails,self.assert_delayed(qs.defer("name").only("value", "name")[0], 1)
as "name" is indeed deferred despite its inclusion inonly()
. It seems expected to me thatonly()
would overridedefer()
so we should see about making that change, but if we can't due to backwards compatibility or implementation, we should definitely correct the docs.