#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.