Dans un Django formulaire, comment faire un champ en lecture seule (ou désactivé), de sorte qu'il ne peut pas être modifié?
Dans un Django formulaire, comment faire un champ en lecture seule (ou désactivé)?
Lorsque le formulaire est utilisé pour créer une nouvelle entrée, tous les champs doivent être activés - mais lorsque l'enregistrement est en mode de mise à jour de certains champs doivent être en lecture seule.
Par exemple, lors de la création d'un nouveau Item
modèle, tous les champs doivent être modifiable, mais alors que la mise à jour de l'enregistrement, est-il un moyen de désactiver la sku
champ de sorte qu'il est visible, mais ne peut pas être modifié?
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
Peut classe ItemForm
- il être réutilisé? Quels changements seraient nécessaires dans le ItemForm
ou Item
modèle de classe? J'ai besoin d'écrire une autre classe, "ItemUpdateForm
", pour la mise à jour de l'article?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
- Voir aussi la question: Pourquoi sont en lecture seule pour les champs de formulaire dans Django une mauvaise idée? @ stackoverflow.com/questions/2902024 , a Accepté de répondre (par Daniel Naab) prend soin de malveillant POST hacks.
Vous devez vous connecter pour publier un commentaire.
Comme l'a souligné dans cette réponse, Django 1.9 ajouté le Champ.désactivé attribut:
Avec Django 1,8 et plus tôt, pour désactiver l'entrée sur le widget et empêcher les POST hacks vous devez frotter l'entrée en plus du réglage de la
readonly
attribut sur le champ de formulaire:Ou encore, remplacer
if instance and instance.pk
avec un autre état indiquant que vous modifiez. Vous pouvez également définir l'attributdisabled
sur le champ de saisie, au lieu dereadonly
.La
clean_sku
fonction de s'assurer que lesreadonly
valeur ne sera pas remplacée par unePOST
.Sinon, il n'est pas intégré dans Django champ de formulaire permettant de rendre une valeur tout en rejetant tenu des données d'entrée. Si c'est ce que vous désirez, vous devez créer un
ModelForm
qui exclut du champ non modifiable(s), et de les imprimer à l'intérieur de votre modèle.instance.id
àinstance.pk
signifie qu'il devrait fonctionner si vous avez défini une non-valeur par défaut de la clé primaire. J'ai un code qui utilise unname
attribut afinid
n'existe pas.clean_description
méthode de la classe de formulaire.disabled
est ajouté dans Django 1.9. SiField.disabled
est fixé àTrue
, puis ajouter de la valeur pour queField
est ignoré. Ainsi, si vous utilisez 1.9, il n'y a pas besoin de surchargerclean
, il suffit de définirdisabled = True
. Vérifier ceci la réponse.clean_<field>
fonctions ? Quelle est la meilleure méthode possible dans ce cas ?Django 1.9 ajouté le Champ.désactivé attribut: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled
disabled=True
va provoquer le modèle de naissain à l'utilisateur avec des erreurs de validation.Paramètre EN lecture seule sur le widget ne fait que l'entrée dans le navigateur en lecture seule. L'ajout d'un clean_sku qui retourne l'instance.sku garantit la valeur du champ ne changera pas sur le niveau de forme.
De cette façon, vous pouvez utiliser du modèle (non modifié enregistrer) et d'éviter d'obtenir le champ requis erreur.
awalker réponse m'a beaucoup aidé!
J'ai changé son exemple fonctionne avec Django 1.3, en utilisant get_readonly_fields.
Vous devez déclarer quelque chose comme cela dans
app/admin.py
:J'ai adapté de cette façon:
Et il fonctionne très bien. Maintenant, si vous ajoutez un Élément, le
url
champ est en lecture-écriture, mais sur le changement, il devient en lecture seule.À faire ce travail pour un
ForeignKey
champ, quelques modifications doivent être apportées. Tout d'abord, laSELECT HTML
balise n'a pas l'attribut lecture seule. Nous avons besoin d'utiliserdisabled="disabled"
à la place. Cependant, le navigateur de ne pas envoyer les données du formulaire de retour pour ce champ. Nous avons donc besoin de définir la matière, afin de ne pas être requis afin que le champ valide correctement. Ensuite, il est nécessaire de réinitialiser la valeur à ce qu'il utilisé pour être si ce n'est pas définie à blanc.Donc pour les clés étrangères, vous aurez besoin de faire quelque chose comme:
De cette façon, le navigateur ne va pas permettre à l'utilisateur de modifier le champ, et sera toujours
POST
comme il avait été laissé en blanc. Nous avons ensuite remplacer leclean
méthode pour définir la valeur du champ à ce qui a été à l'origine de l'instance.TabularInline
, mais a échoué carattrs
ont été partagés entrewidget
les instances et toutes les mais la première ligne, y compris les nouveaux, rendus en lecture seule.Pour Django 1.2+, vous pouvez remplacer le champ de la sorte:
Field
disabled
ne pas faire ce que je veux car elle désactive le terrain, mais aussi supprime l'étiquette ou de la rendre invisible.J'ai fait une classe MixIn qui vous pouvez hériter d'être en mesure d'ajouter un read_only itérable champ de désactiver et de sécuriser les champs sur la non-première édition:
(Basé sur Daniel et Muhuk réponses)
Je viens de créer le plus simple possible widget pour un champ en lecture seule - je ne vois vraiment pas pourquoi les formes ne l'avez pas déjà:
Sous la forme:
Très simple et me met juste à la sortie. Pratique dans un formset avec un tas de lire uniquement des valeurs.
Bien sûr, vous pourriez aussi être un peu plus intelligent et de lui donner un div avec la attrs de sorte que vous pouvez ajouter des classes à elle.
unicode(value)
dans le retour au lieu de cela, peut-être. En supposant que l'unicode dsous est sensible, vous pouvez l'obtenir.J'ai couru à travers un problème similaire.
Il semble que j'ai été en mesure de le résoudre par la définition d'un "get_readonly_fields" de la méthode dans mon ModelAdmin classe.
Quelque chose comme ceci:
La bonne chose est que
obj
sera nul lors de l'ajout d'un nouvel Élément, ou ce sera l'objet en cours de modification lorsque vous êtes à la modification d'un Élément existant.get_readonly_display est documenté ici:
http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods
Une option simple est de type
form.instance.fieldName
dans le modèle, à la place deform.fieldName
.verbos_name
oulabel
de champ? Comment puis-je montrer le label dans django template ? @alzclarkeComme un complément utile à Humphrey post, j'ai eu quelques problèmes avec django-retour, car il lui reste encore inscrit désactivé champs comme "changé". Le code suivant résout le problème.
Que je ne peux pas encore de commentaires (muhuk de la solution), je vais la réponse comme une réponse distincte. C'est un exemple de code, qui a fonctionné pour moi:
J'allais dans le même problème j'ai donc créé un Mixin qui semble fonctionner pour mon cas d'utilisation.
D'utilisation, il suffit de définir ceux qui doivent être en lecture seule:
'collections.OrderedDict' object has no attribute 'iteritems'
Encore une fois, je vais vous offrir la solution 🙂 j'ai été en utilisant Humphrey code, donc c'est basé sur de que.
Cependant, j'ai couru dans des problèmes avec le champ étant un ModelChoiceField. Tout fonctionne sur la première demande. Toutefois, si le formset essayé d'ajouter un nouvel élément et l'échec de la validation, quelque chose allait mal avec les "existants" formes où l'option CHOISIE a été remis à la valeur par défaut "---------".
De toute façon, je ne pouvais pas comprendre comment résoudre ce problème. Donc, au lieu de cela, (et je pense que c'est effectivement plus propre dans la forme), j'ai fait les champs HiddenInputField(). Cela signifie simplement que vous avez à faire un peu plus de travail dans le modèle.
Ainsi, le correctif pour moi a été de simplifier le Formulaire:
Et ensuite dans le modèle, vous aurez besoin de faire quelques manuel de mise en boucle de l'formset.
Donc, dans ce cas il faudrait faire quelque chose comme cela dans le modèle:
Cela fonctionnait un peu mieux pour moi et avec le moins de manipulation de formulaire.
Comment je le fais avec Django 1.11 :
Deux de plus (même) les approches avec un exemple général:
1) première approche - retrait de champ dans la méthode save (), par exemple (non testé 😉 ):
2) deuxième méthode de réinitialisation du champ à la valeur initiale en propre méthode:
Basée sur la deuxième approche que j'ai généralisé comme ceci:
si votre besoin de plusieurs champs en lecture seule.vous pouvez utiliser l'une des méthodes indiquées ci-dessous
méthode 1
méthode 2
héritage méthode
Pour l'Administrateur version, je pense que c'est une façon plus compacte si vous avez plus d'un domaine:
Basé sur Yamikep réponse, j'ai trouvé mieux et solution très simple, qui gère également les
ModelMultipleChoiceField
champs.Retrait de champ à partir de
form.cleaned_data
empêche les champs de sauvegarde:Utilisation:
Ici est un peu plus impliqué version, basée sur christophe31 réponse. Il ne repose pas sur la "readonly" attribut. Cela fait de ses problèmes, comme des listes de sélection étant toujours changeant et datapickers encore d'apparaître, de disparaître.
Au lieu de cela, elle enveloppe les champs du formulaire widget dans une readonly widget, ce qui rend la forme qui reste à valider. Le contenu de l'original widget est affiché à l'intérieur de
<span class="hidden"></span>
balises. Si le widget a unrender_readonly()
méthode qu'il utilise pour le texte visible, sinon il analyse le code HTML du widget d'origine et essaie de deviner la meilleure représentation.Est-ce la façon la plus simple?
Droit dans la vue de code à quelque chose comme ceci:
Il fonctionne très bien!
Pour django de 1,9+
Vous pouvez utiliser les Champs désactivé argument pour faire le terrain désactiver.
par exemple, Dans l'extrait de code suivant à partir de forms.py fichier , j'ai fait employee_code champ désactivé
De référence
https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled
Si vous travaillez avec
Django ver < 1.9
(le1.9
a ajoutéField.disabled
attribut), vous pourriez essayer d'ajouter après le décorateur à votre formulaire__init__
méthode:L'idée principale est que si le champ est
readonly
vous n'avez pas besoin de toute autre valeur, saufinitial
.P. S: N'oubliez pas de mettre
yuor_form_field.widget.attrs['readonly'] = True
Si vous utilisez Django admin, ici, c'est la solution la plus simple.
list_editable
ignorereadonly_fields
.Je pense que votre meilleure option serait d'inclure l'attribut lecture seule dans votre modèle rendu dans un
<span>
ou<p>
plutôt que de l'inclure dans le formulaire si c'est en lecture seule.Formes sont pour la collecte de données, pas de l'afficher. Cela étant dit, les options à afficher dans une
readonly
widget et gommage publier des données sont bien des solutions.J'ai résolu ce problème comme ceci:
vues:
C'est tout.