#34884: Half bug/half enhancement : inconsistent behavior of get_or_create()
regarding related attributes cache
-------------------------------------+-------------------------------------
Reporter: Laurent Lyaudet | Owner: nobody
Type: Uncategorized | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
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
-------------------------------------+-------------------------------------
Comment (by Laurent Lyaudet):
I coded a monkey patch for my use case where it will not be soon to
upgrade Django and in case some bikeshedding occurs that puts to trash
coherency and efficiency in yet another open source software where some
people against free software have influence.
Here it is :
`get_or_create_monkey_patch.py`
{{{
from django.db.models import QuerySet, ForeignKey
original_get_or_create = QuerySet.get_or_create
def patched_get_or_create(self, defaults=None, **kwargs):
result, created = original_get_or_create(self, defaults=defaults,
**kwargs)
if defaults is not None:
for key, value in defaults.items():
if isinstance(result._meta.get_field(key), ForeignKey):
# isinstance handles OneToOneField also.
setattr(result, key, value)
for key, value in kwargs.items():
if isinstance(result._meta.get_field(key), ForeignKey):
# isinstance handles OneToOneField also.
setattr(result, key, value)
return result, created
QuerySet.get_or_create = patched_get_or_create
}}}
You can execute it at the end of the previous script + some test and
obtain this:
{{{
In [15]: from django.db.models import QuerySet, ForeignKey
In [16]: original_get_or_create = QuerySet.get_or_create
In [17]: def patched_get_or_create(self, defaults=None, **kwargs):
...: result, created = original_get_or_create(self,
defaults=defaults, **kwargs)
...: if defaults is not None:
...: for key, value in defaults.items():
...: if isinstance(result._meta.get_field(key),
ForeignKey):
...: # isinstance handles OneToOneField also.
...: setattr(result, key, value)
...: for key, value in kwargs.items():
...: if isinstance(result._meta.get_field(key), ForeignKey):
...: # isinstance handles OneToOneField also.
...: setattr(result, key, value)
...: return result, created
...:
In [18]: QuerySet.get_or_create = patched_get_or_create
In [19]: permission, created =
Permission.objects.get_or_create(name="Test", content_type=content_type,
codename="Test")
In [20]: created
Out[20]: False
In [21]: connection.queries
Out[21]:
[{'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.000'},
{'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 [22]: permission.content_type
Out[22]: <ContentType: permission>
In [23]: connection.queries
Out[23]:
[{'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.000'},
{'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 [24]:
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34884#comment:1>
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/0107018ae3708c06-a1da014b-afc0-469c-a29b-732a1c972bcf-000000%40eu-central-1.amazonses.com.