2015-11-03 3 views
0

Я немного оглянулся, но не могу понять, как это сделать. У меня в основном есть форма документа и элемент inlineformset в представлении, и мне нужно выполнить некоторую проверку, зависящую от значений полей в каждой форме. Например, если поле copyright_needed Item равно YES, необходимо указать поле учетной записи документа.Django: как проверить inlineformset в отношении другой связанной формы

Как передать ссылку на форму Документа, так что в чистом методе ItemForm я могу посмотреть очищенные_данные формы документа? Я пытаюсь использовать карри, как я видел, рекомендовал в других ответах 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 - EDIT - добавил 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,...) 

ответ

1

Я даже не уверен, что делает вид - это выглядит, как вы запутались в роли встроенного шаблона и карри. Во-первых, вы просматриваете метод init ItemForm с doc_form, но вы не написали 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 уже назвали - это похоже на написание свой собственный чистый() на обычном ModelForm.

EDIT:

ОК, так что игнорировать 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 
+0

Я добавил инициализации для ItemForm, который я случайно оставил вне. Я использую inlineformset для отображения DocumentForm и ItemForm в одном представлении (create_item), где пользователь создает новый Item и новый Document, так что новый документ является внешним ключом для нового элемента. Я всегда просто создаю/редактирую один элемент за раз. Может быть, канавка inlineformset и просто показать DocumentForm и ItemForm и явно добавить отношение FK при сохранении? Кажется, я не получаю много от inlineformset. Только быстрый способ сделать это отношение при delcaring ItemFormSet – Carrie

+0

Мой вопрос по-прежнему остается: когда я нахожусь в чистом методе ItemForm, как я могу получить ссылку на DocumentForm? Я вижу, что вы говорите о создании customformset с помощью чистого метода, но я не вижу, как этот formet (который будет представлять мой ItemFormset) может сравнивать поля формы с полями в DocumentForm, которые были отправлены одновременно ? Неужели все еще неясно, что мне нужно? – Carrie

+0

В моем чистом методе MyCustomFormset есть ли self.instance, доступ к которому я могу получить, чтобы получить экземпляр (Document), объявленный при создании item_formset при обработке POST? – Carrie

Смежные вопросы