admin 0Comment

Miało być dzisiaj o czymś innym, ale trafiłem na ciekawą kwestię i pomyślałem, że podzielę się nią z Wami. Wpis będzie dotyczył pracy z frameworkiem Django – myślę, że wielu wannabe-web-developerów, uczących się programowania przy wykorzystaniu języka Python prędzej czy później zapozna się z tym narzędziem i tego rodzaju wpisy mogą się okazać dla nich przydatne. Nawet jeśli nie zetknąłeś się jeszcze z frameworkiem, i tak warto żebyś czytał dalej – wspierając się nieco google-szukajką powinieneś zrozumieć o czym piszę a moje wnioski zawarte we wpisie są dość uniwersalne.

No to wracamy do tematu. Zajmowałem się dzisiaj m. in. kontynuowaniem pracy nad funkcjami CRUD (jeśli chcesz wiedzieć więcej na ten temat, zerknij do tego tematu) w mojej konkursowej aplikacji.  Wcześniej, jeszcze w momencie jej projektowania, zdecydowałem się na używanie widoków bazujących na funkcjach (możemy pisać także widoki bazujące na klasach – jeśli chcesz poczytać o tym więcej, to jest ten moment na skorzystanie z google-szukajki), których schemat wykorzystywania często wygląda mniej więcej tak:

def add_object(request):
	if request.method == 'POST':
        	form = ModelForm(request.POST)
		if form.is_valid():
			# Tutaj operujesz na dostarczonych w formularzu danych, np.
                        # zapisujesz  obiekt w bazie danych.
			return redirect(request, 'success.html')
	form = ModelForm ()
	return render(request, 'template_with_form.html', {'form':  form})

Dla osób nie pracujących z wykorzystaniem Django – jest to przykład, w którym po stronie użytkownika najpierw wyświetli się pusty formularz (po pierwszym wywołaniu funkcji nasz warunek if nie będzie spełniony, więc program przejdzie dalej i umieści ‚pusty’ form w podanym template). Wypełnienie i zatwierdzenie formularza spowoduje, że funkcja ponownie zostanie wywołana, tym jednak razem warunek if zostanie spełniony (dzięki danym podanym przez użytkownika w polach formularza) i, jeśli tylko formularz został wypełniony prawidłowo, zostanie wykonany dalszy kod tak jak jest to opisane w komentarzu, po czym program może wyświetlić kolejny template informujący o tym, że zadanie (np. zapisanie obiektu, którego dane wypełniał w formularzu użytkownik) zostało wykonane.

Oczywiście można (a nawet należy) dodać tutaj inne elementy (np. obsługę sytuacji, kiedy formularz zostanie wypełniony, ale niewłaściwie) – nie o to jednak chodzi w moim dzisiejszym wpisie. Podczas wyszukiwania informacji w google natrafiłem na coś, co na pierwszy rzut oka wydawało się być bardzo fajnym rozwiązaniem – tzw. The Easy Form Views Pattern, co możemy przetłumaczyć na Wzorzec Prostych Widoków Formularza. Oto jak wygląda:

def add_object(request):
        form = ModelForm(request.POST or None)
	if form.is_valid():
		# Tutaj operujesz na dostarczonych w formularzu danych, np. zapisujesz 			
                # obiekt w bazie danych etc.
		return redirect(request, 'success.html')
	return render(request, 'template_with_form.html', {'form':  form})

Na pierwszy rzut oka całość wygląda zdecydowanie lepiej niż wcześniejszy przykład – skracamy kod i rezygnujemy z zagnieżdżenia if-a w if-ie. W końcu o to przecież chodzi, programując w Pythonie, prawa? No właśnie nie do końca, a przynajmniej nie w tym przypadku.

Zanim zabrałem się za refactoring moich pozostałych widoków na wzór tego, stwierdziłem, że warto poczytać więcej na temat tego rozwiązania (które, swoją drogą, jest często wykorzystywane w praktyce, co zauważyłem rozglądając się za nim po innych repozytoriach na GitHubie). Przede wszystkim – w jaki sposób ono działa? Wykorzystujemy to, że w każdym view istnieje request.POST, tyle, że może być ono tylko pustym obiektem typu dictionary, której wartość logiczna w tej sytuacji to False. Jeśli poprzez wypełnienie formularza elementy zostały dodane do tego obiektu¸ całość będzie już miała wartość True.

Konsekwencją jest to, że drugi zaprezentowany tutaj kod ten opiera się na sprawdzaniu czy są dane w POST a nie, czy element jest POST, co w skrajnych przypadkach może doprowadzić do bugów i to takich, które będzie nam trudno zidentyfikować. Nie chodzi o to, że jest to kod błędny w tym konkretnym miejscu, po prostu jest on bardziej podatny na wystąpienie błędów w niektórych sytuacjach, w których będzie on wykorzystany. Może tak wydarzyć się, jeśli w konkretny sposób będziemy chcieli obsłużyć wysłanie pustego formularza albo, gdy będzie się on składał wyłącznie z checkboxes, czyli pól do „zaptaszkowania” odpowiedzi, i żadne z nich nie zostanie zaznaczone, możliwości są różne.

Po namyśle stwierdziłem więc, że zostaję przy dłuższych, ale pozbawionych takiej możliwości, widokach w Django. Wnioski? Przede wszystkim jeden główny – oczywiście nie ma żadnego sensu w każdej możliwej programistycznej sytuacji odkrywać koła na nowo. Korzysta się i należy korzystać z rozwiązań, na które natrafimy, takich jak biblioteki czy właśnie inne schematy pisania kodu. Kluczowe jest by robić to refleksyjnie, tzn. poczytać więcej na dany temat, poznać słabe i mocne strony danego rozwiązania a nie tylko bawić się w bezmyślne kopiuj – wklej.

 

Dodaj komentarz