Definieren Sie die CSS-Klasse in Django-Formularen


192

Angenommen, ich habe ein Formular

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

Gibt es eine Möglichkeit für mich, CSS-Klassen für jedes Feld so zu definieren, dass ich jQuery basierend auf der Klasse auf meiner gerenderten Seite verwenden kann?

Ich hatte gehofft, das Formular nicht manuell erstellen zu müssen.



10
@skyl Ich würde es als Hinweis darauf nehmen, dass es nicht leicht in den Django-Dokumenten zu finden ist. Ich habe auch mehrere Google-Suchanfragen durchgeführt und konnte diese nicht finden. Daher freue ich mich über die Frage und sie wird positiv bewertet.
Nils

Ich weiß, dass es ein alter Thread ist, aber in Django-Formularfeldern haben sie jetzt eine id_fieldname-Klasse.
Ratsimihah

Antworten:


182

Eine weitere Lösung, die keine Änderungen im Python-Code erfordert und daher besser für Designer und einmalige Präsentationsänderungen geeignet ist : Django-Widget-Tweaks . Hoffe, jemand wird es nützlich finden.


61
Die einzig vernünftige Lösung muss ich sagen. Danke dir!. Python-Code, und insbesondere in der Definition des Formulars, ist der letzte Ort, an dem Dinge für das Styling eingefügt werden - diese gehören definitiv zu den Vorlagen.
Boris Chervenkov

5
Dies ist eine großartige Bibliothek! Es ist eine Schande, dass diese Antwort unten vergraben ist.
Chris Lacasse

1
Großartig für Designer! :-)
hobbes3

1
Ausgezeichnet! Ich hatte einige Filter entwickelt, um diese Dinge zu tun, aber dieses Projekt ist viel leistungsfähiger. Vielen Dank!
Msbrogli

1
Eigentlich funktioniert es auch für Jinja2 :-) Ich habe die Reihenfolge des sicheren Fileters geändert und Klammern anstelle des Doppelpunkts hinzugefügt {{myform.email | add_class ("css_class_1 css_class_2") | safe}}. Danke, dass Sie dies geschrieben haben. es sollte ein Teil von Django sein.
David Dehghan

92

Beantwortete meine eigene Frage. Seufzer

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

Ich wusste nicht, dass es an den Widget-Konstruktor übergeben wurde.


2
Bedeutet das, dass es nicht mit der ModelForm-Klasse verwendet werden kann?
Xster

2
Nein, Sie müssen lediglich das Formularfeld im Modellformular explizit definieren, damit Sie das Widget definieren können. Oder verwenden Sie die unten aufgeführte Lösung, um zu vermeiden, dass Sie mit dem Formularfeld herumspielen müssen.
Tom

78

Hier ist eine weitere Lösung zum Hinzufügen von Klassendefinitionen zu den Widgets, nachdem die Felder in der Klasse deklariert wurden.

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

4
Bei ModelForms ist dies häufig besser, da Sie das verwendete Standardformularfeld nicht kennen müssen und verschiedene Klassen basierend auf den Laufzeitbedingungen dynamisch festlegen können. Sauberer als Meta-Coding-Hacks ...
Daniel Naab

1
Dies setzt voraus, dass Sie für jedes Feld in einem Formular eine Eingabe wünschen, was häufig nicht der Fall ist. Ein Formular ist nicht unbedingt an ein Modell gebunden - es kann an viele Modelle gebunden sein. Für den Fall, dass die Modellfelder und die Formularfelder eine 1: 1-Beziehung haben, ist ModelForm eine viel bessere Wahl.
Ashchristopher

44

Verwenden Sie Django-Widget-Tweaks , es ist einfach zu bedienen und funktioniert ziemlich gut.

Andernfalls kann dies mithilfe eines benutzerdefinierten Vorlagenfilters erfolgen.

In Anbetracht dessen, dass Sie Ihr Formular folgendermaßen rendern:

<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 ist eine Instanz von BoundField mit der Methode as_widget .

Sie können einen benutzerdefinierten Filter "addcss" in "my_app / templatetags / myfilters.py" erstellen.

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

Und dann wenden Sie Ihren Filter an:

{% 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 werden dann mit der CSS-Klasse "MyClass" gerendert.

Ich hoffe das hilft.

BEARBEITEN 1

  • Aktualisieren Sie den Filter gemäß der Antwort von dimyG

  • Django-Widget-Tweak-Link hinzufügen

BEARBEITEN 2

  • Aktualisiere den Filter gemäß Bhyds Kommentar

3
Das ist toll! Es ist TROCKEN und trennt die Anzeigeebene von der Kontrollebene. +1 von mir!
Alewwisnia

1
Jetzt habe ich jedoch einen Nachteil bemerkt. Wenn ich eine Klasse in Widget-Attributen definiere, werden sie von diesem 'addcss'-Filter überschrieben. Haben Sie Ideen, wie Sie das zusammenführen können?
Alewwisnia

1
Ich meine, as_widget () überschreibt attrs. Wie kann sichergestellt werden, dass vorhandene Attribute verwendet und um neue erweitert werden?
Alewwisnia

Siehe diese Antwort, wie man bestehende
Feldklassen

get('class', None).split(' ')schlägt fehl, wenn das Tag nicht über das zurückgegebene Klassenattribut verfügt None. Ändern es zu get('class', '').split(' ')funktioniert
dtasev

32

Erweiterung der Methode, auf die unter docs.djangoproject.com verwiesen wird:

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

Ich fand es mühsam, den nativen Widget-Typ für jedes Feld kennen zu müssen, und fand es lustig, die Standardeinstellung zu überschreiben, nur um einen Klassennamen in ein Formularfeld einzufügen. Das scheint bei mir zu funktionieren:

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'

Das scheint mir ein bisschen sauberer zu sein.


Dies ist genau das, was andere vor langer Zeit gesagt haben, außer dass Sie es mit "Größe" und nicht mit "Klasse" tun, was angefordert wurde.
Chris Morgan

3
@Chris Morgan Eigentlich ist er der erste, der vorschlägt, "comment.widget.attrs" in der Formulardeklaration selbst zu verwenden (anstatt mit init herumzuspielen oder dies in der Ansicht zu tun).
DarwinSurvivor

29

Wenn alle Felder im Formular eine bestimmte Klasse erben sollen, definieren Sie einfach eine übergeordnete Klasse, die von dieser erbt forms.ModelFormund dann von ihr erbt

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

Dies hat mir geholfen, die 'form-control'Klasse automatisch zu allen Feldern in allen Formularen meiner Anwendung hinzuzufügen, ohne die Replikation von Code hinzuzufügen.


1
Bitte beginnen Sie Klassennamen mit Großbuchstaben (auch BaseForm scheint ein viel besserer Name dafür zu sein)
Alvaro

16

Hier ist eine einfache Möglichkeit, die Ansicht zu ändern. Fügen Sie unten in der Ansicht hinzu, bevor Sie es in die Vorlage übergeben.

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

14

Fügen Sie die Klassen einfach wie folgt zu Ihrem Formular hinzu.

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

Hier ist eine Variation der obigen, die allen Feldern die gleiche Klasse gibt (z. B. schöne, abgerundete Ecken).

  # 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

Sie können dies versuchen ..

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

Weitere Informationen finden Sie unter: Django Widgets


2

Wenn Sie dem Feld eines Formulars in einer Vorlage eine Klasse hinzufügen möchten (nicht in view.py oder form.py), z. B. in Fällen, in denen Sie Apps von Drittanbietern ändern möchten, ohne deren Ansichten zu überschreiben, dann einen Vorlagenfilter wie beschrieben in Charlesthk Antwort ist sehr bequem. In dieser Antwort überschreibt der Vorlagenfilter jedoch alle vorhandenen Klassen, die das Feld möglicherweise hat.

Ich habe versucht, dies als Bearbeitung hinzuzufügen, aber es wurde vorgeschlagen, es als neue Antwort zu schreiben.

Hier ist also ein Vorlagen-Tag, das die vorhandenen Klassen des Felds berücksichtigt:

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

Danke für Ihren Vorschlag. Ich habe meine Antwort entsprechend mit einem "pythonischeren" Ansatz bearbeitet.
Charlesthk

toll !!, das habe ich gesucht
ugali soft

1

Wie sich herausstellt, können Sie dies im Formularkonstruktor ( Init- Funktion) oder nach dem Initiieren der Formularklasse tun . Dies ist manchmal erforderlich, wenn Sie kein eigenes Formular schreiben und dieses Formular von einem anderen Ort stammt -

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

Sie können auch Django Crispy Forms verwenden ist ein großartiges Tool zum Definieren von Formularen, falls Sie ein CSS-Framework wie Bootstrap oder Foundation verwenden möchten. Dort können Sie ganz einfach Klassen für Ihre Formularfelder angeben.

Ihre Formularklasse möchte dies dann:

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'),
        )
    )
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.