41 votes

Django et fieldsets sur ModelForm

Je sais que vous pouvez spécifier des ensembles de champs dans Django pour les aides d'administration. Cependant, je ne trouve rien d'utile pour les ModelForms. Juste quelques correctifs que je ne peux pas utiliser. Est-ce que quelque chose m'échappe ? Existe-t-il un moyen de réaliser quelque chose comme des fieldsets sans écrire manuellement chaque champ de mon modèle dans la balise appropriée.

Dans l'idéal, je voudrais itérer dans un ensemble de BoundFields. Cependant, en faisant quelque chose comme ceci à la fin de mon ModelForm :

    fieldsets = []
    fieldsets.append(('Personal Information',
                      [username,password,password2,first_name,last_name,email]),) # add a 2 element tuple of string and list of fields
    fieldsets.append(('Terms & Conditions',
                      [acceptterms,acceptprivacy]),) # add a 2 element tuple of string and list of fields

ne fonctionne pas car les éléments contenus dans ma structure de données sont les champs bruts, pas les BoundFields. Il semble que les BoundFields soient générés à la volée... cela me rend triste. Pourrais-je créer ma propre sous-classe de forms.Form qui contienne un concept de fieldsets (même approximatif et non rétrocompatible... c'est juste pour mon propre projet) et si oui, pouvez-vous me donner des indications ? Je ne veux pas toucher au code de Django.

52voto

Carl Meyer Points 30736

Je pense cet extrait fait exactement ce que vous voulez. Il vous donne une sous-classe de formulaire qui vous permet de subdiviser de manière déclarative votre formulaire en ensembles de champs et de les parcourir dans votre modèle.

Mise à jour : cet extrait a depuis été intégré dans le site Web de la Commission européenne. django-form-utils

0 votes

Excellent, il va être intégré à mon projet actuel !

0 votes

Merci pour django-form-utils ! Cela fonctionne comme un charme.

0 votes

J'utilise également form-utils, et j'ai également écrit une extension pour form-utils qui permet aux champs d'être disposés en rangées dans le fieldset... tout comme admin. J'ai l'intention de contacter l'auteur de form-utils pour voir s'il l'acceptera comme patch. En attendant, si vous le souhaitez, demandez-lui...

36voto

Van Gale Points 21982

Les jeux de champs dans les formulaires modulaires sont encore au stade de la "conception". Il y a un billet dans le trac de Django avec une faible activité.

C'est un sujet sur lequel j'aimerais faire des recherches dans un avenir proche, mais comme je ne l'ai pas encore fait, le mieux que je puisse offrir, ce sont ces bribes :

Edit : Je viens de remarquer cette question à nouveau et je me rends compte qu'il faut la modifier pour signaler le projet de Carl. django-form-utils qui contient une classe BetterForm pouvant contenir des fieldsets. Si vous aimez ce projet, donnez-lui un +1 pour sa réponse ci-dessous :)

1 votes

Le deuxième lien m'a donné l'indice dont j'avais besoin pour mettre en œuvre mon support rudimentaire des champs. Merci.

1 votes

Nov. 2010, j'ai utilisé django-form-utils avec succès avec la version 1.2.3. Merci pour l'astuce.

16voto

Joe Holloway Points 11122

Vous pouvez notamment répartir vos ensembles de champs logiques dans des classes de formulaires de modèle distinctes.

class PersonalInfoForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('field1', 'field2', ...)

class TermsForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('fieldX', 'fieldY', ...)

Passez-les à votre modèle dans différentes variables et séparez les jeux de formulaires :

<form ...>
   <fieldset><legend>Personal Information</legend>
       {{ personal_info_form }}
   </fieldset>
   <fieldset><legend>Terms and Conditions</legend>
       {{ terms_form }}
   </fieldset>
</form>

Dans ce sens, chacune de vos classes de formulaire n'est qu'un fragment du formulaire HTML réel.

Cela introduit une touche de complexité lorsque vous appelez save sur le formulaire. Vous voudrez probablement passer commit=False et ensuite fusionner les objets résultants. Ou alors, évitez tout simplement d'utiliser ModelForm.save et remplissez votre objet modèle à la main avec 'cleaned_data'.

1 votes

C'est beaucoup trop d'efforts, surtout dans la couche de visualisation.

5 votes

@Greg, Le downvote ne me dérange pas, mais votre commentaire est confus. Qu'entendez-vous par trop d'efforts ? Casser un formulaire monolithique en fragments de formulaire distincts que vous pouvez manipuler indépendamment les uns des autres est une approche idiomatique de ce problème. Django a peut-être ajouté plus d'utilitaires "fieldset" au cours des deux années qui se sont écoulées depuis que j'ai fourni cette réponse, mais l'approche reste néanmoins valable.

1 votes

Le point de vue de Greg est terriblement invalide Cette option est applicable et flexible. La seule fois où elle n'a pas fonctionné, c'est lorsque, dans la méthode "propre", certaines données de deux ou plusieurs ensembles de champs de formulaires sont nécessaires !

4voto

oivvio Points 1001

Daniel Greenfelds django-uni-form résout ce problème avec la classe d'aide Layout. Je suis en train de l'essayer et cela me semble assez propre.

Les aides uniformes peuvent utiliser des objets de mise en page. Une mise en page peut être constituée de jeux de champs, de lignes, de colonnes, de HTML et de champs. .

J'ai choisi à l'origine Django-uni-form parce qu'il est conforme aux normes de l'UE. article 508 .

3voto

Vous pouvez utiliser ce paquet : https://pypi.org/project/django-forms-fieldset/

pip install django-forms-fieldset

Ajoutez forms_fieldset à votre paramètre INSTALLED_APPS comme ceci :

INSTALLED_APPS = [
    ...
    'forms_fieldset',
]

Ajouter fieldsets dans votre formulaire

from django.forms import ModelForm

from .models import Student

class StudentForm(ModelForm):
    fieldsets = [
        ("Student Information", {'fields': [
            ('first_name', 'last_name'),
            ('email', 'adress'),
        ]}),
        ("Parent Information", {'fields': [
            'mother_name',
            'father_name',
        ]}),
    ]
    class Meta:
        model = Student
        fields = '__all__'

Dans vos vues

def home(request):
    form = StudentForm()
    if request.method == 'POST':
        form = Form(request.POST, request.FILES)
        #save...
    context = {
        'form': form,
    }
    return render(request, 'home.html', context)

dans votre modèle

{% load forms_fieldset static %}
<link rel="stylesheet" type="text/css" href="{% static 'forms_fieldset/css/main.css' %}">

<form>
    {{ form|fieldset:'#42945c' }}
</form>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X