Definire la classe css in django Forms


192

Supponiamo che io abbia un modulo

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

Esiste un modo per definire le classi css su ciascun campo in modo tale da poter usare jQuery in base alla classe nella mia pagina renderizzata?

Speravo di non dover compilare manualmente il modulo.



10
@skyl Lo prenderei come un'indicazione che non è facile da trovare nei documenti di Django. Ho cercato e fatto anche diverse ricerche su Google e non sono riuscito a trovarlo, quindi sono contento per la domanda e ottiene il mio voto.
Nils,

So che è un vecchio thread ma nei campi del modulo Django ora hanno una classe id_fieldname.
ratsimihah,

1
Vedi questa risposta su come definire le classi per un campo modulo all'interno di un modello rispettando le classi di campo esistenti
dimyG

Risposte:


182

Ancora un'altra soluzione che non richiede cambiamenti nel codice Python e quindi è meglio per i progettisti e cambiamenti di presentazione unici: django-widget-tweaks . Spero che qualcuno lo troverà utile.


61
L' unica soluzione sana, devo dire. Grazie!. Il codice Python, e specialmente nella definizione del modulo, è l'ultimo posto in cui inserire elementi per lo styling: questi appartengono sicuramente ai template.
Boris Chervenkov,

5
Questa è un'ottima biblioteca! È un peccato che questa risposta sia sepolta in fondo.
Chris Lacasse,

1
Ottimo per i designer! :-)
hobbes3

1
Eccellente! Avevo sviluppato alcuni filtri per fare queste cose, ma questo progetto è molto più potente. Grazie!
msbrogli,

1
in realtà funziona anche con Jinja2 :-) Ho cambiato l'ordine del filtro sicuro e ho aggiunto la parentesi anziché i due punti {{myform.email | add_class ("css_class_1 css_class_2") | safe}} grazie per averlo scritto. dovrebbe far parte di Django.
David Dehghan,

92

Ha risposto alla mia domanda. Sospiro

http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs

Non mi ero reso conto che fosse passato al costruttore del widget.


2
questo implica che non può essere utilizzato con la classe ModelForm?
xster,

2
No, devi solo definire esplicitamente il campo modulo nel modulo modello in modo da poter definire il widget. Oppure utilizza la soluzione elencata di seguito per evitare di dover confondere con il campo modulo.
Tom,

78

Ecco un'altra soluzione per aggiungere definizioni di classe ai widget dopo aver dichiarato i campi nella classe.

def __init__(self, *args, **kwargs):
    super(SampleClass, self).__init__(*args, **kwargs)
    self.fields['name'].widget.attrs['class'] = 'my_class'

4
Per ModelForms, questo è spesso meglio poiché non è necessario essere consapevoli del campo modulo predefinito utilizzato e è possibile impostare dinamicamente classi diverse in base alle condizioni di runtime. Più pulito degli hack di meta-codifica ...
Daniel Naab il

1
Ciò presuppone che si desideri un input per ogni campo in un modulo, che spesso non è il caso. Una forma non è necessariamente legata a un modello: potrebbe essere legata a molti modelli. Nel caso in cui i campi del modello e i campi del modulo abbiano una relazione 1: 1, quindi Sì, ModelForm è una scelta molto migliore.
ashchristopher,

44

Usa django-widget-tweaks , è facile da usare e funziona abbastanza bene.

Altrimenti ciò può essere fatto usando un filtro template personalizzato.

Considerando che rendi il tuo modulo in questo modo:

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subject è un'istanza di BoundField che ha as_widget metodo .

puoi creare un filtro personalizzato "addcss" in "my_app / templatetags / myfilters.py"

from django import template

register = template.Library()

@register.filter(name='addcss')
def addcss(value, arg):
    css_classes = value.field.widget.attrs.get('class', '').split(' ')
    if css_classes and arg not in css_classes:
        css_classes = '%s %s' % (css_classes, arg)
    return value.as_widget(attrs={'class': css_classes})

E quindi applicare il filtro:

{% load myfilters %}
<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

form.subjects verrà quindi reso con la classe css "MyClass".

Spero che questo aiuto.

MODIFICA 1

  • Filtro di aggiornamento secondo le dimyG 's risposta

  • Aggiungi il link django-widget-tweak

MODIFICA 2

  • Filtro di aggiornamento secondo le Bhyd 's commento

3
Questo è fantastico! È ASCIUTTO e separa il livello di visualizzazione dal livello di controllo. +1 da me!
alekwisnia,

1
Tuttavia, ora ho notato uno svantaggio. Se definisco la classe in widget attrs, vengono sostituiti da questo filtro 'addcss'. Hai qualche idea su come fonderlo?
alekwisnia,

1
Voglio dire, as_widget () sostituisce attrs. Come assicurarsi che utilizzi attrs esistenti e li estenda con uno nuovo?
alekwisnia,

Vedi questa risposta su come rispettare le classi di campi esistenti
dimyG

get('class', None).split(' ')fallirà se il tag non ha l'attributo class, come Noneviene restituito. Cambiarlo in get('class', '').split(' ')funziona
dtasev

32

Espandendo il metodo indicato in docs.djangoproject.com:

class MyForm(forms.Form): 
    comment = forms.CharField(
            widget=forms.TextInput(attrs={'size':'40'}))

Ho pensato che fosse problematico conoscere il tipo di widget nativo per ogni campo e ho pensato che fosse divertente ignorare il valore predefinito solo per inserire un nome di classe in un campo modulo. Questo sembra funzionare per me:

class MyForm(forms.Form): 
    #This instantiates the field w/ the default widget
    comment = forms.CharField()

    #We only override the part we care about
    comment.widget.attrs['size'] = '40'

Questo mi sembra un po 'più pulito.


Questo è esattamente ciò che altri hanno detto, secoli fa, tranne per il fatto che lo stai facendo con 'size' piuttosto che con 'class' che è stato richiesto.
Chris Morgan,

3
@ Chris Morgan In realtà, è il primo a suggerire di usare "comment.widget.attrs" nella dichiarazione del modulo stesso (invece di fare confusione con init o farlo nella vista).
DarwinSurvivor,

29

Se si desidera che tutti i campi nel modulo ereditino una determinata classe, è sufficiente definire una classe padre, che eredita da forms.ModelForm, e quindi eredita da essa

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'someClass'


class WhateverForm(BaseForm):
    class Meta:
        model = SomeModel

Questo mi ha aiutato ad aggiungere automaticamente la 'form-control'classe a tutti i campi in tutti i moduli della mia applicazione, senza aggiungere la replica del codice.


1
si prega di iniziare i nomi delle classi con lettere maiuscole (inoltre, BaseForm sembra un nome molto migliore per questo)
Alvaro

16

Ecco un modo semplice per modificare in vista. aggiungi sotto in vista poco prima di passarlo nel modello.

form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}

14

Aggiungi semplicemente le classi al tuo modulo come segue.

class UserLoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(
        attrs={
        'class':'form-control',
        'placeholder':'Username'
        }
    ))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
        'class':'form-control',
        'placeholder':'Password'
        }
    ))

5

Ecco una variazione di cui sopra che darà a tutti i campi la stessa classe (ad es. Jquery bei angoli arrotondati).

  # Simple way to assign css class to every field
  def __init__(self, *args, **kwargs):
    super(TranslatedPageForm, self).__init__(*args, **kwargs)
    for myField in self.fields:
      self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'

5

Puoi provare questo ..

class SampleClass(forms.Form):
  name = forms.CharField(max_length=30)
  name.widget.attrs.update({'class': 'your-class'})
...

Puoi vedere maggiori informazioni in: Widget Django


2

Nel caso in cui si desideri aggiungere una classe al campo di un modulo in un modello (non in view.py o form.py), ad esempio nei casi in cui si desidera modificare app di terze parti senza sovrascriverne le visualizzazioni, quindi un filtro modello come descritto nella risposta di Charlesthk è molto conveniente. Ma in questa risposta il filtro template sostituisce tutte le classi esistenti che il campo potrebbe avere.

Ho provato ad aggiungere questo come una modifica, ma è stato suggerito di essere scritto come una nuova risposta.

Quindi, ecco un tag modello che rispetta le classi esistenti del campo:

from django import template

register = template.Library()


@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})

Grazie per il tuo suggerimento Ho modificato la mia risposta di conseguenza con un approccio più "pitonico".
Charlesthk,

fantastico !!, questo è quello che stavo cercando
ugali soft

1

A quanto pare puoi farlo nel costruttore di moduli ( funzione init ) o dopo che è stata avviata la classe di moduli. Questo a volte è necessario se non stai scrivendo il tuo modulo e quel modulo proviene da qualche altra parte -

def some_view(request):
    add_css_to_fields = ['list','of','fields']
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    else:
        form = SomeForm()

    for key in form.fields.keys():
        if key in add_css_to_fields:
            field = form.fields[key]
            css_addition = 'css_addition '
            css = field.widget.attrs.get('class', '')
            field.widget.attrs['class'] = css_addition + css_classes

    return render(request, 'template_name.html', {'form': form})

1

Puoi anche usare Django Crispy Forms , è un ottimo strumento per definire i moduli nel caso in cui desideri utilizzare un framework CSS come Bootstrap o Foundation. Ed è facile specificare le classi per i campi del modulo lì.

La tua classe di modulo vorrebbe quindi:

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

    helper = FormHelper()
    helper.form_class = 'your-form-class'
    helper.layout = Layout(
        Field('name', css_class='name-class'),
        Field('age', css_class='age-class'),
        Field('django_hacker', css-class='hacker-class'),
        FormActions(
            Submit('save_changes', 'Save changes'),
        )
    )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.