[Django] #36713: RecursionError with only() and fields usage in __init__

2 views
Skip to first unread message

Django

unread,
Nov 6, 2025, 4:23:07 AM (6 days ago) Nov 6
to django-...@googlegroups.com
#36713: RecursionError with only() and fields usage in __init__
------------------------------+-----------------------------------------
Reporter: Michal Čihař | Type: Uncategorized
Status: new | Component: Uncategorized
Version: 5.2 | Severity: Normal
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+-----------------------------------------
Django ends up in infinite recursion when combining `only()` and accessing
class attributes in `__init__`:

{{{
File "/tmp/django-recursion-test/app/models.py", line 14, in __init__
print(self.descriptions)
^^^^^^^^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query_utils.py", line 267, in __get__
instance.refresh_from_db(fields=[field_name])
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/base.py", line 758, in refresh_from_db
db_instance = db_instance_qs.get()
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 633, in get
num = len(clone)
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 370, in __len__
self._fetch_all()
~~~~~~~~~~~~~~~^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 1995, in _fetch_all
self._result_cache = list(self._iterable_class(self))
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 126, in __iter__
obj = model_cls.from_db(
db, init_list, row[model_fields_start:model_fields_end]
)
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/base.py", line 605, in from_db
new = cls(*values)
File "/tmp/django-recursion-test/app/models.py", line 15, in __init__
print(self.notes)
^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query_utils.py", line 267, in __get__
instance.refresh_from_db(fields=[field_name])
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/base.py", line 758, in refresh_from_db
db_instance = db_instance_qs.get()
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 633, in get
num = len(clone)
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 370, in __len__
self._fetch_all()
~~~~~~~~~~~~~~~^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 1995, in _fetch_all
self._result_cache = list(self._iterable_class(self))
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/query.py", line 126, in __iter__
obj = model_cls.from_db(
db, init_list, row[model_fields_start:model_fields_end]
)
File "/tmp/django-test/lib/python3.13/site-
packages/django/db/models/base.py", line 605, in from_db
new = cls(*values)
File "/tmp/django-recursion-test/app/models.py", line 14, in __init__
print(self.descriptions)
^^^^^^^^^^^^^^^^^
}}}

Preconditions for the error:

* Model with multiple fields
* Using at least two model fields in `__init__` (it does work fine with
accessing just one)
* Using `only()` with fields used in `__init__` but missing a field that
will be used later

To trigger this error, following model was used:

{{{
class Project(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=100)
descriptions = models.TextField()
notes = models.TextField()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
print(self.descriptions)
print(self.notes)
}}}

And this is the code to trigger it:

{{{
Project.objects.create(name="Test", slug="test")
projects = Project.objects.only("descriptions", "notes")
# object is constructed and the field included only can be
accessed:
self.assertEqual(projects[0].notes, "")
# this fails with RecursionError
self.assertEqual(projects[0].slug, "test")
}}}

Reproduced with both Django 5.2 and 6.0b1.

Reproducing tests are available at https://github.com/nijel/django-
recursion-test.
--
Ticket URL: <https://code.djangoproject.com/ticket/36713>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Nov 6, 2025, 8:43:33 AM (6 days ago) Nov 6
to django-...@googlegroups.com
#36713: RecursionError with only() and fields usage in __init__
-------------------------------+--------------------------------------
Reporter: Michal Čihař | Owner: (none)
Type: Uncategorized | Status: closed
Component: Uncategorized | Version: 5.2
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Simon Charette):

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

Comment:

Please
[https://docs.djangoproject.com/en/5.2/ref/models/instances/#django.db.models.Model
refer to the documentation] about `Model.__init__` and the note about
overriding it

> You may be tempted to customize the model by overriding the `__init__`
method. If you do so, however, take care not to change the calling
signature as any change may prevent the model instance from being saved.
**Additionally, referring to model fields within `__init__` may
potentially result in infinite recursion errors in some circumstances**.

You can refer to #31435 for some discussion on the subject but the TL;DR
is that your `__init__` override **must** account for some fields being
potentially deferred.
--
Ticket URL: <https://code.djangoproject.com/ticket/36713#comment:1>
Reply all
Reply to author
Forward
0 new messages