web-dev-qa-db-fra.com

Style CSS dans les formulaires Django

Comment est-ce que je dénomme ce qui suit:

dans 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)

dans contact_form.html -

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

Par exemple, comment définir une classe ou un ID pour le sujet, l'e-mail ou le message auquel fournir une feuille de style externe? Je vous remercie

111
David542

Tiré de ma réponse à: Comment baliser des 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'}),
        }

--- MODIFIER ---
La modification ci-dessus est la modification la plus facile à apporter au code de la question d'origine qui accomplit ce qui a été demandé. Cela vous empêche également de vous répéter si vous réutilisez le formulaire ailleurs; vos classes ou autres attributs ne fonctionnent que 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 entièrement personnalisé, c’est clairement documenté

- EDIT 2 ---
Ajout d'une méthode plus récente pour spécifier un widget et des attributs pour un ModelForm.

144
shadfc

Cela peut être fait en utilisant un filtre de modèle personnalisé . Considérant que vous rendez le 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 la méthode as_widget.

vous pouvez créer un filtre personnalisé "addclass" dans "my_app/templatetags/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 appliquez 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 la classe css "MyClass".

J'espère que cette aide.

82
Charlesthk

Si vous ne souhaitez pas ajouter du code aucun au formulaire (comme indiqué dans les commentaires à la réponse de @ shadfc), il est certainement possible, voici deux options.

Tout d’abord, il vous suffit de référencer les champs individuellement dans le code HTML, plutôt que l’ensemble du formulaire à la 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 remplacé par un liste non classé.) 

Deuxièmement, notez dans la documentation sur la sortie des formulaires au format HTML , Django:

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

Tous vos champs de formulaire ont déjà un unique id. Vous feriez donc référence à id_subject dans votre fichier CSS pour styliser le champ sujet. Je dois noter que voici comment le formulaire se comporte lorsque vous prenez le par défaut HTML, qui nécessite simplement d’imprimer le formulaire, pas les champs individuels:

<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 créer des tableaux, etc.).

Remarque - 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 devrez également mettre à jour le CSS) - mais il est assez facile de le référencer tous les champs par id dans votre CSS comme ceci:

#id_subject, #id_email, #email_message 
{color: red;}
25
John C

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 marche.

Ignas

11
Ignas Butėnas

Per this blog, vous pouvez ajouter des classes CSS à vos champs en utilisant un filtre de modèle personnalisé.

from Django import template
register = template.Library()

@register.filter(name='addcss')
def addcss(field, css):
    return field.as_widget(attrs={"class":css})

Mettez ceci dans le dossier templatetags/de votre application et vous pouvez maintenant faire

{{field|addcss:"form-control"}}
10
aashanand

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

Cela 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" }}
7
Eamonn Faherty

Tu peux faire:

<form action="" method="post">
    <table>
        {% for field in form %}
        <tr><td>{{field}}</td></tr>
        {% endfor %}
    </table>
    <input type="submit" value="Submit">
</form>

Ensuite, vous pouvez ajouter des classes/id à par exemple la balise <td>. Vous pouvez bien sûr utiliser les autres balises de votre choix. Vérifiez Utilisation des formulaires Django , à titre d’exemple, de ce qui est disponible pour chaque field du formulaire ({{field}}, par exemple, n’affiche que la balise d’entrée, pas l’étiquette, etc.).

5

Vous n'avez peut-être pas besoin de remplacer le __init__ de votre classe de formulaire, car Django définit les attributs name & id dans HTML inputs. Vous pouvez avoir CSS comme ça:

form input[name='subject'] {
    font-size: xx-large;
}
2
tehfink

Je n'ai pas vu celui-ci vraiment ...

https://docs.djangoproject.com/fr/1.8/ref/forms/api/#more-granular-output

Sortie plus granulaire

Les méthodes as_p (), as_ul () et as_table () ne sont que des raccourcis pour les développeurs paresseux - ce n’est pas le seul moyen d’afficher un objet de formulaire.

class BoundField Utilisé pour afficher le HTML ou les attributs d'accès pour un seul champ d'une instance de formulaire.

La méthode str () (unicode sous Python 2) de cet objet affiche le code HTML de ce champ.

Pour récupérer un seul BoundField, utilisez la syntaxe de recherche par dictionnaire sur votre formulaire en utilisant le nom du champ comme clé:

>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" />

Pour récupérer tous les objets BoundField, itérez le formulaire:

>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="email" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

La sortie spécifique au champ respecte le paramètre auto_id de l’objet formulaire:

>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" />
2
BilliAm

Il existe un outil très facile à installer et très utile pour Django que je utilise pour le style et qui peut être utilisé pour tous les environnements frontaux tels que Bootstrap, Materialise, Foundation, etc. Il s’appelle widget-tweaks Documentation: Widget Tweaks

  1. Vous pouvez l'utiliser avec les vues génériques de Django
  2. Ou avec vos propres formulaires:

depuis les formulaires d'importation Django

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

Au lieu d'utiliser default:

{{ form.as_p }} or {{ form.as_ul }}

Vous pouvez l'éditer à votre façon en utilisant l'attribut render_field qui vous donne un moyen de le styler plus proche du HTML, comme dans cet exemple:

template.html

{% load widget_tweaks %}

<div class="container">
   <div class="col-md-4">
      {% render_field form.subject class+="form-control myCSSclass" placeholder="Enter your subject here" %}
   </div>
   <div class="col-md-4">
      {% render_field form.email type="email" class+="myCSSclassX myCSSclass2" %}
   </div>
   <div class="col-md-4">
      {% render_field form.message class+="myCSSclass" rows="4" cols="6" placeholder=form.message.label %}
   </div>
</div>

Cette bibliothèque vous donne l’opportunité d’avoir votre front end bien séparé de votre backend

1

Dans Django 1.10 (éventuellement plus tôt également), vous pouvez le faire comme suit.

Modèle:

class Todo(models.Model):
    todo_name = models.CharField(max_length=200)
    todo_description = models.CharField(max_length=200, default="")
    todo_created = models.DateTimeField('date created')
    todo_completed = models.BooleanField(default=False)

    def __str__(self):
        return self.todo_name

Forme:

class TodoUpdateForm(forms.ModelForm):
    class Meta:
        model = Todo
        exclude = ('todo_created','todo_completed')

Modèle:

<form action="" method="post">{% csrf_token %}
    {{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.todo_name.errors }}
    <label for="{{ form.name.id_for_label }}">Name:</label>
    {{ form.todo_name }}
</div>
<div class="fieldWrapper">
    {{ form.todo_description.errors }}
    <label for="{{ form.todo_description.id_for_label }}">Description</label>
    {{ form.todo_description }}
</div>
    <input type="submit" value="Update" />
</form>
1
MadPhysicist

Une solution consiste à utiliser JavaScript pour ajouter les classes CSS requises une fois la page prête. Par exemple, pour styliser la sortie de formulaire Django avec des classes d’amorçage (jQuery utilisé pour abréger):

<script type="text/javascript">
    $(document).ready(function() {
        $('#some_Django_form_id').find("input[type='text'], select, textarea").each(function(index, element) {
            $(element).addClass("form-control");
        });
    });
</script>

Cela évite la laideur de mélanger les spécificités de style avec la logique de votre entreprise.

1
Simon Feltman

Écrivez votre formulaire comme:

    class MyForm(forms.Form):
         name = forms.CharField(widget=forms.TextInput(attr={'class':'name'}))
         message = forms.CharField(widget=forms.Textarea(attr={'class':'message'}))

Dans votre champ HTML, faites quelque chose comme:

{% for field in form %}
      <div class="row">
        <label for="{{ field.name}}">{{ field.name }}</label>{{ field }}
     </div>
{% endfor %}

Ensuite, dans votre CSS, écrivez quelque chose comme:

.name{
      /* you already have this class so create it's style form here */
}
.message{
      /* you already have this class so create it's style form here */
}
label[for='message']{
      /* style for label */
}

J'espère que cette réponse vaut la peine d'essayer! Notez que vous devez avoir écrit vos vues pour rendre le fichier HTML contenant le formulaire.

0
Aula

Edit: Une autre façon (légèrement meilleure) de faire ce que je suggère est la réponse ici: Style de champ de saisie de formulaire Django

Toutes les options ci-dessus sont géniales, je pensais juste y ajouter celle-ci car elle est différente.

Si vous voulez un style personnalisé, des classes, etc. sur vos formulaires, vous pouvez effectuer une entrée html dans votre modèle qui correspond à votre champ de formulaire. Pour un CharField, par exemple, (le widget par défaut est TextInput), supposons que vous souhaitiez une saisie de texte d’apparence amorce. Vous feriez quelque chose comme ça: 

<input type="text" class="form-control" name="form_field_name_here"> 

Et tant que vous mettez le nom du champ de formulaire correspond à l'attribut html name (et que le widget doit probablement correspondre également au type d'entrée), Django exécutera tous les mêmes validateurs sur ce champ lorsque vous exécuterez validate ou form.is_valid() et 

Styliser d'autres éléments tels que les étiquettes, les messages d'erreur et le texte d'aide ne nécessite pas beaucoup de solutions de contournement, car vous pouvez utiliser quelque chose comme form.field.error.as_text et les styler comme vous le souhaitez. Les champs réels sont ceux qui nécessitent un peu de bidouillage.

Je ne sais pas si c'est la meilleure façon, ou celle que je recommanderais, mais c'est une façon, et cela pourrait convenir à quelqu'un.

Voici un guide pratique des formulaires de style qui inclut la plupart des réponses répertoriées dans SO (comme l'utilisation de attr sur les widgets et les modifications de widget) . https://simpleisbetterthancomplex.com/article/2017 /08/19/how-to-render-Django-form-manually.html

0
kimbo

Styling des instances de widgets

Si vous souhaitez rendre une instance de widget différente d'une autre, vous devez spécifier des attributs supplémentaires au moment où l'objet de widget est instancié et affecté à un champ de formulaire (et peut-être ajouter des règles à vos fichiers CSS).

https://docs.djangoproject.com/fr/2.2/ref/forms/widgets/

Pour ce faire, vous utilisez l'argument Widget.attrs lors de la création du widget:

class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

Vous pouvez également modifier un widget dans la définition de formulaire:

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({'class': 'special'})
    comment.widget.attrs.update(size='40')

Ou si le champ n'est pas déclaré directement sur le formulaire (tel que les champs du formulaire modèle), vous pouvez utiliser l'attribut Form.fields:

class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'special'})
        self.fields['comment'].widget.attrs.update(size='40')

Django inclura ensuite les attributs supplémentaires dans la sortie rendue:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>
0
Freman Zhang