如何根据过滤器删除ManyToMany关系中的多个对象? [英] How do I remove multiple objects in a ManyToMany relationship based on a filter?
问题描述
给定这两个模型:
class Item(models.Model):
timestamp = models.DateTimeField()
class Source(models.Model):
items = models.ManyToManyField(Item, related_name="sources")
我可以在给定时间之前使用以下内容找到所有的源项目:
I can find all of a Source's Items before a given time using this:
source.items.filter(timestamp__lte=some_datetime)
如何有效地删除所有的符合该查询的项目?我想我可以尝试这样的事情:
How do I efficiently remove all of the items that match that query? I suppose I could try something like this:
items_to_remove = list(source.items.filter(timestamp__lte=some_datetime))
source.items.remove(*items_to_remove)
但似乎不好。
请注意,我不想删除这些项目,因为它们也可能属于其他来源。我只想删除他们与具体来源的关系。
Note that I do not want to delete these items, since they may also belong to other Sources. I just want to remove their relationship with the specific source.
推荐答案
我认为你的钱正确,除了你不需要转换为列表。
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)
和文档 http://www.djangoproject.com/documentation/models/many_to_many/
使用以形式添加多个示例[p1,p2, p3]
所以我也会为删除
下注,因为参数是一样的。
and the docs http://www.djangoproject.com/documentation/models/many_to_many/
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)
更多的挖掘,删除功能逐个迭代 * objs
,检查它是否是有效的模型,否则使用值作为PK,然后删除具有 pk__in
,所以我会说是的,最好的方法是首先查询你的m2m表,然后将这些对象传递给m2m管理器。
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)
这篇关于如何根据过滤器删除ManyToMany关系中的多个对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!