Code

Opened 19 months ago

Last modified 19 months ago

#19531 new Cleanup/optimization

Surprising impact of defer()

Reported by: Tuttle 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?

Attachments (0)

Change History (1)

comment:1 Changed 19 months ago by akaariai

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Uncategorized to Cleanup/optimization

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.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as new
The owner will be changed from nobody to anonymous. Next status will be 'assigned'
as The resolution will be set. Next status will be 'closed'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.