Opened 12 years ago
Closed 9 years ago
#19531 closed Cleanup/optimization (fixed)
Surprising impact of defer()
Reported by: | Vlada Macek | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.4 |
Severity: | Normal | Keywords: | defer only |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I have Counter model with a few fields. When I call:
>>> cnt=Counter.objects.only('logs').get(id=2349497)
it results in SQL (Postgres):
SELECT "visits_counter"."id", "visits_counter"."logs" FROM "visits_counter" WHERE "visits_counter"."id" = 2349497
That's fine. When I want to directly update the logs field in the database like this:
cnt._default_manager.filter(pk=cnt.pk).update(logs=4)
it results in SQL (Postgres):
SELECT U0."id" FROM "visits_counter" U0 WHERE U0."id" = 2349497 UPDATE "visits_counter" SET "logs" = 4 WHERE "visits_counter"."id" IN (2349497)
which looks strange to me (1. the unnecessary first query, 2. IN in the second). I finally get expected behavior by doing
cnt._meta.concrete_model._default_manager.filter(pk=cnt.pk).update(logs=4)
SQL:
UPDATE "visits_counter" SET "logs" = 4 WHERE "visits_counter"."id" = 2349497
Is it a bug or feature? Am I getting something really wrong?
Change History (2)
comment:1 by , 12 years ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 9 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
It looks like this effectively fixed by 99321e30cebbffeafc6ae19f4f92a0a665cbf19b (#18306) as the added tests demonstrate.
In 1.5 you could use
cnt = Counter.objects.only('logs').get(id=2349497); cnt.logs=4; cnt.save()
- 1.5 will automatically update only those fields loaded (or modified since load).As for the SELECT in the second clause - I think this is because Django mixes proxy and "real" inheritance in the update code. But this isn't necessary, using the concrete_model and the proxied model should work equivalently in this case. And, the reason for the proxy model is the internal implementation of deferred loading.
I haven't verified the behavior in master, still marking accepted on the basis of proxy <-> concrete model .update() behavior difference.