'Django: How to return an inline formset with errors

I have created a form to sign up a user by having them create a User object and a UserProfile object as follows:

class UserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("email",)

class UserProfileCreationForm(ModelForm):
    class Meta:
        model = UserProfile
        fields = (
            "first_name",
            "last_name",
        )

RegisteredCustomerProfileCreationInlineFormset = inlineformset_factory(
    User,
    UserProfile,
    form=UserProfileCreationForm,
    extra=1,
    can_delete=False,
    can_order=False,
)

In my view to display the sign up form, I do the following:

class UserSignupView(CreateView):
    form_class = UserCreationForm
    template_name = "users/signup_form.html"

    def get_context_data(self, **kwargs):
        """Adds the inline formset to the context."""
        context = super(UserSignupView, self).get_context_data(**kwargs)

        if self.request.POST:
            context[
                "user_profile_inline"
            ] = UserProfileCreationInlineFormset(
                self.request.POST
            )
        else:
            context[
                "user_profile_inline"
            ] = UserProfileCreationInlineFormset()
        return context

    def form_invalid(self, request, form):
        # Note: I added request as an argument because I was getting an error that
        # says the method is expecting 2 arguments but got 3.
        return render(self.request, self.template_name, 
            self.get_context_data(
                form=form
            )
        )

    def form_valid(self, form):
        context = self.get_context_data()
        user_profile_inline = context["user_profile_inline"]

        if (
            form.is_valid()
            and user_profile_inline.is_valid()
        ):
            # Handle valid case
            ...
            return redirect(
                self.request.GET.get(reverse_lazy("index"))
            )

        else:
            self.form_invalid(self, form)

My template is as simple as

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    {{ user_profile_inline.as_p }}
    <button type="submit" value="Save">Sign Up</button>
</form>

When my form which is for creation of the User object is invalid, the template is reloaded nicely with the errors in the form. However, when the formset is invalid, I get the error: "didn't return an HttpResponse object. It returned None instead."

Please may you assist me with the correct way of reloading the template with errors for the inline formset.



Solution 1:[1]

For me I had a Function Based View.

If your code looks something like this:

views.py


def fbv(request, model_slug):
    modelName = ModelName.objects.get(slug=model_slug)

    ModelName2Formset = inlineformset_factory(
                    ModelName, ModelName2, fields=('field1', 'field2',), 
                    extra=3, 
                    can_delete = True,
                    widgets={
                        'field1': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Text here'}),
                        'field2': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Numbers here'}),
                        },
                    )

    if request.method == "POST":
    
        formset = ModelName2Formset(request.POST, instance=modelName)
        
        
        if formset.is_valid():
            
            formset.save()

            return HttpResponseRedirect('url-name')
        

    
    formset = ModelName2Formset(instance=modelName)

    return render(request, 'AppName/add-modelName2.html', {'formset' : formset, 'modelName': modelName})


What I did was to add an else to the if request.method == "POST":

views.py

def fbv(request, model_slug):

    ...

    if request.method == "POST":
    
        formset = ModelName2Formset(request.POST, instance=modelName)
        
        
        if formset.is_valid():
            
            formset.save()

            return HttpResponseRedirect('url-name')
        

    # I added else here
    else:
        formset = ModelName2Formset(instance=modelName)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AnonymousUser