You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When calling delete() on one of the child models, the related parent model is also deleted, since Django stores a pointer from the child model to the parent model in the database. This causes the post_delete signal to be run for both the child model and the parent model. Each time the post_delete signal is called, the orders are shifted to accommodate.
importpytest@pytest.mark.django_dbdeftest_parent_child_order():
foobar=Foobar.objects.create(name="foobar")
child1=Child.objects.create(name="child1", foobar=foobar, age=1)
child2=Child.objects.create(name="child2", foobar=foobar, age=2)
child3=Child.objects.create(name="child3", foobar=foobar, age=3)
child4=Child.objects.create(name="child4", foobar=foobar, age=4)
# This is the order of the children at the startassertchild1.order==0assertchild2.order==1assertchild3.order==2assertchild4.order==3# Delete the first child# This causes the parent to be deleted as wellchild1.delete()
# Refresh the dbchild2.refresh_from_db()
child3.refresh_from_db()
child4.refresh_from_db()
# The order of the children should be updated# The expected orderassertchild2.order==0assertchild3.order==1assertchild4.order==2
This test produces this outcome:
> assert child3.order == 1
E assert 0 == 1
E + where 0 = <Child: Child object (3)>.order
AssertionError
You would expect child3.order to be 1, but since the post_delete is called twice, it gets shifted twice. In reality, child2.order is 0, child3.order is 0, and child4.order is 1
Expected result
I would expect that the parent models do not have the post_delete signal called on them. As that is unexpected behavior to have the orders shifted twice.
Workaround
I found that I could disconnect the signal from the parent model, in my apps.py file:
fromdjango.appsimportAppConfigfromdjango.db.models.signalsimportpost_deleteclassMyAppConfig(AppConfig):
...
defready(self):
frommyapp.modelsimportParentres=post_delete.disconnect(sender=Parent, dispatch_uid=Parent.__name__)
ifres==False:
raiseAssertionError("Failed to disconnect post_delete signal from Parent model. Make sure that `ordered_model` is loaded before `myapp` in the settings.py file.")
This only works if my app is set after the ordered_model app in the INSTALLED_APPS list in settings.py
Issue
If I have a parent and child model defined, ordered with respect to some other model:
When calling
delete()
on one of the child models, the related parent model is also deleted, since Django stores a pointer from the child model to the parent model in the database. This causes thepost_delete
signal to be run for both the child model and the parent model. Each time thepost_delete
signal is called, the orders are shifted to accommodate.This test produces this outcome:
You would expect
child3.order
to be1
, but since thepost_delete
is called twice, it gets shifted twice. In reality, child2.order is 0, child3.order is 0, and child4.order is 1Expected result
I would expect that the parent models do not have the
post_delete
signal called on them. As that is unexpected behavior to have the orders shifted twice.Workaround
I found that I could disconnect the signal from the parent model, in my
apps.py
file:This only works if my app is set after the
ordered_model
app in theINSTALLED_APPS
list insettings.py
The text was updated successfully, but these errors were encountered: