#34884: Half bug/half enhancement : inconsistent behavior of get_or_create()
regarding related attributes cache
-------------------------------------+-------------------------------------
     Reporter:  Laurent Lyaudet      |                    Owner:  nobody
         Type:  Uncategorized        |                   Status:  closed
    Component:  Database layer       |                  Version:  dev
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:  invalid
     Keywords:  ORM get_or_create    |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):

 * status:  new => closed
 * resolution:   => invalid


Comment:

 Hello Laurent, thank you for your ticket.

 As far as I understand your report, the key to your issue is about using
 `select_related` when getting the `Permission` you need. Specifically, see
 how if I create a permission using the content_type's PK, the resulting
 object does not have the ContentType instance fetched by default:

 {{{#!python
 >>> permission, created = Permission.objects.get_or_create(name="Test",
 content_type_id=content_type.pk, codename="OtherTest")
 >>> print("\n\n".join(i["sql"] for i in connection.queries))
 SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = 'OtherTest' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 'Test') LIMIT 21

 BEGIN

 INSERT INTO "auth_permission" ("name", "content_type_id", "codename")
 VALUES ('Test', 2, 'OtherTest') RETURNING "auth_permission"."id"

 COMMIT

 >>> permission.content_type
 <ContentType: Authentication and Authorization | permission>
 >>> print("\n\n".join(i["sql"] for i in connection.queries))
 SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = 'OtherTest' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 'Test') LIMIT 21

 BEGIN

 INSERT INTO "auth_permission" ("name", "content_type_id", "codename")
 VALUES ('Test', 2, 'OtherTest') RETURNING "auth_permission"."id"

 COMMIT

 SELECT "django_content_type"."id", "django_content_type"."app_label",
 "django_content_type"."model" FROM "django_content_type" WHERE
 "django_content_type"."id" = 2 LIMIT 21
 }}}

 You can see the extra query at the end when the `content_type` attribute
 is accessed. Similarly, you can avoid the "extra" query when the object
 exists by doing:

 {{{#!python
 >>> permission, created =
 Permission.objects.select_related("content_type").get_or_create(name="Test",
 content_type_id=content_type.pk, codename="OtherTest")
 >>> print("\n\n".join(i["sql"] for i in connection.queries))
 SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename",
 "django_content_type"."id", "django_content_type"."app_label",
 "django_content_type"."model" FROM "auth_permission" INNER JOIN
 "django_content_type" ON ("auth_permission"."content_type_id" =
 "django_content_type"."id") WHERE ("auth_permission"."codename" =
 'OtherTest' AND "auth_permission"."content_type_id" = 2 AND
 "auth_permission"."name" = 'Test') LIMIT 21

 >>> permission.content_type
 <ContentType: Authentication and Authorization | permission>
 >>> print("\n\n".join(i["sql"] for i in connection.queries))
 SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename",
 "django_content_type"."id", "django_content_type"."app_label",
 "django_content_type"."model" FROM "auth_permission" INNER JOIN
 "django_content_type" ON ("auth_permission"."content_type_id" =
 "django_content_type"."id") WHERE ("auth_permission"."codename" =
 'OtherTest' AND "auth_permission"."content_type_id" = 2 AND
 "auth_permission"."name" = 'Test') LIMIT 21
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34884#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018af1d2e4c7-59ec2fea-8d35-4f5c-a208-e36b2f4f2ce2-000000%40eu-central-1.amazonses.com.

Reply via email to