Django m2m 和保存对象
Posted
技术标签:
【中文标题】Django m2m 和保存对象【英文标题】:Django m2m and saving objects 【发布时间】:2009-12-03 07:23:10 【问题描述】:我有几个具有多对多关系的简单对象。 Django 使用 obj1_obj2 表加入了它们,它在 mysql 中看起来像这样;
id | person_id | nationality_id
-----------------------------------
1 | 1 | 1
2 | 1 | 2
现在,当我保存 obj1(它以多选形式显示 obj2)时,即使我没有更改它们,obj1_obj2 表中的 id 也会增加。例如,我在其表单上更改了 obj1 的基本字符字段并将其保存,连接表中的数据似乎已被删除并重新保存,从而为条目提供了新的 id。
事实上,我不需要更改任何内容,只需保存表单,同样的事情就会发生。
我在视图中所做的只是 form.save(),没什么特别的。这是正常的工作方式吗?
编辑:添加模型、视图、表单
class Person(models.Model):
name = models.CharField()
birthdate = models.CharField()
nationality = models.ManyToMany(Nationality)
class Employee(Person):
employeeNum = models.CharField()
class FamilyMember(Person):
employee = models.ForeignKey(Employee)
relationship = models.CharField()
class Nationality(models.Model):
abbrev = models.CharField()
country = models.CharField()
class FamilyMemberDetailsForm(forms.ModelForm):
class Meta:
model = FamilyMemeber
exclude = ['employee']
def editFamilyMember(request, familyMember_id):
familyMember = get_object_404(FamilMember, familyMember_id)
if request.method == 'POST':
form = FamilyMemberDetailsForm(request.POST, instance=familyMember)
if form.is_valid():
form.save()
else:
form = FamilyMemberDetailsForm(instance=familyMember)
return render_to_response(editForm.html, 'form':form,
context_instance(RequestContext(request))
这是模型的精简版,但同样的情况也适用于保存员工或家庭成员。我展示了 FamilyMember,因为它就像这样简单,我创建了 modelForm,然后进行更改,然后保存它。对于员工,我在国籍表格的 init 中进行了更多操作,主要是为了演示,起初我认为是这种操作导致了它,但正如我所说的,同样的事情发生了与 FamilyMember 一起,除了保存之外我什么都不做。
国籍在表单上显示为带有列表的多选框,用户可以从列表中选择一个或多个。如果我只是呈现填充的表单然后保存它而不更改任何内容,那么多对多表条目的 id 会更改。
我也更改了示例表标题。
谢谢, 安德鲁
【问题讨论】:
obj1_obj2 表是否真的将两个 id 都设置为 1 还是只是一个错字? 请显示您的视图代码。 我支持代码请求...我认为我的 m2m 关系不会受到这种影响 id 都是一个是错字。 我已经为视图、模型(缩减)和模型表单添加了代码。 【参考方案1】:是的,在为具有 ManyToManyField 的对象保存表单时,删除 appname_obj1_obj2 中的任何现有行是预期的行为。
您可以在 django/db/models/fields/related.py 中的 ReverseManyRelatedObjectsDescriptor 和 ManyRelatedObjectsDescriptor 中的 add(**values) 之前看到 clear()。
打开一个 shell 并自己查看查询。像这样的东西应该在原始 sql 中的 INSERT 之前向您显示 DELETE。
from django.db import connection
fm = FamilyMember.objects.get(pk=1)
form = FamilyMemberDetailsForm(instance=fm)
data = form.initial
data['name'] = "z%s" % data['name']
form = FamilyMemberDetailsForm(data, instance=fm)
connection.queries = [] # clearing to limit the queries you have to look at
form.save()
for q in connection.queries:
print("%s\n" % q['sql'])
【讨论】:
那么有办法避免这种情况吗?我是否应该在保存表单之前进行测试以查看多对妈妈是否已更改,是否有标准方法可以完成此操作,或者只是没有将其视为问题? 可以自己管理联结表中的实体,但在开始这条路之前问问自己是否值得付出努力。这个表很小,毫无疑问是完全索引的,所以对它的操作应该非常快。如果调用 save(commit=False),save_m2m() 将在表单对象上可用(而不是在 save() 中调用)。然后,您可以尝试使用 person.nationality.add() 和 .remove() 进行自己的 m2m 关系管理,而不是调用 form.save_m2m()。同样,在放弃 save_m2m() 之前,请确保这是值得花时间做的事情。 你关于花费的时间与价值的观点被采纳了。我想我会不管它。感谢您的帮助。以上是关于Django m2m 和保存对象的主要内容,如果未能解决你的问题,请参考以下文章
Django Rest Framework更新嵌套的m2m对象。有谁知道更好的方法?