Csaba Schnitchen
Csaba Schnitchen

Reputation: 107

Why my Django ModelForm doesn't raise validation error for unique_together constraint?

I have read in Django documentation that the clean() method of ModelForm validates the unique_together constraint on my model, and raises a ValidationError if it is not validated. However my ModelForm doesn't do this. At least it doesn't give an error message in the form, instead I get a Django error and traceback:

ValueError at / The Jelentkezes could not be created because the data didn't validate.

This is not because I have excluded one of the fields of the unique_together constraint. Other validations of the form work, they give error messages on the form. Please help, thank you!

I use Django 1.10 and Python is 3.5.

I have created the following models in models.py:

from django.db import models

class FoglalkozasTipus(models.Model):
    foglalkozas_tipusa = models.CharField(max_length=255, unique=True)

    def __str__(self):
        return '%s' % (self.foglalkozas_tipusa)

class Foglalkozas(models.Model):
    kezdet = models.DateTimeField()
    veg = models.DateTimeField()
    foglalkozas_tipusa = models.ForeignKey(FoglalkozasTipus, 
        on_delete=models.CASCADE)

    class Meta:
        unique_together = (("kezdet", "veg"),)
        ordering = ['kezdet', 'veg']

    def __str__(self):
        return '%s-%s %s' % (self.kezdet.strftime("%Y.%m.%d %H:%M"), 
            self.veg.strftime("%H:%M"), self.foglalkozas_tipusa)

class Jelentkezes(models.Model):
    foglalkozas = models.ForeignKey(Foglalkozas, on_delete=models.CASCADE)
    email = models.EmailField()
    vezeteknev = models.CharField(max_length=255)
    keresztnev = models.CharField(max_length=255)

    class Meta:
        unique_together = (("foglalkozas", "email"),)

    def __str__(self):
        return '%s: %s %s (%s)' % (self.foglalkozas, self.vezeteknev, 
            self.keresztnev, self.email)

For model Jelentkezes I have created a ModelForm in forms.py:

from django.utils import timezone
from django.forms import ModelForm, RadioSelect
from .models import Jelentkezes, Foglalkozas

class JelentkezesForm(ModelForm):

    class Meta:
        model = Jelentkezes
        fields = ['foglalkozas', 'email', 'vezeteknev', 'keresztnev']
        widgets = {
            'foglalkozas': RadioSelect,
        }

    def __init__(self, *args, **kwargs):
        super(JelentkezesForm, self).__init__(*args, **kwargs)
        self.fields['foglalkozas'].queryset = 
            Foglalkozas.objects.filter(kezdet__gt=timezone.now())
        self.fields['foglalkozas'].empty_label = None

In views.py I use this ModelForm:

from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import JelentkezesForm

def index(request):
    if request.method == 'POST':
        form = JelentkezesForm(request.POST)
        form.save()
        return HttpResponseRedirect('koszonet/')

    else:
        form = JelentkezesForm()

    return render(request, 'aviva/index.html', {'form': form})

In index.html the form looks like this (I use W3.CSS framework and django-widget-tweaks for styling):

{% load widget_tweaks %}

<form action="" method="post">
    {% csrf_token %}
    {{ form.non_field_errors }}
    {{ form.foglalkozas.errors }}
    <label class="w3-label" for="{{ form.foglalkozas.id_for_label }}"><b>{{ form.foglalkozas.label }}:</b></label>
    {% for radio in form.foglalkozas %}
    <div class="w3-radio">
        {{ radio }}
    </div>
    {% endfor %}
    {{ form.email.errors }}
    <label class="w3-label" for="{{ form.email.id_for_label }}"><b>{{ form.email.label }}:</b></label>
    {{ form.email|add_class:"w3-input w3-border w3-round" }}
    {{ form.vezeteknev.errors }}
    <label class="w3-label" for="{{ form.vezeteknev.id_for_label }}"><b>{{ form.vezeteknev.label }}:</b></label>
    {{ form.vezeteknev|add_class:"w3-input w3-border w3-round" }}
    {{ form.keresztnev.errors }}
    <label class="w3-label" for="{{ form.keresztnev.id_for_label }}"><b>{{ form.keresztnev.label }}:</b></label>
    {{ form.keresztnev|add_class:"w3-input w3-border w3-round" }}
    <p><input type="submit" class="w3-btn w3-blue w3-left w3-border" value="Jelentkezés elküldése" />
    <button type="reset" class="w3-btn w3-yellow w3-right w3-border" value="Reset">Űrlapadatok törlése</button></p>
</form>

Upvotes: 3

Views: 1208

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 600059

You never call the validation on your form. It should be:

if request.method == 'POST':
    form = JelentkezesForm(request.POST)
    if form.is_valid():
        form.save()
        return HttpResponseRedirect('koszonet/')

Upvotes: 1

Related Questions