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

-- 
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 visit 
https://groups.google.com/d/msgid/django-updates/0107019a5879f9df-22bbfebc-b0e9-4c9a-b618-2dfe500d6656-000000%40eu-central-1.amazonses.com.

Reply via email to