alex
alex

Reputation: 2541

Django CreateView with form_class not creating model

I'm practicing from Two Scoops of Django book and i have a problem with form_class in CreateView. If i'm using just fields in the CreateView it's saving the model, if i'm using the form_class it's not saving and not redirecting either.

I'm using form_class for practicing validators.

views.py

class FlavorCreateView(LoginRequiredMixin, CreateView):
    model = Flavor
    success_url = '/flavors/list/'
    template_name = 'flavor_create.html'
    success_msg = 'Flavor created.'
    form_class = FlavorForm
    # fields = ['title', 'slug', 'scoops_remaining']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super(FlavorCreateView, self).form_valid(form)

forms.py

class FlavorForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(FlavorForm, self).__init__(*args, **kwargs)
        self.fields['title'].validators.append(validate_tasty)
        self.fields['slug'].validators.append(validate_tasty)

    class Meta:
        model = Flavor
        fields = ['title', 'slug', 'scoops_remaining']

validators.py

def validate_tasty(value):
    """
    Raise a ValidationError if the value doesn't start with the word 'Tasty'.
    """
    if not value.startswith('Tasty'):
        msg = 'Must start with Tasty'
        raise ValidationError(msg)

flavor_create.html

{% extends 'base_flavor.html' %}

{% block content %}

<form action="" method="POST">{% csrf_token %}
    <p style="color: red;">{{ form.title.errors.as_text }}</p>
    {% for field in form  %}
        <p>{{ field.label }}: {{ field }}</p>
    {% endfor %}
    <button type="Submit">Salveaza</button>

</form>

    <a href="{% url 'flavors:list_flavor' %}">Return home</a>
{% endblock %}

Upvotes: 1

Views: 4287

Answers (1)

Risadinha
Risadinha

Reputation: 16666

Your code probably just works as expected (it looks that way):

"it's not saving and not redirecting" := that is what happens when there is a validation error.

Override form_invalid as well and print some log output. Or just output the form errors in the template.

What happens in case of validation errors in Django is that the form is reloaded and the errors are added to the template context so that they can be rendered for the user.


Just a side note:

As alternative to

self.fields['title'].validators.append(validate_tasty)

You can simply add the validate_tasty method directly to your FlavorForm under the name clean_title and clean_slug. This is a Django standard way for adding custom validation logic.

class FlavorForm(forms.ModelForm):

    def clean_title(self):
        # even if this is a required field, it might be missing
        # Django will check for required fields, no need to raise
        # that error here, but check for existence
        title = self.cleaned_data.get('title', None)
        if title and not value.startswith('Tasty'):
            msg = 'Must start with Tasty'
            raise ValidationError(msg):
        return title

    class Meta:
        model = Flavor
        fields = ['title', 'slug', 'scoops_remaining']

Upvotes: 2

Related Questions