2012-10-23 21 views
23

Nadal próbuję zrozumieć poprawny sposób sprawdzania poprawności obiektu modelu Django za pomocą niestandardowego weryfikatora na poziomie modelu. Wiem, że sprawdzanie poprawności odbywa się zwykle w formie formularza lub modelu. Jednak chcę zapewnić integralność moich danych na poziomie modelu, jeśli wchodzę z nim w interakcję za pośrednictwem ORM w powłoce Pythona. Oto moje obecne podejście:Prawidłowy sposób sprawdzania poprawności obiektów modelu Django?

from django.db import models 
from django.core import validators 
from django.core exceptions import ValidationError 


def validate_gender(value): 
    """ Custom validator """ 
    if not value in ('m', 'f', 'M', 'F'): 
     raise ValidationError(u'%s is not a valid value for gender.' % value) 


class Person(models.Model): 
    name = models.CharField(max_length=128) 
    age = models.IntegerField() 
    gender = models.CharField(maxlength=1, validators=[validate_gender]) 

    def save(self, *args, **kwargs): 
     """ Override Person's save """ 
     self.full_clean(exclude=None) 
     super(Person, self).save(*args, **kwargs) 

Oto moje pytania:

  1. należy utworzyć niestandardową funkcję sprawdzania, wyznacza ją jako weryfikatora, a następnie zastąpić osoby save() funkcja, jak ja” ve zrobione powyżej? (Nawiasem mówiąc, wiem, że mogłem potwierdzić moje wybory dotyczące płci przy użyciu opcji pola "wyboru", ale stworzyłem "validate_gender" w celu ilustracji).

  2. Gdybym naprawdę chce zapewnić integralność moich danych, nie powinien piszę tylko testy jednostkowe Django do testów w warstwie modelu, ale również testy jednostkowe odpowiednik na poziomie bazy danych przy użyciu Python/Psycopg? Zauważyłem, że testy jednostkowe Django, które podnoszą wartości ValidationErrors, sprawdzają tylko model zrozumienia schematu bazy danych za pomocą kopii bazy danych. Nawet jeśli używałbym Południa do migracji, wszelkie ograniczenia na poziomie bazy danych są ograniczone do tego, co Django może zrozumieć i przetłumaczyć na ograniczenie PostgreSQL. Jeśli potrzebuję niestandardowego ograniczenia, którego nie może replikować Django, mogę potencjalnie wprowadzić dane do mojej bazy danych, które naruszają to ograniczenie, jeśli wchodzę w interakcję z bazą danych bezpośrednio za pośrednictwem terminala psql.

Dzięki!

+0

Nie jestem pewien, jak pytanie 1 różni się od poprzednich pytań na ten temat. Zauważ, że nadal nie zapobiega wstawianiu nieprawidłowych danych za pomocą ORM. Rozważ "Person.objects.update (gender =" a ")'. – Alasdair

+1

Masz rację, z wyjątkiem tego, że w poprzednim pytaniu nie zawierałem funkcji sprawdzania poprawności, tak jak tutaj. Jeśli chodzi o twoją drugą obserwację dotyczącą .update, domyślam się, że mam teraz dodatkowy problem, który dodaje do mojego zamieszania.Naprawdę walczę ze zrozumieniem, co jest właściwym sposobem na zrobienie tego. Podczas gdy dokumentacja Django jest całkiem niezła, IMHO, są one długie na fragmentach i "machaniu ręką", ale brakuje im pełnych przykładów, które pomogłyby "nowicjuszowi", takim jak ja, zrozumieć prawidłowy sposób rozwiązania tego problemu. Niestety, pracuję sam i nie mam bardziej doświadczonych programistów, którzy mogliby to omówić. – William

Odpowiedz

16

Miałem podobne nieporozumienie z ORMem, kiedy zaczynałem od Django.

1) Nie, nie umieszczaj self.full_clean() wewnątrz save. Albo

A) używać ModelForm (co spowoduje, wszystko jedno walidacja wystąpić - uwaga: ModelForm.is_valid() nie zadzwoni Model.full_clean wyraźnie, ale będzie wykonywał te same kontrole jak Model.full_clean). Przykład:

class PersonForm(forms.ModelForm): 
    class Meta: 
     model = Person 

def add_person(request): 
    if request.method == 'POST': 
     form = PersonForm(request.POST, request.FILES) 
     if form.is_valid(): # Performs your validation, including ``validate_gender`` 
      person = form.save() 
      return redirect('some-other-view') 
    else: 
     form = PersonForm() 
     # ... return response with ``form`` in the context for rendering in a template 

Należy również pamiętać, formy nie są przeznaczone do użytku tylko w widokach, które czynią je w szablonach - są idealne dla każdego rodzaju zastosowania, w tym API itp po uruchomieniu form.is_valid() i otrzymuję błędy, będziesz mieć form.errors, który jest słownikiem zawierającym wszystkie błędy w formularzu, w tym klucz o nazwie '__all__', który będzie zawierał błędy inne niż pola.

B) Po prostu użyj model_instance.full_clean() w widoku (lub innej logicznej warstwie aplikacji), zamiast korzystać z formularza, ale formularze są miłym dla tego abstrakcją.

2) Nie mam rozwiązania, ale nigdy nie napotkam takiego problemu, nawet w dużych projektach (obecny projekt, w którym pracuję z moją firmą ma 146 tabel) i nie mam podejrzewam, że będzie to również niepokojące w twoim przypadku.

+2

Czy mówisz, że powinienem użyć formularza formularza lub modelu do sprawdzenia poprawności moich modeli danych, nawet jeśli faktycznie nie przedstawiam modelu obiektu w rzeczywistej formie szablonu dla użytkownika? Dzięki. – William

+1

@RobertF. - To jest poprawne. Klasa 'ModelForm' jest przyzwoitą abstrakcją do sprawdzania poprawności modelu, niezależnie od tego, czy aktualizuje się, czy tworzy instancje, nawet jeśli nie zamierza się wyświetlać formularza w szablonie. – orokusaki

+1

Powiedziałeś, że albo A) to zrobić, a jaka jest opcja B? – rgenito

Powiązane problemy