#34884: Half bug/half enhancement : inconsistent behavior of get_or_create()
regarding related attributes cache
-------------------------------------+-------------------------------------
               Reporter:  LLyaudet   |          Owner:  nobody
                   Type:             |         Status:  new
  Uncategorized                      |
              Component:  Database   |        Version:  dev
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:  ORM get_or_create
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Hello,
 The sample script below demonstrates that get_or_create() avoid
 unnecessary DB query for related object given as argument only if created
 is True.
 It would be nice if the case created is False could be made coherent with
 it.
 Setting the cache when possible would avoid having to do all over the
 code:

 {{{
 my_object = MyModel.objects.get_or_create(related_object=related_object)
 my_object.related_object = related_object
 }}}


 I can code a patch and provide it in a few days if my idea is accepted :)
 Here is the script:


 {{{
 In [1]: from django.db import connection

 In [2]: from django.contrib.contenttypes.models import ContentType

 In [3]: from django.contrib.auth.models import Permission

 In [4]: content_type = ContentType.objects.get_for_model(Permission)

 In [5]: permission, created =
 Permission.objects.get_or_create(name="Test", content_type=content_type,
 codename="Test")

 In [6]: created
 Out[6]: True

 In [7]: connection.queries
 Out[7]:
 [{'sql': "SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON
 typnamespace = ns.oid WHERE typname = 'hstore'",
   'time': '0.001'},
  {'sql': "SELECT typarray FROM pg_type WHERE typname = 'citext'",
   'time': '0.000'},
  {'sql': 'SELECT "django_content_type"."id",
 "django_content_type"."app_label", "django_content_type"."model" FROM
 "django_content_type" WHERE ("django_content_type"."app_label" = \'auth\'
 AND "django_content_type"."model" = \'permission\')',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'},
  {'sql': 'INSERT INTO "auth_permission" ("name", "content_type_id",
 "codename") VALUES (\'Test\', 2, \'Test\') RETURNING
 "auth_permission"."id"',
   'time': '0.001'}]

 In [8]: permission.content_type
 Out[8]: <ContentType: permission>

 In [9]: connection.queries
 Out[9]:
 [{'sql': "SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON
 typnamespace = ns.oid WHERE typname = 'hstore'",
   'time': '0.001'},
  {'sql': "SELECT typarray FROM pg_type WHERE typname = 'citext'",
   'time': '0.000'},
  {'sql': 'SELECT "django_content_type"."id",
 "django_content_type"."app_label", "django_content_type"."model" FROM
 "django_content_type" WHERE ("django_content_type"."app_label" = \'auth\'
 AND "django_content_type"."model" = \'permission\')',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'},
  {'sql': 'INSERT INTO "auth_permission" ("name", "content_type_id",
 "codename") VALUES (\'Test\', 2, \'Test\') RETURNING
 "auth_permission"."id"',
   'time': '0.001'}]

 In [10]: permission, created =
 Permission.objects.get_or_create(name="Test", content_type=content_type,
 codename="Test")

 In [11]: created
 Out[11]: False

 In [12]: connection.queries
 Out[12]:
 [{'sql': "SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON
 typnamespace = ns.oid WHERE typname = 'hstore'",
   'time': '0.001'},
  {'sql': "SELECT typarray FROM pg_type WHERE typname = 'citext'",
   'time': '0.000'},
  {'sql': 'SELECT "django_content_type"."id",
 "django_content_type"."app_label", "django_content_type"."model" FROM
 "django_content_type" WHERE ("django_content_type"."app_label" = \'auth\'
 AND "django_content_type"."model" = \'permission\')',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'},
  {'sql': 'INSERT INTO "auth_permission" ("name", "content_type_id",
 "codename") VALUES (\'Test\', 2, \'Test\') RETURNING
 "auth_permission"."id"',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'}]

 In [13]: permission.content_type
 Out[13]: <ContentType: permission>

 In [14]: connection.queries
 Out[14]:
 [{'sql': "SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON
 typnamespace = ns.oid WHERE typname = 'hstore'",
   'time': '0.001'},
  {'sql': "SELECT typarray FROM pg_type WHERE typname = 'citext'",
   'time': '0.000'},
  {'sql': 'SELECT "django_content_type"."id",
 "django_content_type"."app_label", "django_content_type"."model" FROM
 "django_content_type" WHERE ("django_content_type"."app_label" = \'auth\'
 AND "django_content_type"."model" = \'permission\')',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'},
  {'sql': 'INSERT INTO "auth_permission" ("name", "content_type_id",
 "codename") VALUES (\'Test\', 2, \'Test\') RETURNING
 "auth_permission"."id"',
   'time': '0.001'},
  {'sql': 'SELECT "auth_permission"."id", "auth_permission"."name",
 "auth_permission"."content_type_id", "auth_permission"."codename" FROM
 "auth_permission" WHERE ("auth_permission"."codename" = \'Test\' AND
 "auth_permission"."content_type_id" = 2 AND "auth_permission"."name" =
 \'Test\')',
   'time': '0.001'},
  {'sql': 'SELECT "django_content_type"."id",
 "django_content_type"."app_label", "django_content_type"."model" FROM
 "django_content_type" WHERE "django_content_type"."id" = 2',
   'time': '0.001'}]
 }}}

 Best regards,
      Laurent Lyaudet

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34884>
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/0107018ae206436b-f6748db4-fd20-40b5-ac6c-a564c6d97d8f-000000%40eu-central-1.amazonses.com.

Reply via email to