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

Je suis sortie de champs d'un formulaire dans un modèle comme celui-ci {{ form.first_name }} et je voudrais ajouter une classe (par exemple. du plan span x-classe) pour elle. J'aimerais donc savoir s'il existe une bonne solution readymade (filtre de modèle) pour cela, que je pourrais utiliser à la mode {{ form.first_name|add_class:"span-4" }}? (Je veux juste savoir si les développeurs de Django ou quelqu'un a pensé à cela à mon insu avant de le faire par moi-même)

32
demandé sur Srikar Appalaraju 2010-11-08 16:26:01

7 réponses

Il vous suffit d'installer Django widget_tweaks

pip install django-widget-tweaks

Après vous pouvez faire quelque chose comme ça sur votre modèle:

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

--

Lisez tout à ce sujet ici .

46
répondu Cristian Rojas 2012-10-21 09:21:04

Pour résoudre ce problème, j'ai créé mon propre filtre de modèle, vous pouvez l'appliquer sur n'importe quelle balise, pas seulement sur les é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
répondu Bernhard Vallant 2012-10-21 09:20:42

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

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: mon projet > general_tools_app > templatetags > add_class.py

General_tools_app est une application qui collecte des fonctionnalités utiles comme celle - ci que j'ajoute aux nouveaux projets django.

(les répertoires general_tools_app et templatetags ont tous deux un fichier __init__.py vide afin qu'ils soient enregistrés correctement)

Dans settings.py, mon tuple INSTALLED_APPS inclut 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
répondu bitbutter 2012-10-21 09:21:15

Une autre façon est d'utiliser la méthode as_widget sur un champ pour le modifier-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 aussi utiliser as_widget afin d'ajouter d'autres attributs, comme placeholder, etc.

9
répondu user85461 2014-12-04 00:07:19

J'apprends encore Django, mais ne pourriez-vous 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 le faire au niveau du modèle (ou d'utiliser des filtres) sauf si vous avez une exigence que je n'ai pas comprise.

5
répondu Srikar Appalaraju 2012-10-21 09:21:26

Une note de plus sur la solution de lazerscience: si vous appliquez ceci à un élément sans attribut de classe, la chaîne replace dans le cas else 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 à peu près sûr que les navigateurs suppriment ces définitions de classe étrangères, mais cela fait beaucoup de remplacements de chaînes lorsque vous en avez seulement besoin. 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
répondu Gavin 2012-10-21 09:21:53

Vous devez spécifier explicitement le widget et ajouter la classe en utilisant le attrs argument du mot clé . Il n'y a pas d'autre moyen que je connaisse.

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

0
répondu Deniz Dogan 2010-11-08 13:32:00