2011-10-12 10 views
7

Proszę, pomóżcie mi zrozumieć, czy następujące wybory, które zrobiłem, są idiomatyczne/dobre, a jeśli nie, to jak poprawić.Idiomatyczny sposób przekazywania błędów weryfikacji modelu Django do formularza

1) model walidacji nad formą walidacji
Wolę używać nowego model validation nad walidacji formularza miarę możliwości jak wydaje się bardziej suche i zasadniczy sposób tworzenia reguł dla danych. Dwa przykłady prostego modelu kalendarz wjazdu:

  • "start musi być przed końcem"
  • "okres musi być mniejsza niż (end-start)"

Czy idiomatyczne/dobrze umieścić je na poziomie modelu, aby nie trzeba było wkładać ich do formularzy? Jeśli ModelForm jest najlepszą odpowiedzią, to co z przypadkiem użycia wielu modeli w tej samej formie?
(edit: Nie zdawałem sobie sprawy, że wiele ModelForms rzeczywistości może być stosowany razem)

2) Przesyłanie Walidacja modelu do postaci (nie ModelForm)
(EDIT: Okazuje się, wymyślania hydraulika między weryfikacją modelu a weryfikacją formularza nie jest konieczna w mojej sytuacji, a poniższe rozwiązania pokazują, dlaczego)
Załóżmy przez chwilę, że wszelkie błędy sprawdzania poprawności modelu, które mam, mogą być bezpośrednio przekazywane i wyświetlane bezpośrednio użytkownikowi (tj. ignorowanie modelu tłumaczenia błędy sprawdzania poprawności do przyjaznych dla użytkownika błędów sprawdzania poprawności formularza).

Jest to jeden ze sposobów pracy wymyśliłem to zrobić (wszystko w jednym miejscu, bez funkcje pomocnicze):

view_with_a_form: 
... 
if form.is_valid(): 
    instance = ... 
    ... 
    #save() is overridden to do full_clean with optional exclusions 
    try: instance.save() 
    except ValidationError e: 
     nfe= e.message_dict[NON_FIELD_ERRORS] 
     #this is one big question mark: 
     instance._errors['__all__'] = ErrorList(nfe) 
#this is the other big question mark. seems unnatural 
if form.is_valid() 
    return response... 
... #other code in standard format 
#send the user the form as 1)new 2)form errors 3)model errors 
return form 

Jak zauważył w kodzie:
a) Czy to jest idiomatyczne/dobrze sposób na przeniesienie błędów modelu do formularza?

b) Czy jest to idiomatyczny/dobry sposób na sprawdzenie nowych błędów "formy"?

Uwaga: W tym przykładzie użyto błędów innych niż pola, ale myślę, że może to również dotyczyć błędów w polu.

+0

Zmieniam wybraną odpowiedź, ponieważ aktualizacje od Stefano faktycznie przekonały mnie do adaptacji innej metody ([jedna z połączonych metod ModelForms tutaj] (http://stackoverflow.com/questions/569468/django-multiple-models -in-one-template-using-forms)) bez konieczności wymyślania instalacji hydraulicznej między walidacją modelu i walidacją formularza.(Nie wiedziałem, że można je połączyć). Odpowiedź Chrisa jest wspaniała także dla mojego najlepszego zrozumienia. – KobeJohn

Odpowiedz

4

[Edytowane - nadzieję, że to odpowiada na komentarze]

będę krótki i bezpośredni, ale nie chcę być nieuprzejmy :)

1) model walidacji nad formą walidacji

Sądzę, że reguła może polegać na tym, że tak długo, jak reguła jest naprawdę powiązana z modelem, tak, lepiej jest przeprowadzić walidację na poziomie modelu.

Dla wielokrotnego modelu tworzy, prosimy kasy to inne tak pytanie: Django: multiple models in one template using forms, nie zapominając o attached link która jest nieco stary, ale nadal aktualne na dryest sposób to osiągnąć. To zbyt długo, aby ponownie omówić to wszystko tutaj!

2)

  • a) Nie! Powinieneś wyprowadzić swój formularz z ModelForm, który wykona dla ciebie model validation -> nie musisz sam sprawdzać poprawności modelu
  • b) Nie! Jeśli chcesz sprawdzić poprawność modelu, nie powinieneś próbować go zapisywać; powinieneś użyć full_clean -> więc jeśli twój ModelForm jest ważny, to wiesz, że model jest również ważny i możesz go zapisać.

I tak, odpowiedzi te mają zastosowanie nawet w przypadku formularzy wielomodowych.

Więc co należy zrobić, to:

  • Wciąż użyć ModelForm
  • nie martw się o walidację modelu, ponieważ ModelForm zrobi to za Ciebie.

Ogólnie rzecz biorąc, jeśli robisz coś z django, to dlatego, że jest inny, prostszy sposób na zrobienie tego!

The 2nd wskaźnik powinien Ci zacząć i rzeczywiście uprościć kod dużo ...

+0

Co powiesz na część 1)? – KobeJohn

+0

Jeśli chodzi o część 2), pozwól mi odpowiedzieć z kilkoma punktami, aby lepiej zrozumieć. a) W tym przypadku tak, mógłbym użyć modelForm bardziej czysto. Jednak powinienem był stwierdzić, że mam formularze, które zawierają kilka modeli, więc modelForm nie byłby odpowiedni, prawda? W takim przypadku jest tak, jakbym to zrobił dobrze? b) Wystarczająco fair. Wolę to od urodzenia, ponieważ do tej pory to jedyna kombinacja, którą znalazłem. full_clean, po czym zapisz, jeśli nie ma problemów. Po prostu połączyłem je, zamiast pamiętać o tym na każdym polu. Więcej DRY Myślałem. – KobeJohn

+0

@yakiimo nadzieję, że odpowiedziałem na twoje dodatkowe pytania – Stefano

4

1) Tak, to jest całkowicie poprawny zrobić walidację modelu. Dlatego ludzie Django go dodali. Formularze nie zawsze są używane w procesie zapisywania modeli, więc jeśli sprawdzanie poprawności odbywa się tylko za pomocą formularzy, będziesz mieć problemy. Oczywiście, ludzie pracowali nad tym ograniczeniem w przeszłości, zastępując metodę save i włączając walidację w ten sposób. Jednak nowa walidacja modelu jest bardziej semantyczna i daje haczyk w procesie walidacji, gdy faktycznie używa formularza.

2) Dokumenty dość wyraźnie mówią, że sprawdzanie poprawności modelu (full_clean) jest uruchamiane po wywołaniu ModelForm.is_valid. Jeśli jednak nie używasz ModelForm lub chcesz wykonać dodatkowe przetwarzanie, musisz ręcznie zadzwonić pod numer full_clean. Robisz to, ale umieszczenie go w przesłoniętym save jest niewłaściwym podejściem. Pamiętaj: "Jawny jest lepszy niż niejawny". Poza tym, save jest wywoływana w wielu innych miejscach i sposobach, a w przypadku ModelForm, w ten sposób skończy się uruchamianie full_clean.

To powiedziawszy, ponieważ doktorzy mówią, że ModelForm ma automatycznie, domyśliłem się, że byłoby sensowne, aby zobaczyć, jak radzi sobie z błędami. W metodzie _post_clean, począwszy od linii 323 z django.forms.models:

# Clean the model instance's fields. 
try: 
    self.instance.clean_fields(exclude=exclude) 
except ValidationError, e: 
    self._update_errors(e.message_dict) 

# Call the model instance's clean method. 
try: 
    self.instance.clean() 
except ValidationError, e: 
    self._update_errors({NON_FIELD_ERRORS: e.messages}) 

Z kolei kod _update_errors startów na linii 248 w tym samym module:

def _update_errors(self, message_dict): 
    for k, v in message_dict.items(): 
     if k != NON_FIELD_ERRORS: 
      self._errors.setdefault(k, self.error_class()).extend(v) 
      # Remove the data from the cleaned_data dict since it was invalid 
      if k in self.cleaned_data: 
       del self.cleaned_data[k] 
    if NON_FIELD_ERRORS in message_dict: 
     messages = message_dict[NON_FIELD_ERRORS] 
     self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages) 

Będziesz musiał grać z trochę kodu, ale powinno to dać dobry punkt wyjścia do łączenia błędów sprawdzania poprawności formularza i modelu.

+0

Dobre wywołanie na podstawie kodu źródłowego dla ModelForm. To przyszło mi do głowy, a następnie z niego zrezygnowałem. Zajrzę teraz do tego. Dziękuję za wszystkie części odpowiedzi. – KobeJohn

+0

Po sprawdzeniu kodu dewelopera i dalszej analizie, wygląda na to, że wystarczy mi liny, aby powiesić się na moim poziomie umiejętności. Mam nadzieję, że połączone formularze się sprawdzą. Jeszcze raz dziękuję za odpowiedź i wskazówki. – KobeJohn

Powiązane problemy