Opened 3 years ago

Closed 3 years ago

#32660 closed Bug (invalid)

Endless loop upon delete

Reported by: kr Owned by: exec-life
Component: Database layer (models, ORM) Version: 3.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by kr)

I have three models whereas one has a custom __init__() method:

class Foo(models.Model):
    my_foo = models.CharField(max_length=1000)


class Bar(models.Model):
    bar1 = models.CharField(max_length=1000, default="")
    bar2 = models.BooleanField(default=False)
    foo = models.ForeignKey(Foo, on_delete=models.CASCADE)

    def __init__(self, *args, **kwargs):
        super(Bar, self).__init__(*args, **kwargs)
        print("check")
        self._original_bar1 = self.bar1
        self._original_bar2 = self.bar2


class Baz(models.Model):
    bar = models.ForeignKey(Bar, on_delete=models.CASCADE)

Creating a Foo object and a corresponding Bar object (via the admin interface) works fine.
However, when I delete the Foo object, this results in an endless loop of the __init__() method.

If I rewrite the models slightly as

from django.db import models


class Foo(models.Model):
    my_foo = models.CharField(max_length=1000)


class AbstractBar2(models.Model):
    bar2 = models.BooleanField(default=False)

    def __init__(self, *args, **kwargs):
        super(AbstractBar2, self).__init__(*args, **kwargs)
        print("check")
        self._original_bar2 = self.bar2

    class Meta:
        abstract = True


class AbstractBar1(models.Model):
    bar1 = models.CharField(max_length=1000, default="")

    def __init__(self, *args, **kwargs):
        super(AbstractBar1, self).__init__(*args, **kwargs)
        print("check")
        self._original_bar1 = self.bar1

    class Meta:
        abstract = True


class Bar(AbstractBar1, AbstractBar2):
    foo = models.ForeignKey(Foo, on_delete=models.CASCADE)


class Baz(models.Model):
    bar = models.ForeignKey(Bar, on_delete=models.CASCADE)

it errors out on

Fatal Python error: _Py_CheckRecursiveCall: Cannot recover from stack overflow.
Python runtime state: initialized

Current thread 0x000035d0 (most recent call first):
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\fields\__init__.py", line 807 in get_prep_value
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\fields\__init__.py", line 1770 in get_prep_value
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\lookups.py", line 76 in get_prep_lookup
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\lookups.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\sql\query.py", line 1165 in build_lookup
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\sql\query.py", line 1319 in build_filter
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\sql\query.py", line 1377 in _add_q
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\sql\query.py", line 1358 in add_q
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 969 in _filter_or_exclude_inplace
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 962 in _filter_or_exclude
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 942 in filter
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\manager.py", line 85 in manager_method
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 623 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 14 in __init__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 14 in __init__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 14 in __init__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 14 in __init__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 14 in __init__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 24 in __init__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 513 in from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 71 in __iter__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 1308 in _fetch_all
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 269 in __len__
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query.py", line 425 in get
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\base.py", line 635 in refresh_from_db
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\db\models\query_utils.py", line 149 in __get__
  File "C:\Users\name\PycharmProjects\djangoTest\foobar\models.py", line 26 in __init__
  ...

Thread 0x00000a60 (most recent call first):
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\selectors.py", line 315 in _select
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\selectors.py", line 324 in select
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\socketserver.py", line 232 in serve_forever
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\servers\basehttp.py", line 216 in run
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\commands\runserver.py", line 139 in inner_run
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 53 in wrapper
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\threading.py", line 888 in run
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\threading.py", line 950 in _bootstrap_inner
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\threading.py", line 908 in _bootstrap

Thread 0x00000c7c (most recent call first):
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 374 in tick
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 324 in run_loop
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 318 in run
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 603 in start_django
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\utils\autoreload.py", line 618 in run_with_reloader
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\commands\runserver.py", line 103 in run
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\commands\runserver.py", line 96 in handle
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\base.py", line 371 in execute
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\commands\runserver.py", line 61 in execute
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\base.py", line 330 in run_from_argv
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\__init__.py", line 395 in execute
  File "C:\Users\name\PycharmProjects\global39\djangoTest\lib\site-packages\django\core\management\__init__.py", line 401 in execute_from_command_line
  File "C:\Users\name\PycharmProjects\djangoTest\manage.py", line 18 in main
  File "C:\Users\name\PycharmProjects\djangoTest\manage.py", line 22 in <module>

Process finished with exit code -1

Change History (6)

comment:1 by Tim Graham, 3 years ago

You should explain why Django is at fault and not your custom __init__() method, and ideally propose some solution.

comment:2 by exec-life, 3 years ago

Owner: changed from nobody to exec-life
Status: newassigned

in reply to:  1 comment:3 by kr, 3 years ago

Replying to Tim Graham:

You should explain why Django is at fault and not your custom __init__() method, and ideally propose some solution.

The only thing my custom __init__() method does is retrieving model attributes and saving them to local variables. I don't see why this should be illegal to do, especially because it works except when I try to perform the delete operations.
In my opinion, the code is simple enough that a "justification" why the __init__() method is not at fault is not needed.
Obviously, django runs into an endless loop with the model initializations / fetching the model from the db. This clearly seems to be a fault of the django framework. Agreed?

comment:4 by kr, 3 years ago

Description: modified (diff)

comment:5 by Simon Charette, 3 years ago

Your code will break as soon as fields are deferred which is something model deletion does to instantiate model instances while reducing memory and CPU usage during cascade deletion.

Your code breaks the Bar.objects.defer('bar1) pattern because accessing fields triggers loading which is covered by the docs.

This is detailed a bit in #31475 but I suggest you avoid overriding __init__ and favour from_db_value and rely on fields instead of if you cannot do self.__dict__.get('bar1') to bypass deferred attributes descriptors.

Last edited 3 years ago by Simon Charette (previous) (diff)

comment:6 by Tim Graham, 3 years ago

Resolution: invalid
Status: assignedclosed
Type: UncategorizedBug
Note: See TracTickets for help on using tickets.
Back to Top