Django UpdateView - 从多对多字段获取初始数据并在保存表单时添加它们
Django UpdateView - get initial data from many-to-many field and add them when saving form
我正在使用基于 Django class 的通用视图。在我的 models.py 中,我有一个名为 MyModel 的模型,其中包含名为 m2m 的多对多字段。我有多个用户组,他们可以编辑 m2m 字段。每组用户只能看到他们的部分并将其添加到该字段 - 使用 get_form 设置他们在 m2m 字段中可以看到的内容。我遇到的问题是,当一个用户输入他的记录时,它将删除 m2m 字段中的初始记录。我需要以某种方式从 m2m 字段中获取初始值并保存它们,然后在提交表单时将它们添加到新值中。这是我的 views.py:
class MyModelUpdate(UpdateView):
model = MyModel
fields = ['m2m']
def get_initial(self):
return initials
def get_form(self, form_class=None):
form = super(MyModelUpdate, self).get_form(form_class)
form.fields["m2m"].queryset = DiffModel.objects.filter(user = self.request.user)
return form
def form_valid(self, form):
form.instance.m2m.add( ??? add the initial values)
return super(MyModelUpdate, self).form_valid(form)
def get_success_url(self):
...
经过几天的搜索和编码,我找到了解决方案。
views.py:
from itertools import chain
from .forms import MyForm,
def MyModelUpdate(request, pk):
template_name = 'mytemplate.html'
instance = MyModel.objects.get(pk = pk)
instance_m2m = instance.m2m.exclude(user=request.user)
if request.method == "GET":
form = MyForm(instance=instance, user=request.user)
return render(request, template_name, {'form':form})
else:
form = MyForm(request.POST or None, instance=instance, user=request.user)
if form.is_valid():
post = form.save(commit=False)
post.m2m = chain(form.cleaned_data['m2m'], instance_m2m)
post.save()
return redirect(...)
forms.py:
from django import forms
from .models import MyModel
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['m2m']
def __init__(self, *args, **kwargs):
current_user = kwargs.pop('user')
super(MyForm, self).__init__(*args, **kwargs)
self.fields['m2m'].queryset = self.fields['m2m'].queryset.filter(user=current_user)
我添加这个答案是为了提供对此类问题的简化解释,也是因为 OP 在他的解决方案中从 UpdateView 切换到基于函数的视图,这可能不是某些用户正在寻找的.
如果您将 UpdateView 用于具有 ManyToMany 字段的模型,但您没有将其显示给用户,因为您只想保留此数据,则在保存表单后所有 m2m 值都将被删除.
这显然是因为 Django 希望这个字段包含在表单中,不包含它等同于将它发送为空,因此,告诉 Django 删除所有 ManyToMany 关系。
在那种简单的情况下,您不需要定义 form_valid 然后检索原始值等等,您只需要告诉 Django 不要期待这个字段。
所以,如果你是这样看的:
class ProjectFormView(generic.UpdateView):
model = Project
form_class = ProjectForm
template_name = 'project.html'
在您的表单中,排除 m2m 字段:
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = '__all__'
exclude = ['many_to_many_field']
我正在使用基于 Django class 的通用视图。在我的 models.py 中,我有一个名为 MyModel 的模型,其中包含名为 m2m 的多对多字段。我有多个用户组,他们可以编辑 m2m 字段。每组用户只能看到他们的部分并将其添加到该字段 - 使用 get_form 设置他们在 m2m 字段中可以看到的内容。我遇到的问题是,当一个用户输入他的记录时,它将删除 m2m 字段中的初始记录。我需要以某种方式从 m2m 字段中获取初始值并保存它们,然后在提交表单时将它们添加到新值中。这是我的 views.py:
class MyModelUpdate(UpdateView):
model = MyModel
fields = ['m2m']
def get_initial(self):
return initials
def get_form(self, form_class=None):
form = super(MyModelUpdate, self).get_form(form_class)
form.fields["m2m"].queryset = DiffModel.objects.filter(user = self.request.user)
return form
def form_valid(self, form):
form.instance.m2m.add( ??? add the initial values)
return super(MyModelUpdate, self).form_valid(form)
def get_success_url(self):
...
经过几天的搜索和编码,我找到了解决方案。
views.py:
from itertools import chain
from .forms import MyForm,
def MyModelUpdate(request, pk):
template_name = 'mytemplate.html'
instance = MyModel.objects.get(pk = pk)
instance_m2m = instance.m2m.exclude(user=request.user)
if request.method == "GET":
form = MyForm(instance=instance, user=request.user)
return render(request, template_name, {'form':form})
else:
form = MyForm(request.POST or None, instance=instance, user=request.user)
if form.is_valid():
post = form.save(commit=False)
post.m2m = chain(form.cleaned_data['m2m'], instance_m2m)
post.save()
return redirect(...)
forms.py:
from django import forms
from .models import MyModel
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['m2m']
def __init__(self, *args, **kwargs):
current_user = kwargs.pop('user')
super(MyForm, self).__init__(*args, **kwargs)
self.fields['m2m'].queryset = self.fields['m2m'].queryset.filter(user=current_user)
我添加这个答案是为了提供对此类问题的简化解释,也是因为 OP 在他的解决方案中从 UpdateView 切换到基于函数的视图,这可能不是某些用户正在寻找的.
如果您将 UpdateView 用于具有 ManyToMany 字段的模型,但您没有将其显示给用户,因为您只想保留此数据,则在保存表单后所有 m2m 值都将被删除.
这显然是因为 Django 希望这个字段包含在表单中,不包含它等同于将它发送为空,因此,告诉 Django 删除所有 ManyToMany 关系。
在那种简单的情况下,您不需要定义 form_valid 然后检索原始值等等,您只需要告诉 Django 不要期待这个字段。
所以,如果你是这样看的:
class ProjectFormView(generic.UpdateView):
model = Project
form_class = ProjectForm
template_name = 'project.html'
在您的表单中,排除 m2m 字段:
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = '__all__'
exclude = ['many_to_many_field']