ModelsForms mit Choices validiert nicht korrekt

Um es vorweg zu nehmen, dies ist die Beschreibung eines Bugs in Django. Ja, dafür gibt es schon ein Ticket und nein, es ist derzeit noch nicht im Trunk gefixt.

Oki, wer bis hierhin durchgehalten hat, weiter gehts: :-)

Angenommen wir haben dieses simple Model, die Werte des Testfeldes bestehen aus den vorher definierten Choices.

from django.db import models

CHOICES = (
    (u'Bube', u'Bube'),
    (u'Dame', u'Dame'),
    (u'Koenig', u'Koenig'),
    (u'Ass', u'Ass'),
)

# Das Model
class TestModel(models.Model):
    testfeld = models.CharField(max_length=30, choices=CHOICES)

Um ein simples Formular daraus zu erstellen ist ModelForms ideal:

from testprojekt.models import TestModel
from django import forms # Django 1.0 Alpha wohooo!

class TestForm(forms.ModelForm):
    class Meta:
        model = TestModel

Einfacher gehts kaum, mit den paar Zeilen hat man schon ein komplettes Formular parat. Aber dass wußtest du sicher schon, also weiter. Basteln wir uns eine einfache Ausgabe:

>>> f = TestForm()
>>> f.as_ul()

# Beispielausgabe
<select name="testfeld" id="id_testfeld">
    <option value="Bube">Bube</option>
    <option value="Dame">Dame</option>
    <option value="Koenig">Koenig</option>
    <option value="Ass">Ass</option>
</select>

Alles korrekt bis hier hin. Angenommen das Formular wird nun auf der Webseite angezeigt, der User wählt "Bube" und schickt das Formular ab:

>>> f = TestForm(data={'testfeld': 'Bube'})
>>> f.as_ul()

<select name="testfeld" id="id_testfeld">
    <option value="Bube" selected="selected">Bube</option>
    <option value="Dame">Dame</option>
    <option value="Koenig">Koenig</option>
    <option value="Ass">Ass</option>
</select>

>>> f.is_valid()
True

Das Formular ist valide, weil "Bube" ja eine korrekte Auswahl für das Feld 'testfeld' ist. Aber zur Erinnerung: SELECT-Felder in HTML sind auch nur stinknormale Datenfelder und der Browser prüft nicht, ob der abgesendete Wert auch des Feldes auch vorher in den SELECT-Options definiert wurde. Ändern wir also mal die Werte der Formulardaten:

>>> f = TestForm(data={'testfeld': 'Boeses Maedchen'})
>>> f.as_ul()

<select name="testfeld" id="id_testfeld">
    <option value="Bube">Bube</option>
    <option value="Dame">Dame</option>
    <option value="Koenig">Koenig</option>
    <option value="Ass">Ass</option>
</select>

>>> f.is_valid()
True

Wem das nicht schlimm erscheint: Diese Daten speichert das Formular leider auch in die Datenbank, das Model selbst validiert also nicht noch einmal nach.

>>> objekt = f.save()
>>> objekt.testfeld
u'Boeses Maedchen'

Ganz fatal in meinen Augen. Zur Erinnerung, eigentlich sollte das testfeld im Model nur die Daten Bube, Dame, Koenig und Ass annehmen.

Wie kann man eigentlich "fremde" Daten in ein Select-Feld schreiben? Nichts einfacher als das, die bekannte Firefox-Extension "Web Developer Toolbar" hat eine eigene Funktion dafür:

Mein derzeitiger Lösungsvorschlag sieht so aus, dass ich einfach mit einer clean-Methode auf das Vorhandensein der Eingabe in den Choices prüfe:

from testprojekt.models import TestModel, CHOICES
from django import forms

class TestForm(forms.ModelForm):

    def clean_testfeld(self):
        if not self.cleaned_data['testfeld'] in dict(CHOICES):
            raise forms.ValidationError(u'%s is not a valid choice' % (self.cleaned_data['testfeld']))            
        return self.cleaned_data['testfeld']

    class Meta:
        model = TestModel

Dann klappts auch wie gewünscht.

>>> f = TestForm(data={'testfeld': 'Boeses Maedchen'})
>>> print f.is_valid()
False
>>> f.as_ul()
errorlist: "Boeses Maedchen is not a valid choice"
<select name="testfeld" id="id_testfeld">
    <option value="Bube">Bube</option>
    <option value="Dame">Dame</option>
    <option value="Koenig">Koenig</option>
    <option value="Ass">Ass</option>
</select

Durch das derzeitge Release von Django 1.0 Alpha gehe ich aber mal davon aus, dass dieser Bug in nächster Zeit gefixt wird. Ein Patch exisitiert ja schon.


Comments closed

Sorry, new comments are no longer allowed for this entry.

Write me an email if you have feedback or any questions regarding this post. If you found this post useful and just want to say thank you then don't forget that I have an Amazon Wishlist. :-)


↑ to the elevators

© 2001—2010 Martin Mahner. This is an I ♥ Django Project.

Admin | Generated: Wed, 1 Sep 2010 06:51:30 +0200