mishy
mishy

Reputation: 135

Does form_valid() in CBV not call is_valid() method?

When I used function views, It was able to handle cleaned_data with overriding form.clean() method. I thought when I call form.is_valid method, form.clean() is called too.

Form validation happens when the data is cleaned. If you want to customize this process, there are various places to make changes, each one serving a different purpose. Three types of cleaning methods are run during form processing. These are normally executed when you call the is_valid() method on a form.

Now I'm trying to do same things with class-based-view, but it does not work as I thought.

Here's my forms.py:

class PublishForm(forms.ModelForm):
    class Meta:
        model = models.Article
        exclude = [
           'author',    
         ]

    def __init__(self, user, *args, **kwargs) -> None:
        self.user = user
        return super(PublishForm, self).__init__(*args, **kwargs)

    def is_valid(self):
        print('IS_VALID METHOD CALLED')
        return super(PublishForm, self).is_valid()

    def clean(self):
        print('CLEAN METHOD CALLED')
        cleaned = super(PublishForm, self).clean()
        cleaned['author'] = self.user
        return cleaned

views.py:

class PublishView(generic.CreateView):
    form_class = forms.PublishForm
    success_url = '/'
    template_name = 'ex00/publish.html'

    def form_valid(self, form):
        print(form.cleaned_data)
        return super(PublishView, self).form_valid(form)

    def form_invalid(self, form):
        print(form.errors)
        return super(PublishView, self).form_invalid(form)

and urls.py:

app_name = 'ex00'
urlpatterns = [
    path('', views.HomeView.as_view(), name='home'),
    path('articles/', views.ShowArticlesView.as_view(), name='show-articles'),
    path('detail/<slug:slug>/', views.ArticleDetailView.as_view(), name='article-detail'),
    path('favourites/', views.FavouriteArticlesView.as_view(), name='favourite-articles'),
    path('login/', views.LogInView.as_view(), name='login'),
    path('logout/', views.LogOutView.as_view(), name='logout'),
    path('like/', views.LikeView.as_view(), name='like'),
    path('register/', views.RegisterView.as_view(), name='register'),
    path('publish/', views.PublishView.as_view(), name='publish'),
]

It seems form_valid() does not call neither form.is_valid() or form.clean(). But It was able to get form.cleaned_data().

How does form_valid() work?
What should I do to manipulate cleaned_data like I did it with form.is_valid()?

Addition: enter image description here

I can see the message POST CALLED. But cannot see when added print at ProcessFormView that inherited by PublishView.

console: enter image description here

my template:

{% extends 'share/base.html' %}
{% load django_bootstrap5 %}
{% block title %}Publishing Article{% endblock %}
{% block style %}
<style>
</style>
{% endblock %}
{% block content %}
    <form method="POST">{% csrf_token %}
        {{form}}
        <input type="submit" value="Post">
    </form>
{% endblock %}

Upvotes: 2

Views: 1341

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477338

Short answer: It calls it in the post method. The call to the .clean() method of the form, is part of the validation with form.is_valid().

Indeed, if we take a look at the source code ProcessFormView [GitHub], the view that is inherited by a CreateView, FormView and UpdateView, we see:

class ProcessFormView(View):

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

The post method will thus first create a form, and then check if it is valid, and depending on that, it will call the form_valid method, or the form_invalid method.

The clean() method is not called by the view, but it is part of the form.is_valid() method to clean all individual fields, and then call clean() to validate items not related to a specific field.

Upvotes: 2

Related Questions