﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
34884	Half bug/half enhancement : inconsistent behavior of get_or_create() regarding related attributes cache	Laurent Lyaudet	nobody	"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"	Cleanup/optimization	closed	Database layer (models, ORM)	dev	Normal	wontfix	ORM get_or_create	laurent.lyaudet@…	Unreviewed	0	0	0	0	0	0
