[Django] #31600: Calling .delete() on a queryset doesn't delete related objects

23 views
Skip to first unread message

Django

unread,
May 17, 2020, 11:21:36 AM5/17/20
to django-...@googlegroups.com
#31600: Calling .delete() on a queryset doesn't delete related objects
-----------------------------------------+------------------------
Reporter: אורי | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 3.0
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 |
-----------------------------------------+------------------------
I created a new test and it had users and I deleted them:

`User.objects.all().exclude(pk=self.user_1.pk).delete()`

The User model has related models with `on_delete=models.CASCADE` which
should be deleted as well.

But in my test, I got this exception:

{{{
======================================================================
ERROR: test_like_list_views_titles_with_empty_lists
(speedy.match.likes.tests.test_views.LikeListViewsEnglishTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "env\lib\site-packages\django\db\backends\utils.py", line 84, in
_execute
return self.cursor.execute(sql)
psycopg2.errors.ForeignKeyViolation: insert or update on table
"net_accounts_siteprofile" violates foreign key constraint
"net_accounts_sitepro_user_id_c96775a1_fk_accounts_"
DETAIL: Key (user_id)=(403828609159078) is not present in table
"accounts_user".


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "env\lib\site-packages\django\test\testcases.py", line 274, in
__call__
self._post_teardown()
File "env\lib\site-packages\django\test\testcases.py", line 1009, in
_post_teardown
self._fixture_teardown()
File "env\lib\site-packages\django\test\testcases.py", line 1177, in
_fixture_teardown
connections[db_name].check_constraints()
File "env\lib\site-packages\django\db\backends\postgresql\base.py", line
276, in check_constraints
self.cursor().execute('SET CONSTRAINTS ALL IMMEDIATE')
File "env\lib\site-packages\django\db\backends\utils.py", line 68, in
execute
return self._execute_with_wrappers(sql, params, many=False,
executor=self._execute)
File "env\lib\site-packages\django\db\backends\utils.py", line 77, in
_execute_with_wrappers
return executor(sql, params, many, context)
File "env\lib\site-packages\django\db\backends\utils.py", line 86, in
_execute
return self.cursor.execute(sql, params)
File "env\lib\site-packages\django\db\utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "env\lib\site-packages\django\db\backends\utils.py", line 84, in
_execute
return self.cursor.execute(sql)
django.db.utils.IntegrityError: insert or update on table
"net_accounts_siteprofile" violates foreign key constraint
"net_accounts_sitepro_user_id_c96775a1_fk_accounts_"
DETAIL: Key (user_id)=(403828609159078) is not present in table
"accounts_user".


----------------------------------------------------------------------
Ran 1 test in 7.425s
}}}

I think this exception is because the users I deleted.
`net_accounts_siteprofile` refers to the `SiteProfile` model which should
be deleted when deleting a user by on_delete=models.CASCADE .

I checked and eventually I found out that changing:

`User.objects.all().exclude(pk=self.user_1.pk).delete()`

To:

{{{
for user in User.objects.all().exclude(pk=self.user_1.pk):
user.delete()
}}}

Fixes the problem. But I expected related objects to be deleted by the
first query too. Does it mean I can't safely delete users in bulk by
`.delete()`? And if it does, how do I disable it so trying to delete users
in bulk will raise an exception?

I would like either to fix the queryset bulk `.delete()` method to delete
related objects too, or to completely disable bulk deletions in Django. Is
there a simple way to define a manager which doesn't have this bulk delete
feature?

--
Ticket URL: <https://code.djangoproject.com/ticket/31600>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
May 17, 2020, 11:22:17 AM5/17/20
to django-...@googlegroups.com
#31600: Calling .delete() on a queryset doesn't delete related objects
-------------------------------+--------------------------------------

Reporter: אורי | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Description changed by אורי:

Old description:

New description:

`User.objects.all().exclude(pk=self.user_1.pk).delete()`

`User.objects.all().exclude(pk=self.user_1.pk).delete()`

To:

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31600#comment:1>

Django

unread,
May 17, 2020, 11:43:40 PM5/17/20
to django-...@googlegroups.com
#31600: Calling .delete() on a queryset doesn't delete related objects
-------------------------------+--------------------------------------

Reporter: אורי | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

Comment (by אורי):

Hi,

Since it's open source you can see the code. I created a branch with the
failing test. You can see the test on https://github.com/speedy-net
/speedy-
net/blob/uri_temp_temp_branch_2020-05-18_a/speedy/match/likes/tests/test_views.py#L366-L411
and the commit who causes it to fail on https://github.com/speedy-net
/speedy-net/commit/d91bd29d465149ede7ff906e0982b21d6c4a712f . You can
check the failing tests on Travis CI https://travis-ci.org/github/speedy-
net/speedy-net/builds/688212117 and the passing tests without this commit
on https://travis-ci.org/github/speedy-net/speedy-net/builds/688210140 .

--
Ticket URL: <https://code.djangoproject.com/ticket/31600#comment:2>

Django

unread,
May 18, 2020, 3:18:22 AM5/18/20
to django-...@googlegroups.com
#31600: Calling .delete() on a queryset doesn't delete related objects.
-------------------------------------+-------------------------------------
Reporter: אורי | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: master
(models, ORM) |
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 felixxm):

* status: new => closed
* resolution: => invalid
* version: 3.0 => master
* component: Uncategorized => Database layer (models, ORM)


Comment:

Thanks for this ticket, however I cannot reproduce this issue, everything
works for me with two simple models (I used `OneToOneField` like in your
models):
{{{
class A(models.Model):
pass

class B(models.Model):
a = models.OneToOneField(A, primary_key=True,
on_delete=models.CASCADE, related_name='other_name')
}}}

it's hard to tell why your tests failed because models are quite
complicated. Please use one of support channel.

Closing per TicketClosingReasons/UseSupportChannels.

--
Ticket URL: <https://code.djangoproject.com/ticket/31600#comment:4>

Django

unread,
May 18, 2020, 11:31:34 PM5/18/20
to django-...@googlegroups.com
#31600: Calling .delete() on a queryset doesn't delete related objects.
-------------------------------------+-------------------------------------
Reporter: אורי | Owner: nobody

Type: Bug | Status: closed
Component: Database layer | Version: master
(models, ORM) |
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
-------------------------------------+-------------------------------------

Comment (by אורי):

Eventually I decided to disable the .delete() method in all querysets in
model managers in my project and I don't allow to delete objects from
querysets any more. Any delete command should be executed on the object
itself. [ [https://github.com/speedy-net/speedy-
net/commit/e92c5679e2d98090e88f0595035ab96b6c1a5b24 commit] ]

It would be nice to have a settings in Django that does this - disable the
.delete() method in all querysets.

--
Ticket URL: <https://code.djangoproject.com/ticket/31600#comment:5>

Reply all
Reply to author
Forward
0 new messages