[PYTHON] Ajouter dynamiquement des champs aux objets Form avec Django

J'ai essayé le contenu écrit en marge de Spécification dynamique de l'ensemble de requêtes de ModelChoiceField dans Django, donc mémo mémo.

Derniers devoirs

En jouant avec Form.fields, vous pouvez modifier divers attributs d'autres champs après la création du formulaire. Est-il possible d'ajouter / supprimer le champ lui-même?

Je l'ai vraiment essayé

Lancez la commande shell de Django et essayez-la sur un shell interactif

Créer un objet Form vide

>>> from django import forms
>>> f = forms.Form()
>>> f.as_p()
''
>>> f.fields
OrderedDict()

Aucun champ n'est défini à ce stade, donc appeler ʻas_p () ne rend rien Form.fields n'affiche que les objets ʻOrderdDict vides

… Pour la première fois, nous savons que le type de Form.fields est une classe appelée OrderedDict.

Ajouter des champs à Form.fields

>>> f.fields['name'] = forms.CharField(label='Nom')
>>> f.as_p()
'<p><label for="id_name">Nom:</label> <input id="id_name" name="name" type="text" /></p>'

>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B388>)])

Ajoutez «CharField» avec la clé «nom». Correctement rendu avec ʻas_p () `. Le contenu de «Form.fields» contient également l'objet de «CharField» avec la clé «nom».

Appel de ʻis_valid () et vérification des erreurs, nettoyées_données`

>>> f.is_valid()
Flase

>>> f.errors
{}

>>> f.cleaned_data
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Form' object has no attribute 'cleaned_data'

Puisque le champ de nom ajouté est required = True (valeur par défaut), on s'attend à ce que ʻis_valid ()soit False, mais pour une raison quelconqueForm.errors` est vide.

Quand je l'ai recherché, si l'objet Form n'avait pas changé la valeur de chaque champ, ou n'avait pas reçu de données dans son argument, il créerait simplement une ʻerreurs vide et gérer full_clean (). Il semble se terminer (cleaning_data` n'est pas généré non plus).

Il n'y a aucune aide pour cela, alors passez l'argument data à l'objet Form et régénérez-le. Je vais essayer.

>>> f = forms.Form(data={})
>>> f.fields['name'] = forms.CharField(label='Nom')
>>> f.is_valid()
False

>>> f.errors
{'name': ['This field is required.']}

>>> f.cleaned_data
{}

Comme prévu, le contenu de «erreurs» contenait une erreur de vérification obligatoire pour «nom». Un dict vide est également généré pour clean_data.

Détour: Comportement de ʻis_valid () et ʻerrors

Au début, j'ai essayé d'assigner directement un dict vide à Form.data pour résoudre le problème de ↑, mais le résultat n'a pas changé. Quand j'ai suivi la source de django, c'était à cause du traitement suivant au début de __init __ () de la classe BaseForm, qui est le parent de la classe Form.

forms.py


        self.is_bound = data is not None or files is not None

Donc, l'implémentation de ʻis_valid` est seulement une ligne ci-dessous

forms.py


    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
        return self.is_bound and not bool(self.errors)

De plus, les erreurs sont définies comme des méthodes avec des décorateurs de propriété plutôt que comme des champs.

forms.py


    @property
    def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

Ainsi, il ne suffisait pas d'éditer directement les «données», et les deux processus suivants étaient nécessaires.

Eh bien, si vous pensez l'utiliser comme une application Web normale, vous ne devriez pas avoir à changer les paramètres et à refaire la validation en traitant une requête ... Il est naturel que la validation (appel de full_clean ()) ne soit pas exécutée à chaque fois que ʻis_valid () ou ʻerrors est accédé, mais seulement la première fois.

Modifiez data pour que la validation soit True

>>> f.data = {'name':'hoge'}
>>> f.full_clean()
>>> f.is_valid()
True

>>> f.errors
{}

>>> f.cleaned_data
{'name':'hoge'}

Essayez d'ajouter plus de champs

>>> f.fields['date'] = forms.DateField(label='Date',required=False)

>>> f.as_p()
'<ul class="errorlist"><li>This field is required.</li></ul>\n<p><label for="id_name">Nom:</label> <input id="id_name" name="name" type="text" /></p>\n<p><label for="id_date">Date:</label> <input id="id_date" name="date" type="text" /></p>'

>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B38>), ('date', <django.forms.fields.DateField object at 0x0000000002A3C828>)])

>>> f.full_clean()
>>> f.is_valid()
True

>>> f.errors
{}

>>> f.cleaned_data
{'date':None, 'name':'hoge'}

>>> f.data['date'] = '2014-12-04'
>>> f.full_clean()
>>> f.is_valid()
True

>>> f.errors
{}

>>> f.cleaned_data
{'date':datetime.date(2014, 12, 4), 'name':'hoge'}

Supprimer les champs de Form.fields

>>> f.fields.popitem()
('date', <django.forms.fields.DateField object at 0x0000000002A3C828>)

>>> f.as_p()
'<p><label for="id_name">Nom:</label> <input id="id_name" name="name" type="text" value="hoge" /></p>'

>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B38>)])

>>> f.full_clean()
>>> f.cleaned_data
{'name': 'hoge'}

>>> f.data
{'date': '2014-12-04', 'name': 'hoge'}

Form.fields supprime l'élément avec ʻOrderedDict.popitem. LIFO si l'argument last` est True (par défaut), LILO si False. Cette fois, c'est vrai, donc le champ de date que j'ai ajouté plus tard a été supprimé.

Résumé

… Ainsi, l'objet Form de Django peut être ajouté / supprimé ultérieurement dans le champ lui-même. Je pense qu'il peut répondre à des demandes telles que "Vous permettre d'ajouter librement des éléments d'entrée d'écran dans les paramètres principaux!"

Recommended Posts

Ajouter dynamiquement des champs aux objets Form avec Django
Ajouter dynamiquement des champs de formulaire dans Django
Comment obtenir plusieurs objets de modèle au hasard dans Django
Définissez DateField du formulaire sur type = date dans Django
Implémentation de boutons d'ajout de formulaire dans Django Inline Form Set Part2
Implémenter un bouton d'ajout de formulaire dans l'ensemble de formulaires en ligne Django
[Django] Comment tester le formulaire [TDD]
Définir des espaces réservés dans les champs de saisie dans Django
Ajouter des champs à des entités avec ArcPy
Erreur liée à memcached dans django
Comment refléter CSS dans Django
6 façons d'enchaîner des objets en Python
Comment définir dynamiquement des variables en Python
Comment supprimer des sessions expirées dans Django
Connaissances minimales pour utiliser Form avec Flask
Dans Jupyter, ajoutez IPerl au noyau.
Spécifiez dynamiquement le jeu de requêtes ModelChoiceField dans Django
Comment remplir dynamiquement des zéros avec Python
Comment faire des événements envoyés par le serveur dans Django
[Django memo] Je souhaite définir à l'avance les informations de l'utilisateur connecté dans le formulaire.
Autoriser l'utilisation de HTML5 <input type = "date / time"> dans le formulaire DatetimeField dans Django
Comment ajouter un traitement de pré-sauvegarde lors de l'ajout d'un objet sur le site d'administration de Django
Essayez d'utiliser django-import-export pour ajouter des données csv à django
Comment implémenter la fonctionnalité de type helper Rails dans Django
Je veux corriger Datetime.now dans le test de Django
Enregistrez plusieurs modèles sous un seul formulaire avec Django
Comment refléter ImageField dans Django + Docker (oreiller)
Pour remplacer dynamiquement la méthode suivante en python
Pour ajouter un module à python que vous mettez dans Julialang
Passer les informations de connexion à afficher dans Django
Comment créer une API Rest dans Django
Ajouter une fonctionnalité pour modifier les informations de quart de jour Django
Ajouter des totaux aux lignes et aux colonnes avec des pandas
Formulaire de demande Django 2
Modèle dans Django
Formulaire suggéré par Django
Je souhaite envoyer un message d'erreur en japonais avec le formulaire de changement de mot de passe django
Ramasser les oreilles tombées de Django Form
Formulaire à Django
Formulaire de contact Django
[Python] [Django] Comment utiliser le champ de choix et comment ajouter des options
Ajouter un complément automatique à la programmation EV3 Micropyhon dans VS Code
Implémenter un formulaire de courrier supplémentaire dans une application Web sans serveur ~ Version backend ~
Comment utiliser le bootstrap dans la vue de classe générique Django
TemplateView les modèles que vous souhaitez apprendre en premier dans Django
Préparation au contrôle des objets rhino avec des scripts dans Grasshopper / Python
Comment ajouter des numéros de page à un fichier PDF (en Python)
Django / Objets associés (ajouter, créer, supprimer, effacer, définir) Résumé
Créez dynamiquement des tables dans un schéma avec Django, générez dynamiquement des modèles
Comment télécharger des fichiers dans la vue de classe générique Django
Comment utiliser Decorator dans Django et comment le créer
Comment ajouter une barre de couleur dans le graphique à barres de matplotlib
Comment référencer des fichiers statiques dans un projet Django
[Django] Une histoire sur le fait de rester coincé dans un marais en essayant de valider un zip avec un formulaire [TDD]