2012-09-05 16 views
18

Jest to problem, który pojawił się podczas pracy nad projektem Django. Chodzi o walidację formularza.Python: Unikaj oceny zwarcia

W Django, po przesłaniu formularza można wywołać is_valid() na odpowiednim obiekcie formularza, aby uruchomić sprawdzanie poprawności i zwrócić wartość typu Boolean. Tak, zazwyczaj masz kod tak wewnątrz Państwa zdanie funkcji:

if form.is_valid(): 
    # code to save the form data 

is_valid() sprawdza nie tylko dane formularza, ale również dodaje komunikaty o błędach do obiektu formularza, który może być następnie wyświetlane użytkownikowi.

Na jednej stronie używam dwóch formularzy razem, a także chcę, aby dane były zapisywane, tylko jeśli oba formularze zawierają prawidłowe dane. Oznacza to, że muszę wywołać is_valid() na obu formularzach przed wykonaniem kodu, aby zapisać dane. Najbardziej oczywisty sposób:

if form1.is_valid() and form2.is_valid(): 
    # ... 

nie będzie działać z powodu oceny zwarcia operatorów logicznych. Jeśli formularz1 nie jest prawidłowy, formularz2 nie zostanie oceniony, a jego komunikaty o błędach będą nieobecne.

To tylko przykład. O ile mi wiadomo, nie ma chciwej alternatywy dla and/or, podobnie jak w innych językach (np. Smalltalk). Mogę sobie wyobrazić ten problem występujący w różnych okolicznościach (i nie tylko w Pythonie). Rozwiązania, o których mogłem myśleć, są wszelkiego rodzaju niezgrabne (zagnieżdżone ifs, przypisujące wartości zwracane do zmiennych lokalnych i używające ich w instrukcji if). Chciałbym poznać pytonowy sposób rozwiązania tego rodzaju problemów.

Z góry dziękuję!

Odpowiedz

27

Jak o czymś takim:

if all([form1.is_valid(), form2.is_valid()]): 
    ... 

W ogólnym przypadku, wykaz-zrozumieniem mogłyby zostać wykorzystane więc wyniki są obliczane z przodu (w przeciwieństwie do ekspresji generator, który jest powszechnie stosowany w tym kontekście) . np .:

if all([ form.is_valid() for form in (form1,form2) ]) 

To będzie skalować się ładnie do dowolnej liczby warunków, jak również ... Jedynym haczykiem jest to, że wszystkie one muszą być podłączone przez „and” w przeciwieństwie do if foo and bar or baz: ....

(dla krótkiego obwodu or można użyć any zamiast all).

+0

Dokładnie to, czego szukałem. Dziękuję Ci! – j0ker

+2

Zabrało mi to kilka sekund. Jest to przypadek narożny, którego wcześniej nie brałem pod uwagę (często pracuję w Fortranie, który nie gwarantuje zwarcia, ale pozwala na to) i zawsze staram się wymyślić, jak upewnić się, że moje wyrażenia są zwarte. Rozszyfrowanie tego było dla mnie trochę odwrotne :). – mgilson

+0

Tak, "wszystko" jest tutaj, ale gdzie używasz zrozumienia list? Widzę tylko prostą listę na twoim przykładzie. – rantanplan

16

Możesz po prostu użyć operatora binarnego &, który wykona logikę niezawierającą zwarcia i na sygnałach.

if form1.is_valid() & form2.is_valid(): 
    ... 
+3

Dokładniej, zrobi on bitowe 'i' na liczbach całkowitych. Ponieważ boole są wyprowadzane z liczb całkowitych z "True == 1" i "False == 0", to działa. Nie będzie (koniecznie) działać dla innych typów lub funkcji, które zwracają rzeczy, które nie są boolean. Mimo to jest dobrym narzędziem do posiadania (+1) – mgilson

+1

Zdecydowanie prostsze niż rozwiązanie przez MGilson. Dziękuję za to! Drugi może być bardziej pomocny dla innych osób czytających kod. Tutaj, myślę, że możesz pomyśleć, że po prostu pomyliłem 'i' oraz' & '. – j0ker

+0

@mgilson Funkcja 'all' była również pierwszym rozwiązaniem, które przyszło mi do głowy (użyłbym go dokładnie z tego powodu, o którym wspomniał j0ker), ale odkryłem to pytanie za późno na tę odpowiedź (+1, btw) :-) – sloth