#18676: Django should do m2m deletes in a single query when possible -------------------------------------+------------------------------------- Reporter: jdunck | Owner: nobody Type: | Status: closed Cleanup/optimization | Version: 1.4 Component: Database layer | Resolution: fixed (models, ORM) | Triage Stage: Ready for Severity: Normal | checkin Keywords: | Needs documentation: 0 Has patch: 1 | Patch needs improvement: 0 Needs tests: 0 | UI/UX: 0 Easy pickings: 0 | -------------------------------------+-------------------------------------
Comment (by pressureman): After doing a git bisect, I discovered that the commit 1cd6e04cd4f768bcd4385b75de433d497d938f82 caused a regression in an existing project of mine, that uses a custom object manager. The setup is as follows (simplified - other models also have `ForeignKey` back to `OrgUnit` model): {{{ #!python class OrgUnit(models.Model): name = models.CharField(max_length=64, unique=True) groups = models.ManyToManyField(Group, blank=True) users = models.ManyToManyField(User, blank=True) class LoginManager(models.Manager): def restricted(self, user): q_group = Q(orgunit__groups__user=user) q_user = Q(orgunit__users=user) return self.filter(q_group | q_user).distinct() class Login(models.Model): description = models.CharField(max_length=32) orgunit = models.ForeignKey(OrgUnit) private_data = models.TextField(editable=False) objects = LoginManager() }}} My view POSTs a list of ids to a view that deletes Login objects, and it throws a DB exception "subquery has too many columns". I can see quite clearly from the generated SQL that the sub-select is including unnecessary fields for the "DELETE FROM foo WHERE id in (SELECT id, description FROM login ... )". I don't understand why the sub-select is including the `Login.description` field :-? The following is the code in the view that triggers the exception: {{{ #!python id_list = map(int, request.POST.getlist('_id_list')) Login.objects.restricted(request.user).filter(id__in=id_list).delete() }}} What I've found is that if I modify the `LoginManager.restricted()` to either not `filter()` (undesirable) or not `.distinct()` then the bug does not occur. This code is a few years old now, and I don't remember why exactly I put a `.distinct()` in there. It doesn't seem to cause any undesirable side effects if I remove it, but I'd like to try to understand why this Django commit has caused this regression in the first place, as it may affect other people. -- Ticket URL: <https://code.djangoproject.com/ticket/18676#comment:8> 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 post to this group, send email to django-updates@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.