Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non Form Errors for a Formset not Rendering with Django Crispy Forms

I implement a custom clean method to validate my formset. I know there are error as I can print them to the console but these non_form_errors() are never rendered in my template. How can I render them?

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"
            ),
        )
like image 764
steph Avatar asked Apr 01 '15 20:04

steph


People also ask

When to use Django-crispy-forms and when not to?

By default django-crispy-forms renders the layout specified if it exists strictly. Sometimes you might be interested in rendering all form’s hidden fields no matter if they are mentioned or not. Useful when trying to render forms with layouts as part of a formset with hidden primary key fields.

How to create a formset in Django using default rendering?

Let’s start creating a formset using the previous ExampleFormform: fromdjango.forms.modelsimportformset_factoryExampleFormSet=formset_factory(ExampleForm,extra=3)formset=ExampleFormSet() This is how you would render the formset using default rendering, no layouts or form helpers: {%crispyformset%}

What is an example of form errors?

Example: “Form Errors”. If you are rendering a formset using {% crispy %} tag and it has non_form_errors to display, they are rendered in a div. You can set the title of the div with this attribute. Example: “Formset Errors”.

What is the difference between model formsets and inline formsets in Django?

Finally, model formsets and inline formsets are rendered exactly the same as formsets, the only difference is how you build them in your Django code. Extra context¶ Rendering any kind of formset with crispy injects some extra context in the layout rendering so that you can do things like:


1 Answers

After a lot of investigations, I found the solution for render non_form_errors of crispy BaseInlineFormSet in template by native django-crispy's filter. Maybe it would be helpful for someone (it works at least for django-crispy-forms==1.5.2, Django==1.6):

{% load crispy_forms_filters %}
{% if formset.non_form_errors %}
    {{ formset|as_crispy_errors }}
{% endif %}
like image 119
Vladimir Chub Avatar answered Sep 23 '22 02:09

Vladimir Chub