【发布时间】:2014-01-21 04:18:39
【问题描述】:
我有一个 Book 模型,它有一个多对多字段 Author。如果我合并两本书,我想确保合并的书只有唯一的作者,没有双打。我认为实现这一点的最好方法是重写 save() 方法,到目前为止我已经来到了这个模型:
class Book(models.Model):
authors = models.ManyToManyField()
def save(self):
authors_new = []
authors = self.authors.all()
for author in authors:
if author not in authors_new:
authors_new.append(author)
self.authors = authors_new #This won't work
super(Book, self).save()
倒数第二行显然不起作用,但我似乎无法正确使用语法。不过,我认为我想要实现的目标非常明显。有人知道正确的语法是什么吗?
编辑 1:
解释合并:我必须说我没有完全理解代码(由其他人编写 - 合并发生在几个函数上),所以在这里展示它对我没有帮助。它的作用是:假设数据库中有两本书显然是相同的。第一本书有
title= “Harry Potter and the Philosopher’s Stone”
author=“JK Rowling”
year=1999
另一本书有
title=“Harry Potter (book 1)”
author=“JK Rowling”
pages=320
合并时,您需要选择哪本书是主书。如果我选择第一个作为主要的,那么合并最终应该是
title=“Harry Potter and the Philosopher’s Stone”
author=“JK Rowling”
year=1999
pages=320
问题是合并以 author="JK Rowling" 两次结束我认为我可以在保存功能中取出重复项。
编辑 2:
合并发生在这个函数中,我没有写:
def merge_model_objects(primary_object, *alias_objects):
# Use this function to merge model objects and migrate all of
# the related fields from the alias objects to the primary object.
for alias_object in alias_objects:
meta = alias_object._meta
for related_object in meta.get_all_related_objects():
alias_varname = related_object.get_accessor_name()
obj_varname = related_object.field.name
related_objects = getattr(alias_object, alias_varname)
for obj in related_objects.all():
if getattr(obj, 'do_not_merge', False):
continue
setattr(obj, obj_varname, primary_object)
obj.save()
related_objects = meta.get_all_related_many_to_many_objects()
for related_many_object in related_objects:
alias_varname = related_many_object.get_accessor_name()
obj_varname = related_many_object.field.name
if alias_varname is not None:
# standard case
related_many_objects = getattr(
alias_object, alias_varname).all()
else:
# special case, symmetrical relation, no reverse accessor
related_many_objects = getattr(alias_object, obj_varname).all()
for obj in related_many_objects.all():
getattr(obj, obj_varname).remove(alias_object)
getattr(obj, obj_varname).add(primary_object)
alias_object.delete()
primary_object.save()
return primary_object
这是一个相当通用的函数,可以合并两个以上的对象,但是如果我合并 Book 1 (= primary_object) 和 Book 2 (= alias_object) 它将保存为带有 author="JK Rowling" 的书 两次。
【问题讨论】:
-
对不起,我不认为这很明显。 “合并”两本书是什么意思?为什么会有重复项?
-
确实可能存在重复,不同的人将书籍添加到数据库中。如果合并书籍,我想确保每个作者只添加一次。
-
我认为 django ManyToManyField 已经约束了独特的关系。你试过了吗?
-
我已经尝试过正常的合并,但是如果合并前的两本书有相同的作者,那么作者只是在新合并的书中添加了两次。我尝试了类似
models.ManyToManyField(unique=True)的方法,但我收到消息 ManyToManyFields cannot be unique -
您应该解释一下“正常合并”实际上是什么。 显示代码,了解如何合并图书。通常,正如其他人所说,如果项目已经存在,Django 不会将项目添加到 M2M。