2010-11-08 12 views
32

Sto trasmettendo i campi di un modulo in un modello come questo {{ form.first_name }} e vorrei aggiungere una classe (ad esempio blueprint's span-x -class) ad esso. Quindi mi piacerebbe sapere se c'è una bella soluzione readymade (filtro template) per questo, che potrei usare nella moda {{ form.first_name|add_class:"span-4" }}? (Voglio solo sapere se gli sviluppatori di Django o qualcuno lo hanno già pensato senza saperlo prima di farlo da solo)Django: aggiunta di classi CSS durante il rendering di campi modulo in un modello

risposta

22

Per risolvere questo ho creato il mio filtro modello, è possibile applicarlo su qualsiasi tag, non solo elementi di input!

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 
+2

Molto ben fatto. Per farlo funzionare per i campi che terminano con '/>', ho usato 'return mark_safe (string.replace ('', 'class ="% s "'% css_class))' - usato uno spazio invece di '>' in modo che trovi il primo spazio e inietti l'attributo prima del resto. – abstractpaper

+0

Il regexp corrisponde avido, ma dovrebbe corrispondere pigro. Ho modificato il codice di sopra in '' class_re = re.compile (r '(? <= Class = ["\']) (. *?) (? = [" \ '])') ''. Altrimenti coincide con l'ultimo '' "' 'char invece della fine della classe. –

0

È necessario specificare il widget esplicitamente e aggiungere la classe utilizzando attrs keyword argument. Non c'è altro modo di cui io sappia.

Tuttavia, se questo è troppo macchinoso, è ancora possibile avvolgere il campo in un altro elemento, come div o span e aggiungere una classe a questo. Quindi modifica il tuo CSS di conseguenza.

+1

Come ho già detto:

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

E nel tuo modello 'Mi piacerebbe farlo nel modello, perché il modulo può essere reso in varie apparenze! –

+1

Per risultati ottimizzati, è consigliabile leggere i layout reattivi. I tuoi modelli e le tue classi dovrebbero rimanere invariati e tutta la magia rimane in css. –

5

sto ancora imparando Django, ma non potresti fare questo qualcosa di simile -

from django import forms 

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

Credo che non c'è bisogno di fare questo a livello di modello (o utilizzare filtri) a meno che non si dispone di una certa requisito che non ho capito.

+2

È molto più semplice separare lo stile (css) dalla funzionalità (il modulo). Ad esempio, in che modo si aggiunge una classe a un campo modulo nel modello utilizzando questo metodo? Inoltre, come puoi visualizzare questo modulo in modi diversi senza duplicare il modulo, ad esempio un modulo ottimizzato per i dispositivi mobili e un modulo non adatto ai dispositivi mobili? La convalida fornita dal modulo non cambia, ma la visione di esso lo fa. – varikin

+1

La classe CSS applicata a livello di modulo non ha alcun impatto su diversi display. La classe del form dovrebbe rimanere la stessa su qualsiasi dispositivo e dovresti avere una configurazione di file css specifica per dispositivo, quando necessario. –

+0

Questa è la risposta corretta, per la maggior parte dei casi comunque. Non c'è bisogno di scherzare con espressioni regex! Basta forse menzionare il caso per ModelForm: 'classe Meta: widgets = {'f': forms.TextInput (attrs = {'class': 'name'}}}' – frnhr

12

Alcune note in più su come andare avanti con la soluzione molto pratica di Lazerscience. Ecco come appare il file con le importazioni delle importazioni:

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 

Ho incollato questo file in un file chiamato add_class.py. La struttura della directory è: mydjangoproject> general_tools_app> templatetags> add_class.py

general_tools_app è un'applicazione che raccoglie funzionalità utili come questa che aggiungo ai nuovi progetti di django.

(I general_tools_app e templatetags directory sia avere un file vuoto __init__.py in modo che essi ottenere registrati correttamente)

In settings.py, mia INSTALLED_APPS tuple include la voce 'mydjangoproject.general_tools_app'.

Per utilizzare il filtro in un modello, aggiungo la riga {% load add_class %} nella parte superiore del file. Se voglio aggiungere la classe 'cancella' a un campo, farei questo

{{ myfield|add_class:'delete' }} 
+1

Ho trovato la definizione' class_re' un po 'troppo avida, e ho finito in alcuni campi che la classe veniva inserita nell'attributo 'type' invece che in 'class'. La mia versione revisionata:' class_re = re.compile (r '(? <= class = ["\']) ([^" \ '] *) (["\']) ')' – DanH

3

Una nota di più sulle soluzioni di lazerscience: se si applica ad un <selezionare> elemento con nessun attributo class, la stringa sostituire nel caso altrimenti produrrebbe qualcosa come questo:

<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"> 

sono abbastanza sicuro browser rottami queste definizioni estranei di classe, ma questo è un sacco di corda sostituisce quando hai solo bisogno di uno. Un rimedio semplice per questo:

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

Questo ultimo argomento (1) farà in modo che solo la prima istanza di ">" verrà sostituito con "class =" ... ">, che è logicamente corretto per qualsiasi elemento di forma.

+0

Ciao , grazie per l'ispirazione, credo di non averlo mai usato con un 'select' ancora! –

46

Hai solo bisogno di installare Django widget_tweaks

pip install django-widget-tweaks 

Dopo si può fare qualcosa di simile sul modello:

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

-

Leggi tutto su di esso here.

+1

Stavo cercando come aggiungere classi alle 'labels', il ricordo che è semplice aggiungerli manualmente:' ' –

9

Un altro modo è utilizzare il metodo as_widget su un campo per modificarlo, più semplice e più sicuro dell'approccio regex e non richiede alcuna dipendenza aggiuntiva.

Definire un custom template filter: Ho

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

È inoltre possibile utilizzare as_widget per aggiungere altri attributi, come placeholder, ecc

+0

è abbastanza semplice e funziona – Bwire

+0

Ama questa soluzione elegante, inoltre ora ho imparato a utilizzare i tag modello. Grazie! – Matt

Problemi correlati