Ich habe gerade angefangen, mit Django zu arbeiten, der aus den Jahren von Spring MVC stammt, und die Implementierung der Formulare scheint etwas verrückt zu sein. Wenn Sie nicht vertraut sind, beginnt Django Forms mit einer Formularmodellklasse, die Ihre Felder definiert. Der Frühling beginnt in ähnlicher Weise mit einem Formträger. Wo Spring jedoch eine Taglib zum Binden von Formularelementen an das Hintergrundobjekt in Ihrer JSP bereitstellt , sind in Django Formular-Widgets direkt mit dem Modell verknüpft. Es gibt Standardwidgets, mit denen Sie Ihren Feldern Stilattribute hinzufügen können, um CSS anzuwenden, oder vollständig benutzerdefinierte Widgets als neue Klassen definieren können. Es geht alles in Ihrem Python-Code. Das kommt mir verrückt vor. Erstens fügen Sie Informationen zu Ihrer Ansicht direkt in Ihr Modell ein und zweitens binden Sie Ihr Modell an eine bestimmte Ansicht. Vermisse ich etwas?
EDIT: Ein Beispielcode wie gewünscht.
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'}))
Spring 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>
Antworten:
Ja, die Django-Formulare sind aus MVC-Sicht ein Durcheinander. Angenommen, Sie arbeiten in einem großen MMO-Superheld-Spiel und erstellen das Hero-Modell:
Nun werden Sie gebeten, ein Formular dafür zu erstellen, damit die MMO-Spieler ihre Helden-Superkräfte eingeben können:
Da der Shark Repellent eine sehr mächtige Waffe ist, hat Ihr Chef Sie gebeten, ihn einzuschränken. Wenn ein Held das Shark Repellent hat, kann er nicht fliegen. Die meisten Leute fügen diese Geschäftsregel einfach in das Formular clean ein und nennen es einen Tag:
Dieses Muster sieht cool aus und funktioniert möglicherweise bei kleinen Projekten, aber meiner Erfahrung nach ist es sehr schwierig, es bei großen Projekten mit mehreren Entwicklern beizubehalten. Das Problem ist, dass das Formular Teil der Ansicht der MVC ist. Sie müssen sich also jedes Mal an diese Geschäftsregel erinnern, wenn Sie:
Mein Punkt hier ist, dass die forms.py alles über das Formularlayout und die Präsentation ist. Sie sollten niemals Geschäftslogik in diese Datei einfügen, es sei denn, Sie genießen es, mit Spaghetti-Code herumzuspielen.
Der beste Weg, um das Heldenproblem zu lösen, ist die Verwendung der Model-Clean-Methode plus eines benutzerdefinierten Signals. Die Modellbereinigung funktioniert wie die Formularbereinigung, ist jedoch im Modell selbst gespeichert, und ruft bei jeder Bereinigung von HeroForm automatisch die Hero-Bereinigungsmethode auf. Dies ist eine gute Vorgehensweise, da ein anderer Entwickler, der ein anderes Formular für den Hero schreibt, die Repellent / Fly-Validierung kostenlos erhält.
Das Problem bei der Bereinigung ist, dass sie nur aufgerufen wird, wenn ein Modell von einem Formular geändert wird. Es wird nicht aufgerufen, wenn Sie es manuell speichern () und Sie können mit einem ungültigen Helden in Ihrer Datenbank enden. Um diesem Problem entgegenzuwirken, können Sie Ihrem Projekt diesen Listener hinzufügen:
Dadurch wird die Clean-Methode bei jedem Aufruf von save () für alle Ihre Modelle aufgerufen.
quelle
Sie mischen den gesamten Stapel, es sind mehrere Ebenen beteiligt:
Ein Django-Modell definiert die Datenstruktur.
Ein Django-Formular ist eine Verknüpfung zum Definieren von HTML-Formularen, Feldvalidierungen und Python / HTML-Wert-Übersetzungen. Es ist nicht unbedingt erforderlich, aber oft praktisch.
Eine Django ModelForm ist eine weitere Verknüpfung, kurz eine Form-Unterklasse, die ihre Felder aus einer Modelldefinition bezieht. Nur ein praktischer Weg für den allgemeinen Fall, dass ein Formular zum Eingeben von Daten in die Datenbank verwendet wird.
und schlussendlich:
Einige Leute sehen das als Ketzerei an; Es ist jedoch wichtig, sich daran zu erinnern, dass MVC ursprünglich für GUI-Anwendungen definiert wurde und für Webanwendungen eher umständlich ist.
quelle
Ich beantworte diese alte Frage, weil die anderen Antworten das erwähnte spezifische Problem zu vermeiden scheinen.
Mit Django-Formularen können Sie problemlos kleinen Code schreiben und ein Formular mit vernünftigen Standardeinstellungen erstellen. Jede Menge Anpassungen führen sehr schnell zu "mehr Code" und "mehr Arbeit" und machen den Hauptnutzen des Formularsystems etwas zunichte
Template-Bibliotheken wie Django-Widget-Tweaks erleichtern das Anpassen von Formularen erheblich. Hoffentlich sind solche Anpassungen vor Ort mit einer Vanille-Django-Installation ganz einfach.
Ihr Beispiel mit Django-Widget-Tweaks:
quelle
(Ich habe Kursivschrift verwendet , um die MVC-Konzepte zu kennzeichnen und die Lesbarkeit zu verbessern.)
Nein, meiner Meinung nach brechen sie MVC nicht. Wenn Sie mit Django Models / Forms arbeiten, stellen Sie sich vor, dass Sie einen gesamten MVC-Stapel als Modell verwenden :
django.db.models.Model
ist das Basismodell (die Daten und die Geschäftslogik hält).django.forms.ModelForm
Bietet einen Controller für die Interaktion mitdjango.db.models.Model
.django.forms.Form
(wie durch die Vererbung von bereitgestelltdjango.forms.ModelForm
) ist die Ansicht , mit der Sie interagieren.ModelForm
es sich um eine handeltForm
, so dass die beiden Schichten eng miteinander verbunden sind. Meiner Meinung nach wurde dies aus Gründen der Kürze in unserem Code und zur Wiederverwendung im Code der Django-Entwickler durchgeführt.Auf diese Weise wird
django.forms.ModelForm
(mit seinen Daten und seiner Geschäftslogik) selbst ein Modell . Sie könnten es als (MVC) VC bezeichnen, was in OOP eine ziemlich häufige Implementierung ist.Nehmen Sie zum Beispiel Djangos
django.db.models.Model
Klasse. Wenn wir uns diedjango.db.models.Model
Objekte ansehen , sehen wir Model , obwohl es bereits eine vollständige Implementierung von MVC ist. Angenommen, MySQL ist die Back-End-Datenbank:MySQLdb
ist das Modell (Datenspeicherschicht und Geschäftslogik in Bezug auf die Interaktion / Validierung der Daten).django.db.models.query
ist der Controller (verarbeitet Eingaben aus der Ansicht und übersetzt sie für das Modell ).django.db.models.Model
ist die Ansicht (mit der der Benutzer interagiert).Diese Interaktion ist dieselbe wie bei Ihren "clientseitigen Entwicklern", wenn Sie mit Objekten arbeiten
yourproject.forms.YourForm
(vondjango.forms.ModelForm
Objekten erben ):django.db.models.Model
ihnen umgeht, müssen sie wissen, wie man mityourproject.forms.YourForm
ihnen umgeht (ihr Modell ).MySQLdb
, müssen Ihre "clientseitigen Entwickler" nichts darüber wissenyourproject.models.YourModel
.quelle