Wie mache ich in einem Django-Formular ein Feld schreibgeschützt (oder deaktiviert)?
Wenn das Formular zum Erstellen eines neuen Eintrags verwendet wird, sollten alle Felder aktiviert sein. Wenn sich der Datensatz jedoch im Aktualisierungsmodus befindet, müssen einige Felder schreibgeschützt sein.
Wenn Sie beispielsweise ein neues Item
Modell erstellen , müssen alle Felder bearbeitet werden können. Gibt es jedoch beim Aktualisieren des Datensatzes eine Möglichkeit, das sku
Feld so zu deaktivieren , dass es sichtbar ist, aber nicht bearbeitet werden kann?
class Item(models.Model):
sku = models.CharField(max_length=50)
description = models.CharField(max_length=200)
added_by = models.ForeignKey(User)
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ('added_by')
def new_item_view(request):
if request.method == 'POST':
form = ItemForm(request.POST)
# Validate and save
else:
form = ItemForm()
# Render the view
Kann der Unterricht ItemForm
wiederverwendet werden? Welche Änderungen wären in der ItemForm
oder Item
Modellklasse erforderlich ? Muss ich eine weitere Klasse " ItemUpdateForm
" schreiben , um das Element zu aktualisieren?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
Antworten:
Wie in dieser Antwort ausgeführt , hat Django 1.9 das Attribut Field.disabled hinzugefügt :
Mit Django 1.8 und früheren Versionen müssen Sie zusätzlich zum Festlegen des
readonly
Attributs im Formularfeld die Eingabe bereinigen, um den Eintrag im Widget zu deaktivieren und böswillige POST-Hacks zu verhindern :Oder ersetzen Sie sie
if instance and instance.pk
durch eine andere Bedingung, die angibt, dass Sie bearbeiten. Sie können das Attribut auchdisabled
im Eingabefeld anstelle von festlegenreadonly
.Die
clean_sku
Funktion stellt sicher, dass derreadonly
Wert nicht von a überschrieben wirdPOST
.Andernfalls gibt es kein integriertes Django-Formularfeld, das einen Wert rendert, während gebundene Eingabedaten zurückgewiesen werden. Wenn Sie dies wünschen, sollten Sie stattdessen ein separates
ModelForm
Feld erstellen , das die nicht bearbeitbaren Felder ausschließt, und sie einfach in Ihre Vorlage drucken.quelle
clean_description
der Formularklasse eine Methode hinzu.disabled
Django 1.9 wird ein neues Feldargument hinzugefügt. Wenn auf gesetztField.disabled
istTrue
, wird der POST-Wert dafürField
ignoriert. Wenn Sie also 1.9 verwenden, müssen Sie nicht überschreibenclean
, sondern nur festlegendisabled = True
. Überprüfen Sie diese Antwort.Django 1.9 hat das Attribut Field.disabled hinzugefügt: https://docs.djangoproject.com/de/stable/ref/forms/fields/#disabled
quelle
disabled=True
wird das Modell mit Validierungsfehlern an den Benutzer zurückgespuckt.Durch die Einstellung
readonly
in einem Widget wird die Eingabe im Browser nur schreibgeschützt. Durch Hinzufügen einerclean_sku
Rückgabe wirdinstance.sku
sichergestellt, dass sich der Feldwert auf Formularebene nicht ändert.Auf diese Weise können Sie Modelle (unverändertes Speichern) verwenden und vermeiden, dass der Feldfehler angezeigt wird.
quelle
return self.cleaned_data['sku']
so gut oder besser? In den Dokumenten wird anscheinend Folgendes vorgeschlagencleaned_data
: "Der Rückgabewert dieser Methode ersetzt den vorhandenen Wert incleaned_data
. Es muss also der Wert des Felds voncleaned_data
(auch wenn diese Methode ihn nicht geändert hat) oder ein neuer bereinigter Wert sein."Antwort des Walkers hat mir sehr geholfen!
Ich habe sein Beispiel geändert, um mit Django 1.3 unter Verwendung von get_readonly_fields zu arbeiten .
Normalerweise sollten Sie so etwas deklarieren in
app/admin.py
:Ich habe mich folgendermaßen angepasst:
Und es funktioniert gut. Wenn Sie nun ein Element hinzufügen, ist das
url
Feld schreibgeschützt, bei Änderung jedoch schreibgeschützt.quelle
Damit dies für ein
ForeignKey
Feld funktioniert , müssen einige Änderungen vorgenommen werden. Erstens hat dasSELECT HTML
Tag nicht das Attribut readonly. Wir müssen verwendendisabled="disabled"
stattdessen verwenden. Dann sendet der Browser jedoch keine Formulardaten für dieses Feld zurück. Daher müssen wir festlegen, dass dieses Feld nicht erforderlich ist, damit das Feld korrekt validiert wird. Wir müssen dann den Wert auf den ursprünglichen Wert zurücksetzen, damit er nicht leer bleibt.Für Fremdschlüssel müssen Sie also Folgendes tun:
Auf diese Weise lässt der Browser den Benutzer das Feld nicht ändern und lässt es immer so,
POST
wie es leer gelassen wurde. Anschließend überschreiben wir dieclean
Methode, um den Wert des Felds auf den ursprünglichen Wert in der Instanz festzulegen.quelle
TabularInline
, bin jedoch fehlgeschlagen, daattrs
es zwischenwidget
Instanzen und allen außer der ersten Zeile, einschließlich der neu hinzugefügten, schreibgeschützt gerendert wurde.Für Django 1.2+ können Sie das Feld folgendermaßen überschreiben:
quelle
Field
disabled
macht nicht was ich will, weil es das Feld deaktiviert, sondern auch Beschriftung entfernt / unsichtbar macht.Ich habe eine MixIn-Klasse erstellt, die Sie möglicherweise erben, um ein iterierbares Feld read_only hinzufügen zu können, das Felder bei der nicht ersten Bearbeitung deaktiviert und sichert:
(Basierend auf Daniels und Muhuks Antworten)
quelle
Ich habe gerade das einfachste Widget für ein schreibgeschütztes Feld erstellt. Ich verstehe nicht wirklich, warum Formulare dies noch nicht haben:
In der Form:
Sehr einfach - und bringt mich nur zur Ausgabe. Praktisch in einem Formset mit einer Reihe von schreibgeschützten Werten. Natürlich - Sie könnten auch ein bisschen schlauer sein und es mit den attrs teilen, damit Sie Klassen daran anhängen können.
quelle
unicode(value)
das stattdessen vielleicht in der Rückgabe. Angenommen, der Unicode-Dunder ist sinnvoll, dann würden Sie das bekommen.Ich bin auf ein ähnliches Problem gestoßen. Es sieht so aus, als ob ich es lösen konnte, indem ich eine "get_readonly_fields" -Methode in meiner ModelAdmin-Klasse definierte.
Etwas wie das:
Das Schöne ist das
obj
beim Hinzufügen eines neuen Elements "Keine" oder beim Ändern eines vorhandenen Elements das Objekt bearbeitet wird.get_readonly_display ist hier dokumentiert: http://docs.djangoproject.com/de/1.2/ref/contrib/admin/#modeladmin-methods
quelle
Eine einfache Möglichkeit besteht darin, statt nur
form.instance.fieldName
die Vorlage einzugebenform.fieldName
.quelle
verbos_name
oderlabel
vom Feld? Wie kann ich `label in der Django-Vorlage anzeigen? @alzclarkeWie ich es mit Django 1.11 mache:
quelle
Als nützliche Ergänzung zu Humphreys Beitrag hatte ich einige Probleme mit der Django-Umkehrung, da deaktivierte Felder immer noch als "geändert" registriert wurden. Der folgende Code behebt das Problem.
quelle
Da ich noch keinen Kommentar abgeben kann ( Muhuks Lösung ), werde ich als separate Antwort antworten. Dies ist ein vollständiges Codebeispiel, das für mich funktioniert hat:
quelle
Ich werde noch einmal eine weitere Lösung anbieten :) Ich habe Humphreys Code verwendet , also basiert dies darauf.
Ich stieß jedoch auf Probleme mit dem Feld a
ModelChoiceField
. Alles würde bei der ersten Anfrage funktionieren. Wenn das Formularset jedoch versuchte, ein neues Element hinzuzufügen, und die Validierung fehlschlug, lief bei den "vorhandenen" Formularen, bei denen dieSELECTED
Option auf die Standardeinstellung zurückgesetzt wurde, ein Fehler---------
.Wie auch immer, ich konnte nicht herausfinden, wie ich das beheben konnte. Also habe ich stattdessen (und ich denke, das ist tatsächlich sauberer in der Form) die Felder gemacht
HiddenInputField()
. Dies bedeutet nur, dass Sie etwas mehr Arbeit in der Vorlage erledigen müssen.Die Lösung für mich bestand also darin, das Formular zu vereinfachen:
Und dann müssen Sie in der Vorlage eine manuelle Schleife des Formularsatzes durchführen .
In diesem Fall würden Sie also in der Vorlage Folgendes tun:
Dies funktionierte etwas besser für mich und mit weniger Formmanipulation.
quelle
Ich hatte das gleiche Problem und habe ein Mixin erstellt, das für meine Anwendungsfälle zu funktionieren scheint.
Verwendung, definieren Sie einfach, welche schreibgeschützt sein müssen:
quelle
'collections.OrderedDict' object has no attribute 'iteritems'
Wenn Sie mehrere schreibgeschützte Felder benötigen, können Sie eine der unten angegebenen Methoden verwenden
Methode 1
Methode 2
Vererbungsmethode
quelle
Zwei weitere (ähnliche) Ansätze mit einem verallgemeinerten Beispiel:
1) erster Ansatz - Entfernen des Feldes in der save () -Methode, z. B. (nicht getestet;)):
2) zweiter Ansatz - Feld in der sauberen Methode auf den Anfangswert zurücksetzen:
Basierend auf dem zweiten Ansatz habe ich es so verallgemeinert:
quelle
Für die Admin-Version ist dies meiner Meinung nach kompakter, wenn Sie mehr als ein Feld haben:
quelle
Basierend auf der Antwort von Yamikep habe ich eine bessere und sehr einfache Lösung gefunden, die auch
ModelMultipleChoiceField
Felder behandelt.Das Entfernen von
form.cleaned_data
Feldern aus verhindert, dass Felder gespeichert werden:Verwendungszweck:
quelle
Hier ist eine etwas kompliziertere Version, die auf der Antwort von christophe31 basiert . Es ist nicht auf das Attribut "readonly" angewiesen. Dies führt dazu, dass die Probleme, z. B. dass Auswahlfelder immer noch veränderbar sind und Daten-Picker immer noch auftauchen, verschwinden.
Stattdessen wird das Widget für Formularfelder in ein schreibgeschütztes Widget eingeschlossen, sodass das Formular weiterhin gültig ist. Der Inhalt des ursprünglichen Widgets wird in
<span class="hidden"></span>
Tags angezeigt . Wenn das Widget einerender_readonly()
Methode hat, verwendet es diese als sichtbaren Text, andernfalls analysiert es den HTML-Code des ursprünglichen Widgets und versucht, die beste Darstellung zu erraten.quelle
Ist das der einfachste Weg?
Genau in einem Ansichtscode wie folgt:
Es funktioniert gut!
quelle
Für Django 1.9+
Sie können das Argument Felder deaktiviert verwenden, um das Feld zu deaktivieren. Beispiel: Im folgenden Codeausschnitt aus der Datei forms.py habe ich das Feld employee_code deaktiviert
Referenz https://docs.djangoproject.com/de/2.0/ref/forms/fields/#disabled
quelle
Wenn Sie mit
Django ver < 1.9
(das Attribut1.9
hat hinzugefügtField.disabled
) arbeiten, können Sie versuchen, Ihrer Formularmethode den folgenden Dekorator hinzuzufügen__init__
:Die Hauptidee ist, dass
readonly
Sie , wenn Feld ist , keinen anderen Wert benötigen alsinitial
.PS: Vergiss nicht einzustellen
yuor_form_field.widget.attrs['readonly'] = True
quelle
Wenn Sie Django admin verwenden, ist hier die einfachste Lösung.
quelle
Ich denke, Ihre beste Option wäre nur, das schreibgeschützte Attribut in Ihre Vorlage aufzunehmen, die in einem
<span>
oder gerendert ist,<p>
anstatt es in das Formular aufzunehmen, wenn es schreibgeschützt ist.Formulare dienen zum Sammeln und nicht zum Anzeigen von Daten. Abgesehen davon sind die Optionen zum Anzeigen in einem
readonly
Widget und zum Bereinigen von POST-Daten gute Lösungen.quelle