2009-10-12 14 views
11

W niestandardowym formularzu w jaki sposób można zweryfikować unikalność pola modelu (tzn. Ma on zestaw unique=True)?Jak sprawdzić/wyczyścić() a unikalne = Prawdziwe pole bez użycia ModelForm?

wiem, że Django ModelForm automatycznie wykonuje validate_unique() funkcji, która jest wywoływana wewnątrz clean() metoda BaseModelForm jest - tak, przy użyciu ModelForm, to będzie prawidłowo obsługiwane (jak to jest w admin).

Jednak tworzę swój własny formularz od podstaw i zastanawiam się, jak sam mogę sobie z tym poradzić? Myślę, że moją największą przeszkodą jest wiedzieć, który obiekt jest dołączony do formularza, gdy dane jest czyszczona ...

Niektóre kodu:

class UserProfile(CreatedModifiedModel): 
    user   = models.ForeignKey(User, unique=True) 
    display_name = models.CharField('Display Name',max_length=30, 
         blank=True,unique=True) 

class EditUserProfileForm(forms.Form): 
    display_name = forms.CharField(required=False,max_length=30) 

    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    def clean_display_name(self): 
     # how do I run my own validate_unique() on this form? 
     # how do I know which UserProfile object I am working with? 

    # more code follows, including the __init__ which sets up the notifications 
+1

Czy istnieje jakiś powód, dla którego tworzysz niestandardową formę zamiast ModelForm? – tghw

+0

Zaktualizowałem kod, aby wyświetlał pole "powiadomienia", które jest potrzebne z innej aplikacji, ale obsługiwane na tym samym EditUserProfileForm ... mam nadzieję, że ma to sens. Nie sądzę, mogę zrobić ModelForm z wielu źródeł modelu ... – thornomad

Odpowiedz

15

Unikalne walidacja jest trudno dostać się całkowicie w prawo, tak bym polecam przy użyciu ModelForm anyways:

class EditUserProfileForm(forms.ModelForm): 
    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    class Meta: 
     model = UserProfile 
     fields = ('display_name',) 

Tworzenie formularza z wielu modeli nie jest łatwe, ale w tym przypadku można po prostu dodać pole notifications na ModelForm i wyciągnąć go z .cleaned_data jak zwykle:

# view 
if request.method == 'POST': 
    form = EditUserProfileForm(request.POST, instance=user_profile) 
    if form.is_valid(): 
     user_profile = form.save() 
     notifications = form.cleaned_data['notifications'] 
     # Do something with notifications. 

To jak zrobiłbym to, ale jeśli jesteś ustawiony na sprawdzanie wyjątkowy siebie, zawsze można zrobić coś takiego:

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    if UserProfile.objects.filter(display_name=display_name).count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

Istnieją dwa problemy tutaj widzę. Po pierwsze, możesz napotkać problemy z współbieżnością, w których dwie osoby przesyłają tę samą nazwę, oba przechodzą unikalne sprawdzenia, ale jeden dostaje błąd DB. Innym problemem jest to, że nie możesz edytować profilu użytkownika, ponieważ nie masz identyfikatora, który ma zostać wykluczony z wyszukiwania. Trzeba by przechowywać go w __init__ a następnie użyć go do czyszczenia:

def __init__(self, *args, **kwargs): 
    ... 
    if 'instance' in kwargs: 
     self.id = kwargs['instance'].id 
    ... 

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    qs = UserProfile.objects.filter(display_name=display_name) 
    if self.id: 
     qs = qs.exclude(pk=self.id) 
    if qs.count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

Ale w tym momencie jesteś po prostu powielenie logikę w ModelForms.

+1

Hej - dzięki za to. Nie byłem pewien o dodawaniu pól do ModelForm, które nie odpowiadają modelowi ... Ale dam to spróbować na początek. Jeśli będę miał problemy, zgłoś to. – thornomad

+0

tghw dzięki bro, świetna odpowiedź – PyDroid

Powiązane problemy