Właśnie zacząłem pracować z Django pochodzącym z lat Spring MVC, a implementacja formularzy wydaje się nieco szalona. Jeśli nie jesteś zaznajomiony, formularze Django zaczynają się od klasy modelu formularza, która definiuje twoje pola. Wiosna podobnie zaczyna się od obiektu opartego na formularzu. Ale tam, gdzie Spring udostępnia taglib do wiązania elementów formularza do obiektu podkładu w JSP, Django ma widżety formularzy powiązane bezpośrednio z modelem. Istnieją domyślne widżety, w których można dodać atrybuty stylu do pól w celu zastosowania CSS lub zdefiniować całkowicie niestandardowe widżety jako nowe klasy. Wszystko idzie w kodzie Pythona. To wydaje mi się szalone. Po pierwsze, umieszczasz informacje o swoim widoku bezpośrednio w swoim modelu, a po drugie wiążesz swój model z określonym widokiem. Czy coś brakuje?
EDYCJA: Niektóre przykładowy kod na żądanie.
Django:
# Class defines the data associated with this form
class CommentForm(forms.Form):
# name is CharField and the argument tells Django to use a <input type="text">
# and add the CSS class "special" as an attribute. The kind of thing that should
# go in a template
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
# Again, comment is <input type="text" size="40" /> even though input box size
# is a visual design constraint and not tied to the data model
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
Wiosna MVC:
public class User {
// Form class in this case is a POJO, passed to the template in the controller
private String firstName;
private String lastName;
get/setWhatever() {}
}
<!-- JSP code references an instance of type User with custom tags -->
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- "user" is the name assigned to a User instance -->
<form:form commandName="user">
<table>
<tr>
<td>First Name:</td>
<!-- "path" attribute sets the name field and binds to object on backend -->
<td><form:input path="firstName" class="special" /></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName" size="40" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form:form>
Odpowiedzi:
Tak, formy Django to bałagan z perspektywy MVC, załóżmy, że pracujesz w wielkiej grze MMO superbohater i tworzysz model Bohatera:
Teraz musisz utworzyć formularz, aby gracze MMO mogli wprowadzić swoje super moce bohatera:
Ponieważ Odstraszacz Rekinów jest bardzo potężną bronią, twój szef poprosił cię o jej ograniczenie. Jeśli bohater ma Odstraszacz Rekinów, nie może latać. To, co większość ludzi robi, to po prostu dodać tę regułę biznesową w postaci czystej i nazwać to dniem:
Ten wzór wygląda fajnie i może działać na małych projektach, ale z mojego doświadczenia jest bardzo trudny do utrzymania w dużych projektach z wieloma programistami. Problem polega na tym, że formularz jest częścią widoku MVC. Musisz więc pamiętać tę regułę biznesową za każdym razem, gdy:
Chodzi mi o to, że forms.py dotyczy układu i prezentacji formularza, nigdy nie należy dodawać logiki biznesowej do tego pliku, chyba że lubisz bawić się kodem spaghetti.
Najlepszym sposobem na rozwiązanie problemu z bohaterem jest użycie metody czyszczenia modelu oraz niestandardowego sygnału. Model clean działa podobnie do formularza clean, ale jest przechowywany w samym modelu, za każdym razem, gdy HeroForm jest czyszczony, automatycznie wywołuje metodę Hero clean. Jest to dobra praktyka, ponieważ jeśli inny programista napisze kolejną formę dla Bohatera, otrzyma bezpłatną weryfikację odstraszania / muchy.
Problem z czyszczeniem polega na tym, że jest wywoływany tylko wtedy, gdy model jest modyfikowany przez formularz. Nie jest wywoływany, gdy ręcznie go zapiszesz () i możesz skończyć z niepoprawnym bohaterem w bazie danych. Aby przeciwdziałać temu problemowi, możesz dodać tego detektora do swojego projektu:
Spowoduje to wywołanie metody clean przy każdym wywołaniu funkcji save () dla wszystkich modeli.
źródło
Mieszasz cały stos, w grę wchodzi kilka warstw:
Model Django definiuje strukturę danych.
Formularz Django to skrót do definiowania formularzy HTML, sprawdzania poprawności pól i tłumaczenia wartości w języku Python / HTML. Nie jest to absolutnie potrzebne, ale często przydatne.
Django ModelForm to kolejny skrót, w skrócie podklasa Form, która pobiera swoje pola z definicji Modelu. Po prostu wygodny sposób na częsty przypadek, gdy formularz służy do wprowadzania danych do bazy danych.
i w końcu:
Niektórzy uważają to za herezję; ale ważne jest, aby pamiętać, że MVC zostało pierwotnie zdefiniowane dla aplikacji GUI i jest raczej niezręczne dla aplikacji internetowych.
źródło
Odpowiadam na to stare pytanie, ponieważ wydaje się, że w innych odpowiedziach nie ma wspomnianego konkretnego problemu.
Formularze Django umożliwiają łatwe pisanie małego kodu i tworzenie formularza z rozsądnymi ustawieniami domyślnymi. Każda modyfikacja bardzo szybko prowadzi do „więcej kodu” i „więcej pracy” i nieco niweluje podstawową korzyść systemu formularzy
Biblioteki szablonów, takie jak ulepszenia widgetów django, znacznie ułatwiają dostosowywanie formularzy. Mamy nadzieję, że takie modyfikacje w terenie będą łatwe dzięki instalacji waniliowej Django.
Twój przykład z django-widget-tweaks:
źródło
(Użyłem kursywy do oznaczenia koncepcji MVC, aby uczynić to bardziej czytelnym.)
Nie, moim zdaniem, nie łamią MVC. Pracując z modelami / formularzami Django, pomyśl o tym jako o użyciu całego stosu MVC jako modelu :
django.db.models.Model
jest modelem podstawowym (zawiera dane i logikę biznesową).django.forms.ModelForm
zapewnia kontroler do interakcjidjango.db.models.Model
.django.forms.Form
(pod warunkiem dziedziczenia przezdjango.forms.ModelForm
) to widok, z którym wchodzisz w interakcje.ModelForm
jest toForm
, więc dwie warstwy są ściśle ze sobą powiązane. Moim zdaniem zostało to zrobione ze względu na zwięzłość naszego kodu i ponowne użycie kodu w kodzie programisty Django.W ten sposób
django.forms.ModelForm
(wraz z logiką danych i biznesu) staje się samym modelem . Można go nazwać VC (MVC), co jest dość powszechną implementacją w OOP.Weźmy na przykład
django.db.models.Model
klasę Django . Kiedy patrzymy nadjango.db.models.Model
obiekty, widzimy Model, mimo że jest to już pełna implementacja MVC. Zakładając, że MySQL jest bazą danych zaplecza:MySQLdb
to Model (warstwa przechowywania danych i logika biznesowa dotycząca interakcji z danymi / sprawdzania ich poprawności).django.db.models.query
jest kontrolerem (obsługuje dane wejściowe z widoku i tłumaczy je dla modelu ).django.db.models.Model
jest Widok (z czym użytkownik wchodzi w interakcje).Ta interakcja jest taka sama, jak twoi „programiści po stronie klienta” podczas pracy z
yourproject.forms.YourForm
(dziedziczeniem podjango.forms.ModelForm
) obiektami:django.db.models.Model
, musieliby wiedzieć, jak wchodzić w interakcjeyourproject.forms.YourForm
(ich Model ).MySQLdb
, twoi „programiści po stronie klienta” nie muszą nic wiedziećyourproject.models.YourModel
.źródło