Django 如何基于筛选器删除多个关系中的多个对象?

Django 如何基于筛选器删除多个关系中的多个对象?,django,manytomanyfield,Django,Manytomanyfield,鉴于这两种模式: class Item(models.Model): timestamp = models.DateTimeField() class Source(models.Model): items = models.ManyToManyField(Item, related_name="sources") 我可以使用以下方法在给定时间之前找到源的所有项: source.items.filter(timestamp__lte=some_datetime) 如何有效地

鉴于这两种模式:

class Item(models.Model):
    timestamp = models.DateTimeField()

class Source(models.Model):
    items = models.ManyToManyField(Item, related_name="sources")
我可以使用以下方法在给定时间之前找到源的所有项:

source.items.filter(timestamp__lte=some_datetime)
如何有效地删除与该查询匹配的所有项?我想我可以试试这样的东西:

items_to_remove = list(source.items.filter(timestamp__lte=some_datetime))
source.items.remove(*items_to_remove)
但这似乎很糟糕


请注意,我不想删除这些项目,因为它们可能也属于其他来源。我只想删除他们与特定来源的关系。

我认为你在钱上做得很对,只是你不需要转换为列表

source.items.remove(*source.items.filter(*args))
remove
/
add
方法如下所示

remove(self, *objs)
add(self, *objs)
用法以
[p1,p2,p3]
的形式添加了多个示例,因此我打赌
删除
也是如此,因为参数是相同的

>>> a2.publications.add(p1, p2, p3)
再深入一点,remove函数一个接一个地迭代
*objs
,检查它是否属于有效模型,否则使用值作为PK,然后删除
中带有
PK\u的项,所以我要说是,最好的方法是先查询m2m表中要删除的对象,然后将这些对象传入m2m管理器

    # 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)
根据当前的情况,有一个
属性,允许您访问管理多对多关系的表,如so
Model.m2mfield.through.objects.all()

就你的例子而言:

source.items.through.objects \
    .filter(item__timestamp__lte=some_datetime) \
    .delete()

谢谢我试试看,效果如何。现在我只使用一条原始SQL语句(在PostgreSQL中使用“DELETE…using”,我知道这是非标准的)。是的,大多数人都喜欢使用ORM:)在m2m字段上使用
remove
难道不删除它们吗?OP说他不想删除,只是想删除关系。你能澄清一下吗?@sgauri这是一篇老文章,但如果你看一下那里的django代码,它会通过
模型删除
,即m2m关系。同样,add()不添加相关模型,只添加关系,remove()只删除关系,而不删除相关模型。我还认为这就是为什么django开发人员明确地称这个add/remove而不是create/delete。@Yuji'Tomita'Tomita是的,你是对的。我在
.clear()
.remove()
之间有疑问,后来我了解到前者用于删除所有相关对象的关系,而后者用于特定对象。谢谢你的回复。