web-dev-qa-db-fra.com

Django: Ajout de classes CSS lors du rendu des champs de formulaire dans un modèle

Je produis les champs d'un formulaire dans un modèle comme celui-ci {{ form.first_name }} et j'aimerais lui ajouter une classe (par exemple, la classe span-x - de blueprint). J'aimerais donc savoir s'il existe une solution Nice readymade (filtre de gabarit) pour cela, que je pourrais utiliser dans le code {{ form.first_name|add_class:"span-4" }}? (Je veux juste savoir si les développeurs de Django ou qui que ce soit ont déjà pensé à cela à mon insu avant de le faire moi-même)

32
Bernhard Vallant

Pour résoudre ce problème, j'ai créé mon propre filtre de modèle, vous pouvez l'appliquer à n'importe quelle balise, pas seulement aux éléments d'entrée!

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
@register.filter
def add_class(value, css_class):
    string = unicode(value)
    match = class_re.search(string)
    if match:
        m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                                                    css_class, css_class), 
                                                    match.group(1))
        print match.group(1)
        if not m:
            return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
                                          string))
    else:
        return mark_safe(string.replace('>', ' class="%s">' % css_class))
    return value
22
Bernhard Vallant

Vous devez seulement installer Django widget_tweaks

pip install Django-widget-tweaks

Après avoir pu faire quelque chose comme ça sur votre modèle:

{{ form.search_query|attr:"type:search" }}

-

Lire tout à ce sujet here .

46
Cristian Rojas

Quelques notes supplémentaires sur la façon de s'y prendre avec la solution très pratique de Lazerscience. Voici à quoi ressemble le fichier avec les importations de dépendance:

import re
from Django.utils.safestring import mark_safe
from Django import template
register = template.Library()

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
@register.filter
def add_class(value, css_class):
    string = unicode(value)
    match = class_re.search(string)
    if match:
        m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                                                    css_class, css_class), 
                                                    match.group(1))
        print match.group(1)
        if not m:
            return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
                                          string))
    else:
        return mark_safe(string.replace('>', ' class="%s">' % css_class))
    return value

J'ai collé ceci dans un fichier appelé add_class.py. La structure du répertoire est la suivante: Mydjangoproject> general_tools_app> templatetags> add_class.py

general_tools_app est une application qui regroupe des fonctionnalités utiles, comme celles que j’ajoute aux nouveaux projets Django.

(Les répertoires general_tools_app et templatetags ont tous deux un fichier __init__.py vide pour pouvoir être correctement enregistrés)

Dans settings.py, mon tuple INSTALLED_APPS comprend l'entrée "mydjangoproject.general_tools_app".

Pour utiliser le filtre dans un modèle, j'ajoute la ligne {% load add_class %} en haut du fichier. Si je veux ajouter la classe 'delete' à un champ, je le ferais 

{{ myfield|add_class:'delete' }}
12
bitbutter

Une autre méthode consiste à utiliser la méthode as_widget sur un champ pour le modifier, ce qui est plus simple et plus sûr que l'approche regex et ne nécessite aucune dépendance supplémentaire.

Définir un filtre de modèle personnalisé :

@register.filter
def add_class(field, class_name):
    return field.as_widget(attrs={
        "class": " ".join((field.css_classes(), class_name))
    })

Et dans votre modèle:

{{ form.first_name|add_class:"span-4" }}

Vous pouvez également utiliser as_widget pour ajouter d'autres attributs, tels que placeholder, etc.

10
user85461

J'apprends encore Django, mais ne pourrais-tu pas faire quelque chose comme ça -

from Django import forms

class SomeForm(forms.Form):
    f = forms.CharField(label='x',widget=forms.TextInput(attrs={'class':'name'}))

Je suppose qu'il n'est pas nécessaire de faire cela au niveau du modèle (ou d'utiliser des filtres) à moins que vous n'ayez certaines exigences que je ne comprenais pas.

5

Encore une remarque sur la solution de lazerscience: si vous appliquez cela à un élément <select> sans attribut de classe, la chaîne remplacée dans le cas contraire produirait quelque chose comme ceci:

<select name="state" id="id_state" class="class1 class2">
    <option value="AL" class="class1 class2">Alabama</option class="class1 class2">
    <option value="AK" class="class1 class2">Alaska</option class="class1 class2">
    <option value="AZ" class="class1 class2">Arizona</option class="class1 class2">
</select class="class1 class2">

Je suis presque sûr que les navigateurs suppriment ces définitions de classes superflues, mais il y a beaucoup de chaînes de remplacement lorsque vous n'en avez besoin que d'une. Un remède facile pour cela:

return mark_safe(string.replace('>', ' class="%s">' % css_class, 1))

Ce dernier argument (1) garantira que seule la première instance de ">" sera remplacée par "class =" ... ">, ce qui est logiquement correct pour tout élément de formulaire.

3
Gavin

Vous devez spécifier explicitement le widget et ajouter la classe à l'aide de l'argument de mot clé attrs . Il n'y a pas d'autre moyen que je sache.

Toutefois, si cela est trop lourd, vous pouvez toujours envelopper le champ dans un autre élément, tel que div ou span et y ajouter une classe. Puis modifiez votre CSS en conséquence.

0
Deniz Dogan