How do I remove multiple objects in a ManyToMany relationship based on a filter?

女生的网名这么多〃 提交于 2019-11-30 03:28:41
Yuji 'Tomita' Tomita

I think you got it right on the money, except you don't need to convert to a list.

source.items.remove(*source.items.filter(*args))

The remove/add method looks like the following

remove(self, *objs)
add(self, *objs)

and the docs use add multiple examples in the form of [p1, p2, p3] so I'd wager the same goes for remove, seeing as the arguments are the same.

>>> a2.publications.add(p1, p2, p3)

Digging in a little more, the remove function iterates over *objs one by one, checking if it's of the valid model, otherwise using the values as PK's, then deletes the items with a pk__in, so I'm gonna say yes, the best way is to query your m2m table first for objects to delete then pass in those objects into the m2m manager.

    # django.db.models.related.py
    def _remove_items(self, source_field_name, target_field_name, *objs):
        # source_col_name: the PK colname in join_table for the source object
        # target_col_name: the PK colname in join_table for the target object
        # *objs - objects to remove

        # If there aren't any objects, there is nothing to do.
        if objs:
            # Check that all the objects are of the right type
            old_ids = set()
            for obj in objs:
                if isinstance(obj, self.model):
                    old_ids.add(obj.pk)
                else:
                    old_ids.add(obj)
            if self.reverse or source_field_name == self.source_field_name:
                # Don't send the signal when we are deleting the
                # duplicate data row for symmetrical reverse entries.
                signals.m2m_changed.send(sender=rel.through, action="pre_remove",
                    instance=self.instance, reverse=self.reverse,
                    model=self.model, pk_set=old_ids)
            # Remove the specified objects from the join table
            db = router.db_for_write(self.through.__class__, instance=self.instance)
            self.through._default_manager.using(db).filter(**{
                source_field_name: self._pk_val,
                '%s__in' % target_field_name: old_ids
            }).delete()
            if self.reverse or source_field_name == self.source_field_name:
                # Don't send the signal when we are deleting the
                # duplicate data row for symmetrical reverse entries.
                signals.m2m_changed.send(sender=rel.through, action="post_remove",
                    instance=self.instance, reverse=self.reverse,
                    model=self.model, pk_set=old_ids)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!