我已经看了很多,但不能弄清楚如何使这项工作。我在视图中基本上有一个Document表单和一个Item inlineformset,我需要根据每个表单中的字段值执行一些验证。例如,如果项目的copyright_needed字段为YES,则需要Document的帐户字段。
如何传递对Document表单的引用,以便在ItemForm的clean方法中,我可以查看Document表单的cleaning_data?我尝试使用咖喱,正如我在其他SO答案中看到的那样,但是它的工作做得并不正确。
Models.py
class Document(models.Model):
account = models.CharField(max_length=22, blank=True, null=True)
class Item(models.Model):
copyright_needed = models.CharField(max_length=1)
# Document foreign key
document = models.ForeignKey(Document)
它是ItemForm清洁方法,显示了我想要完成的事情,以及我得到的错误。
Forms.py - 编辑 - 将init添加到ItemForm
class ItemForm(forms.ModelForm):
class Meta:
model = Item
fields=[..., 'copyright_needed' ]
def __init__(self, *args, **kwargs):
self.doc_form = kwargs.pop('doc_form')
super(ItemForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(ItemForm, self).clean()
msg_required = "This field is required."
cr = cleaned_data.get("copyright_needed")
# This line generates this error: DocumentForm object has no attribute cleaned_data
acct_num = self.doc_form.cleaned_data.get("account")
if cr and cr == Item.YES:
if not acct_num:
self.doc_form.add_error("account", msg_required)
return cleaned_data
class DocumentForm(forms.ModelForm):
...
account = forms.CharField(widget=forms.TextInput(attrs={'size':'25'}), required=False)
class Meta:
model = Document
fields = [ ..., 'account' ]
views.py
def create_item(request):
# create empty forms
form=DocumentForm()
ItemFormSet = inlineformset_factory(Document, Item,
form=ItemForm,
can_delete=False,
extra=1 )
# This is my attempt to pass the DocumentForm to each ItemForm, but its not working
ItemFormSet.form = staticmethod(curry(ItemForm, doc_form=form))
item_formset=ItemFormSet(instance=Document())
if request.POST:
d = Document()
form=DocumentForm(request.POST, instance=d)
if form.is_valid():
new_document=form.save(commit=False)
item_formset=ItemFormSet(request.POST, instance=new_document)
if item_formset.is_valid():
new_document.save()
new_item=item_formset.save()
return HttpResponseRedirect(...)
item_formset=ItemFormSet(request.POST)
return render(request,...)
答案 0 :(得分:1)
我甚至不确定视图的作用 - 看起来你对inlineformset和curry的作用感到困惑。首先,您使用doc_form来讨论ItemForm的init方法,但是您还没有编写init。
其次,看起来您希望能够编辑“文档”表单中的“项目”。因此,您需要modelformset_factory,并传入一个自定义Formset,您可以在其上编写一个干净的方法,该方法可以访问您需要的所有内容。
from django.forms.models import modelformset_factory
ItemFormSet = modelformset_factory(Item, form=ItemForm, formset=MyCustomFormset)
然后在你的customformset中 -
class MyCustomFormset(BaseInlineFormset):
def clean():
super(MyCustomFormset, self).clean()
for form in self.forms:
#do stuff
注意每个ItemForm上的clean方法已被调用 - 这类似于在普通模型上编写自己的clean()。
编辑:
好的,所以忽略了formset干净,我误解了。只需在视图中创建文档表单,将其与表单集一起传递,然后将它们全部放在相同的表单标记中。<form method="post" action=".">
{%for field in doc_form %}
{{field}}
{%endfor%}
{%for form in formset%}
{{form.as_p}}
{%endfor%}
</form>
然后您可以访问request.POST中的所有字段,您可以随心所欲地执行任何操作
doc_form = DocumentForm(request.POST)
formset = ItemFormSet(request.POST)
if all([doc_form.is_valid(), formset.is_valid()]):
#do some stuff