Eu implemento um método de limpeza personalizado para validarformset. Eu sei que há erro como eu posso imprimi-los para o console, mas estes non_form_errors () nunca são processados no meu modelo. Como posso renderizá-los?
template.html:
<form action="{% url "databank:register" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="container">
<div class="row" style="margin-top: 30px">
<div class="col-md-10 col-md-offset-1">
{{ dataset_form.media }}
{% crispy dataset_form %}
<div class="authorFormset">
{% for form in formset %}
{% crispy form helper %}
{% endfor %}
</div>
{% crispy terms_form %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<input type="submit" class="btn btn-lg btn-success" value="Submit">
</div>
</div>
</div>
{{ formset.management_form }}
forms.py:
class BaseAuthorFormset(BaseFormSet):
def clean(self):
if any(self.errors):
return
roles = []
for form in self.forms:
contributor_role = form.cleaned_data["role"]
for x in contributor_role:
if (x == "Depositor") and (x in roles):
raise forms.ValidationError("Only one Contributor may be marked Depositor.")
roles.append(x)
if "Depositor" not in roles:
raise forms.ValidationError("You must designate one Contributor as Depositor.")
def __init__(self, *args, **kwargs):
super(BaseAuthorFormset, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
class AuthorForm(forms.Form):
first_name = forms.CharField(
max_length=96,
required=True,
)
middle_initial = forms.CharField(
max_length=96,
required=False,
)
last_name = forms.CharField(
max_length = 96,
required = True,
)
email = forms.EmailField(
required = True
)
role = forms.ModelMultipleChoiceField(
queryset=AuthorRole.objects.filter(is_visible=True),
widget=forms.CheckboxSelectMultiple,
required = False,
)
affiliation = forms.CharField(
max_length=512,
required=True,
)
AuthorFormset = formset_factory(AuthorForm, formset=BaseAuthorFormset, extra=1)
class AuthorFormHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(AuthorFormHelper, self).__init__(*args, **kwargs)
self.helper = FormHelper()
FormHelper.form_tag = False
FormHelper.disable_csrf = True
FormHelper.formset_error_title = "Contributor Errors"
self.layout = Layout(
Div(
Div( HTML("<h4>Contributor</h4>"),
Div(
Div("first_name", css_class="col-xs-4"),
Div("middle_initial", css_class="col-xs-4"),
Div("last_name", css_class="col-xs-4"),
css_class="row"
),
Div(
Div("affiliation", css_class="col-xs-12 col-sm-6"),
Div("email", css_class="col-xs-12 col-sm-6"),
Div(
Field(
InlineCheckboxes("role"),
),
css_class="col-xs-12 col-sm-6"),
css_class="row"
),
),
css_class = "add_author",
id="authorFormDiv"
),
)
Respostas:
1 para resposta № 1Obrigado a @Brandon por me ajudar a descobrir isso!
Na visão, formset.__dict__
pode ser usado para imprimir o próprio objeto para descobrir onde os erros estão sendo armazenados. Isso mostrou que os erros do formset são armazenados usando o _non_form_errors
chave. Então passei esses erros para o modelo!
1 para resposta № 2
Depois de muitas investigações, encontrei a solução para renderizar non_form_errors
de crocante BaseInlineFormSet
no modelo por nativo django-crispy
"s filtro. Talvez seja útil para alguém (funciona pelo menos para django-crispy-forms
== 1.5.2, Django
== 1.6):
{% load crispy_forms_filters %}
{% if formset.non_form_errors %}
{{ formset|as_crispy_errors }}
{% endif %}