Make inlineformset in django required

2019-07-07 05:03发布

I am new to django (until now, I used the symfony PHP Framework). My problem is this: I have a model Event and model Date. The Date has a foreign key to Event, so that an Event may (or should) have one or more Dates.

Now I want to have a form to create Events and this form should include a subform for adding one corresponding Date (more dates should be added later, if the Event has more than one date).

I used the inlineformset to realize the Date subform, but if no Date is being entered, no error occurs and the Event is being saved without a Date. All I want is to make this inlineformset required or to say, that there has to be at lease (and only) one inlineformset.

I found these questions, but none of the answers helped me:

Any hints for me?

EDIT: I need this for the frontend, not for the backend. The first link covers it for the admin backend.

EDIT2: Some sourcecode added

MandatoryInlineFormSet.py:

from django.forms.models import BaseInlineFormSet
from django import forms

class MandatoryInlineFormSet(BaseInlineFormSet):
    def clean(self):
        # get forms that actually have valid data
        count = 0
        for form in self.forms:
            try:
                if form.cleaned_data:
                    count += 1
            except AttributeError:
                # annoyingly, if a subform is invalid Django explicity raises
                # an AttributeError for cleaned_data
                pass
        if count < 1:
            raise forms.ValidationError('You must have at least one order')

event.py:

from [...]
def new(request):
    DateFormset = inlineformset_factory(
            Event,
            Date,
            can_delete=False,
            extra=1,
            max_num=1,
            formset=MandatoryInlineFormSet,
            )

    if request.POST:
        form = EventForm(request.POST)
        date_formset = DateFormset(request.POST)
        if form.is_valid():
            event = form.save(commit=False)
            date_formset = DateFormset(request.POST, instance=event)
            if date_formset.is_valid():
                event.save()
                date_formset.save()
                return HttpResponseRedirect(reverse('frontpage'))
    else:
        form = EventForm()
        date_formset = DateFormset()
    return render_to_response('event/new.html', {
        'form': form,
        'date_formset': date_formset,
        }, context_instance=RequestContext(request))

event/new.html:

[...]
<form action="{% url new-event %}" method="post">
    {% csrf_token %}
    {{ form.as_p }}

    {{ date_formset.management_form }}
    {% for date_form in date_formset.forms %}
        {{ date_form.as_p }}
    {% endfor %}


    <input type="submit" value="{% trans "Create event" %}"/>
</form>
[...]

Best regards, sewid

1条回答
萌系小妹纸
2楼-- · 2019-07-07 05:09

I've tripped over this myself almost by accident. I had an inline formset which had a modelchoicefield on it. That modelchoice had no empty_label. So it technically wasn't entirely blank. When other fields were left out on the inline form it would show validation errors (you can easily test for this in the view and not save the main form unless all the inline forms are valid).

So, it seems you are left with two options: 1) populate the date form with invalid text (i.e. not a date, "helper" text of some kind) that when left in there and submitted it fails to validate, or 2) rework your date selector to dropdown widgets that have no blank state - thus forcing the user to pick something (but you might prefer a proper javascript date widget, which would make multiple dropdowns onerous.

查看更多
登录 后发表回答