184 votes

Stylisation CSS dans les formulaires Django

Je voudrais styliser les éléments suivants :

forms.py :

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

formulaire_contact.html :

<form action="" method="post">
  <table>
    {{ form.as_table }}
  </table>
  <input type="submit" value="Submit">
</form>

Par exemple, comment définir un classe ou ID pour le subject , email , message pour fournir une feuille de style externe à ?

248voto

shadfc Points 1275

Tiré de ma réponse à : Comment baliser les champs de formulaire avec <div class='field_type'> dans Django

class MyForm(forms.Form):
    myfield = forms.CharField(widget=forms.TextInput(attrs={'class': 'myfieldclass'}))

ou

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield'].widget.attrs.update({'class': 'myfieldclass'})

ou

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'myfield': forms.TextInput(attrs={'class': 'myfieldclass'}),
        }

--- EDIT ---
Ce qui précède est le changement le plus facile à faire au code de la question originale qui accomplit ce qui a été demandé. Cela vous évite également de vous répéter si vous réutilisez le formulaire à d'autres endroits ; vos classes ou autres attributs fonctionnent simplement si vous utilisez les méthodes de formulaire as_table/as_ul/as_p de Django. Si vous avez besoin d'un contrôle total pour un rendu complètement personnalisé, c'est la méthode clairement documenté

-- EDIT 2 ---
Ajout d'une nouvelle façon de spécifier le widget et les attrs pour un ModelForm.

35 votes

Cependant, il n'est pas recommandé de mélanger la présentation avec la logique d'entreprise.

9 votes

Comment cela se présente-t-il ? Vous donnez à l'élément une classe, qui n'est qu'un identifiant ou une catégorisation. Tu dois encore définir ce que ça fait ailleurs

9 votes

Oui et non. Tout d'abord, les classes CSS sont, par convention, utilisées pour le style. Si vous avez besoin d'un identifiant unique, il est préférable d'utiliser l'option id . Deuxièmement, c'est généralement la responsabilité du côté du modèle de faire exactement cela, surtout si vous allez accéder à cette classe via des méthodes frontales (js, css). Je n'ai pas dit que votre réponse était fausse. A mon avis, c'est juste une mauvaise pratique (surtout lorsque vous travaillez dans une équipe avec des développeurs front-end et back-end).

142voto

Charlesthk Points 361

Cela peut être fait en utilisant un filtre de modèle personnalisé. Pensez à rendre votre formulaire de cette façon :

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subject est une instance de BoundField qui a le as_widget() méthode.

Vous pouvez créer un filtre personnalisé addclass sur mon_app/templateetags/myfilters.py :

from django import template

register = template.Library()

@register.filter(name='addclass')
def addclass(value, arg):
    return value.as_widget(attrs={'class': arg})

Et ensuite appliquer votre filtre :

{% load myfilters %}

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject|addclass:'MyClass' }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjects sera ensuite rendu avec l'option MyClass Classe CSS.

9 votes

C'est l'une des solutions les plus propres et les plus faciles à mettre en œuvre.

6 votes

Cette réponse devrait être la première réponse ! !! Elle est vraiment plus propre que la solution proposée par Django ! Bien joué @Charlesthk

7 votes

Super utile. Ce n'était pas évident pour moi au début, mais vous pouvez aussi l'utiliser pour ajouter plusieurs classes : {{ form.subject|addclass:'myclass1 myclass2' }}

34voto

John C Points 2060

Si vous ne voulez pas ajouter tout code à la forme (comme mentionné dans les commentaires de la réponse de @shadfc), c'est certainement possible, voici deux options.

Tout d'abord, il suffit de référencer les champs individuellement dans le HTML, plutôt que le formulaire entier en une seule fois :

<form action="" method="post">
    <ul class="contactList">
        <li id="subject" class="contact">{{ form.subject }}</li>
        <li id="email" class="contact">{{ form.email }}</li>
        <li id="message" class="contact">{{ form.message }}</li>
    </ul>
    <input type="submit" value="Submit">
</form>

(Notez que je l'ai également transformé en un fichier non trié. liste .)

Deuxièmement, notez dans les docs sur sortie des formulaires au format HTML Django :

L'identifiant du champ est généré en en ajoutant "id_" au nom du champ. Les attributs et les balises id sont inclus dans la sortie par défaut.

Tous les champs de votre formulaire ont déjà un nom unique id . Ainsi, vous feriez référence id_sujet dans votre fichier CSS pour donner du style à l'élément sujet champ. Je dois noter que c'est ainsi que le formulaire se comporte lorsque vous prenez le champ par défaut HTML, ce qui nécessite d'imprimer uniquement le formulaire, et non les différents champs :

<ul class="contactList">
    {{ form }}  # Will auto-generate HTML with id_subject, id_email, email_message 
    {{ form.as_ul }} # might also work, haven't tested
</ul>

Voir le lien précédent pour d'autres options lors de la sortie de formulaires (vous pouvez faire des tableaux, etc.).

Note - Je réalise que ce n'est pas la même chose que d'ajouter un classe à chaque élément (si vous ajoutez un champ au formulaire, vous devez également mettre à jour la feuille de style en cascade), mais il est assez facile de faire référence à tous les champs à l'aide de la commande id dans votre CSS comme ceci :

#id_subject, #id_email, #email_message 
{color: red;}

0 votes

J'ai essayé votre deuxième solution mais cela n'a pas fonctionné. J'ai créé une classe pour l'id_email et cela n'a donné aucun résultat.

0 votes

@almostabeginner une chose que je peux suggérer pour le débogage - une fois que vous voyez la page dans un navigateur, utilisez Afficher la source de la page (généralement en faisant un clic droit), et regardez la page complète que Django génère. Voyez si les champs existent, avec la balise id ou classe que vous attendez. De plus, la plupart des navigateurs (éventuellement en installant un plugin) peuvent exécuter un débogueur qui vous montre l'identificateur css qui est appliqué à une page, également utile pour voir ce qui se passe.

0 votes

@almostabeginner notez aussi, j'ai ajouté un peu de code d'exemple. Au cas où le texte n'aurait pas été clair, vous devez faire référence au formulaire lui-même, et non à des champs individuels, auquel cas le formulaire génère automatiquement du HTML qui contient ids comme décrit. J'espère que cela vous aidera.

14voto

Ignas Butėnas Points 2174

Vous pouvez faire comme ça :

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    subject.widget.attrs.update({'id' : 'your_id'})

J'espère que ça marchera.

Ignas

0 votes

Merci Ignas. Une réponse précise !

10voto

Eamonn Faherty Points 54

Vous pourriez utiliser cette bibliothèque : https://pypi.python.org/pypi/django-widget-tweaks

Il vous permet de faire ce qui suit :

{% load widget_tweaks %}
<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}

1 votes

Jetez un œil à la solution de Charlesthk, c'est la même chose sans ajouter une bibliothèque supplémentaire :)

0 votes

@DavidW. : Oui, mais Widget Tweaks a beaucoup plus de filtres, tels que render_field .

0 votes

La solution Charlesthk convertit le BoundField en SafeString Les autres filtres (similaires) ne peuvent donc pas être enchaînés. django-widget-tweaks renvoie des champs, ce qui en fait une solution plus robuste.

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