CSS-Styling in Django-Formen

150

Ich möchte Folgendes stylen:

forms.py:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

contact_form.html:

<form action="" method="post">
  <table>
    {{ form.as_table }}
  </table>
  <input type="submit" value="Submit">
</form>

Zum Beispiel : Wie kann ich eine Klasse oder ID für die subject, email, messageein externes Stylesheet zu bieten?

David542
quelle

Antworten:

192

Entnommen aus meiner Antwort auf: So markieren Sie Formularfelder mit <div class = 'field_type'> in Django

class MyForm(forms.Form):
    myfield = forms.CharField(widget=forms.TextInput(attrs={'class' : 'myfieldclass'}))

oder

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield'].widget.attrs.update({'class' : 'myfieldclass'})

oder

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'myfield': forms.TextInput(attrs={'class': 'myfieldclass'}),
        }

--- BEARBEITEN ---
Das Obige ist die einfachste Änderung am Code der ursprünglichen Frage, die das erfüllt, was gefragt wurde. Es hält Sie auch davon ab, sich zu wiederholen, wenn Sie das Formular an anderen Stellen wiederverwenden. Ihre Klassen oder andere Attribute funktionieren nur, wenn Sie die Formularmethoden as_table / as_ul / as_p des Django verwenden. Wenn Sie die vollständige Kontrolle für ein vollständig benutzerdefiniertes Rendering benötigen, ist dies klar dokumentiert

- EDIT 2 --- Es wurde
eine neuere Methode zum Angeben von Widgets und Attributen für eine ModelForm hinzugefügt.

Shadfc
quelle
27
Es wird jedoch nicht empfohlen, Präsentation mit Geschäftslogik zu mischen.
Torsten Engelbrecht
8
Wie ist diese Präsentation? Sie geben dem Element eine Klasse, die nur eine Kennung oder Kategorisierung ist. Sie müssen noch definieren, was das anderswo tut
Shadfc
9
Ja und nein. Erste CSS-Klassen werden standardmäßig für das Styling verwendet. Wenn Sie eine eindeutige Kennung benötigen, ist diese besser zu verwenden id. Zweitens ist es normalerweise die Verantwortung der Vorlagenseite, dies genau zu tun, insbesondere, wenn Sie über Frontend-Methoden (js, css) auf diese Klasse zugreifen. Ich habe nicht gesagt, dass deine Antwort falsch ist. Meiner Meinung nach ist es nur eine schlechte Praxis (insbesondere wenn Sie in einem Team mit Frontend- und Backend-Entwicklern arbeiten).
Torsten Engelbrecht
6
Das sieht lächerlich aus, nur um eine Klasse hinzuzufügen, brauchen Sie so viel Code? Es scheint einfacher zu sein, HTML / CSS in diesen Bereichen hart zu codieren (insbesondere für eine CSS-lastige Site).
David542
9
Es ist verrückt, dass Django das so umständlich macht!
Bryce
103

Dies kann mithilfe eines benutzerdefinierten Vorlagenfilters erfolgen. Rendern Sie Ihr Formular folgendermaßen:

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjectist eine Instanz, von BoundFieldder die as_widget()Methode hat.

Sie können einen benutzerdefinierten Filter addclassin my_app / templatetags / myfilters.py erstellen :

from django import template

register = template.Library()

@register.filter(name='addclass')
def addclass(value, arg):
    return value.as_widget(attrs={'class': arg})

Und dann wenden Sie Ihren Filter an:

{% load myfilters %}

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject|addclass:'MyClass' }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjectswird dann mit der MyClassCSS-Klasse gerendert .

Charlesthk
quelle
5
Dies ist eine der saubereren und einfach zu implementierenden Lösungen
Benutzer
5
Diese Antwort sollte die beste Antwort sein !!! Es ist wirklich sauberer als die von Django vorgeschlagene Lösung! Gut gemacht @Charlesthk
David D.
4
Super hilfreich. Anfangs war es mir nicht klar, aber Sie können dies auch verwenden, um mehrere Klassen hinzuzufügen:{{ form.subject|addclass:'myclass1 myclass2' }}
smg
Ich mag es, dass dies ermöglicht, die HTML-Klassen in den HTML-Dateien zu behalten. Wenn ich mit Styling arbeite, springe ich zwischen Stylesheets und Strukturen hin und her, nicht zwischen Modellen und / oder Formularen.
Kevin
29

Wenn Sie dem Formular keinen Code hinzufügen möchten (wie in den Kommentaren zu @ shadfcs Antwort erwähnt), ist dies sicherlich möglich. Hier sind zwei Optionen.

Erstens verweisen Sie nur die Felder einzeln im HTML, anstatt das gesamte Formular auf einmal:

<form action="" method="post">
    <ul class="contactList">
        <li id="subject" class="contact">{{ form.subject }}</li>
        <li id="email" class="contact">{{ form.email }}</li>
        <li id="message" class="contact">{{ form.message }}</li>
    </ul>
    <input type="submit" value="Submit">
</form>

(Beachten Sie, dass ich es auch in eine unsortierte Liste geändert habe .)

Zweitens beachten Sie in den Dokumenten zur Ausgabe von Formularen als HTML , Django:

Die Feld-ID wird generiert, indem dem Feldnamen 'id_' vorangestellt wird. Die ID-Attribute und Tags sind standardmäßig in der Ausgabe enthalten.

Alle Ihre Formularfelder haben bereits eine eindeutige ID . So würden Sie verweisen id_subject in Ihrem CSS - Datei Stil das Thema Feld. Ich sollte beachten, dass sich das Formular so verhält, wenn Sie den Standard- HTML-Code verwenden, für den nur das Formular gedruckt werden muss, nicht die einzelnen Felder:

<ul class="contactList">
    {{ form }}  # Will auto-generate HTML with id_subject, id_email, email_message 
    {{ form.as_ul }} # might also work, haven't tested
</ul>

Weitere Optionen für die Ausgabe von Formularen finden Sie im vorherigen Link (Sie können Tabellen usw. erstellen).

Hinweis - Mir ist klar, dass dies nicht mit dem Hinzufügen einer Klasse zu jedem Element identisch ist (wenn Sie dem Formular ein Feld hinzugefügt haben, müssen Sie auch das CSS aktualisieren). Es ist jedoch einfach genug, alle Felder anhand der ID zu referenzieren in Ihrem CSS wie folgt:

#id_subject, #id_email, #email_message 
{color: red;}
John C.
quelle
Ich habe Ihre zweite Lösung ausprobiert, aber sie hat nicht funktioniert. Ich habe eine Klasse für die id_email erstellt und es konnten keine Ergebnisse erzielt werden.
Fast ein Anfänger
@almostabeginner eins kann ich für das Debuggen vorschlagen - wenn Sie die Seite in einem Browser verwenden View Seite Quelle ( in der Regel durch einen Rechtsklick) und Blick auf die tatsächliche volle Seite , dass Django Erzeugungs ist. Überprüfen Sie, ob die Felder mit der erwarteten ID oder Klassenkennung vorhanden sind. Außerdem können die meisten Browser (möglicherweise durch Installation eines Plugins) einen Debugger ausführen, der Ihnen das CSS anzeigt, das auf eine Seite angewendet wird. Dies ist auch hilfreich, um zu sehen, was los ist.
John C
@almostabeginner auch beachten, ich habe ein bisschen Beispielcode hinzugefügt. Falls dies nicht nur aus dem Text hervorgeht, müssen Sie auf das Formular selbst verweisen, nicht auf einzelne Felder. Zu diesem Zeitpunkt generiert das Formular automatisch HTML, das wie beschrieben IDs enthält . Hoffentlich hilft das.
John C
1
Vielen Dank für die Hilfe, das Problem war überhaupt nicht mein CSS, das Problem hing mit dem Cache zusammen. Also wurde mein altes CSS gespeichert, daher würde keine der Änderungen angezeigt werden. Ich habe gerade den Cache aus Chrome gelöscht und alle Updates wurden angezeigt.
Fast ein Anfänger
15

Gemäß diesem Blog-Beitrag können Sie Ihren Feldern mithilfe eines benutzerdefinierten Vorlagenfilters CSS-Klassen hinzufügen.

from django import template
register = template.Library()

@register.filter(name='addcss')
def addcss(field, css):
    return field.as_widget(attrs={"class":css})

Legen Sie dies in die Vorlagen / Ordner Ihrer App und Sie können dies jetzt tun

{{field|addcss:"form-control"}}
Aashanand
quelle
2
Dies sollte als die echte Antwort auf diesen Beitrag akzeptiert worden sein :)
MVDB
Mit Abstand beste Lösung.
Mods Vs Rockers
1
Genial, danke! Vergessen Sie nicht, das Tag tatsächlich zu laden. In Django 2.1 konnte ich Django nur durch Hinzufügen einer Option in settings.py dazu bringen, die Vorlage zu finden: 'library': {'add_css': 'app.templatetags.tag_name',}
simonbogarde
11

Sie können dies tun:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    subject.widget.attrs.update({'id' : 'your_id'})

Hoffe das funktioniert.

Ignas

Ignas Butėnas
quelle
Danke ignas. Präzise Antwort!
Rudresh Ajgaonkar
9

Sie können diese Bibliothek verwenden: https://pypi.python.org/pypi/django-widget-tweaks

Damit können Sie Folgendes tun:

{% load widget_tweaks %}
<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}
Eamonn Faherty
quelle
1
Schauen Sie sich die Charlesthk-Lösung an, es ist dasselbe, ohne eine zusätzliche Bibliothek hinzuzufügen :)
David D.
@ DavidW.: Ja, aber Widget Tweaks hat viele weitere Filter, wie z render_field.
mrdaliri
5

Du kannst tun:

<form action="" method="post">
    <table>
        {% for field in form %}
        <tr><td>{{field}}</td></tr>
        {% endfor %}
    </table>
    <input type="submit" value="Submit">
</form>

Dann können Sie beispielsweise dem <td>Tag Klassen / IDs hinzufügen . Sie können natürlich auch beliebige andere Tags verwenden. Aktivieren Sie als Beispiel die Option Mit Django-Formularen arbeiten, was für jedes fieldFormular verfügbar ist ( {{field}}z. B. wird nur das Eingabe-Tag ausgegeben, nicht das Etikett usw.).

Torsten Engelbrecht
quelle
3

Eine Lösung besteht darin, JavaScript zu verwenden, um die erforderlichen CSS-Klassen hinzuzufügen, nachdem die Seite fertig ist. Beispiel: Stylen der Ausgabe von Django-Formularen mit Bootstrap-Klassen (der Kürze halber wird jQuery verwendet):

<script type="text/javascript">
    $(document).ready(function() {
        $('#some_django_form_id').find("input[type='text'], select, textarea").each(function(index, element) {
            $(element).addClass("form-control");
        });
    });
</script>

Dies vermeidet die Hässlichkeit, Styling-Details mit Ihrer Geschäftslogik zu mischen.

Simon Feltman
quelle
3

Schreiben Sie Ihr Formular wie folgt:

    class MyForm(forms.Form):
         name = forms.CharField(widget=forms.TextInput(attr={'class':'name'}),label="Your Name")
         message = forms.CharField(widget=forms.Textarea(attr={'class':'message'}), label="Your Message")

Führen Sie in Ihrem HTML-Feld Folgendes aus:

{% for field in form %}
      <div class="row">
        <label for="{{ field.name}}">{{ field.label}}</label>{{ field }}
     </div>
{% endfor %}

Dann schreiben Sie in Ihr CSS etwas wie:

.name{
      /* you already have this class so create it's style form here */
}
.message{
      /* you already have this class so create it's style form here */
}
label[for='message']{
      /* style for label */
}

Hoffe, diese Antwort ist einen Versuch wert! Beachten Sie, dass Sie Ihre Ansichten geschrieben haben müssen, um die HTML-Datei zu rendern, die das Formular enthält.

Aula
quelle
Vielen Dank. aber wie kann ich einen bestimmten beschriftungstext schreiben?
Gakeko Betsi
2

Möglicherweise müssen Sie Ihre Formularklasse nicht überschreiben __init__, da Django Sätze nameund idAttribute in den HTML- Codes festlegt input. Sie können CSS wie folgt haben:

form input[name='subject'] {
    font-size: xx-large;
}
tehfink
quelle
1
Dazu hinzufügen. Bei "subject = forms ..." ist id = "id_subject" und name = "subject" die Django-Konvention für diese Attribute. Daher sollten Sie auch in der Lage sein, #id_subject {...}
solartic
@ Solartic: Du hast recht, danke. Ich habe das nicht erwähnt, weil das idvon Django für Formsets erstellte Feld ziemlich haarig wird…
tehfink
2

Ich habe diesen nicht wirklich gesehen ...

https://docs.djangoproject.com/de/1.8/ref/forms/api/#more-granular-output

Granularere Ausgabe

Die Methoden as_p (), as_ul () und as_table () sind lediglich Verknüpfungen für faule Entwickler - sie sind nicht die einzige Möglichkeit, ein Formularobjekt anzuzeigen.

Klasse BoundField Wird verwendet, um HTML- oder Zugriffsattribute für ein einzelnes Feld einer Formularinstanz anzuzeigen.

Die Methode str () ( Unicode in Python 2) dieses Objekts zeigt den HTML-Code für dieses Feld an.

Verwenden Sie zum Abrufen eines einzelnen BoundField die Syntax für die Wörterbuchsuche in Ihrem Formular, wobei Sie den Feldnamen als Schlüssel verwenden:

>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" />

Um alle BoundField-Objekte abzurufen, wiederholen Sie das Formular:

>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="email" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

Die feldspezifische Ausgabe berücksichtigt die auto_id-Einstellung des Formularobjekts:

>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" />
BilliAm
quelle
2

Es gibt ein sehr einfach zu installierendes und großartiges Tool für Django, das ich für das Styling verwende. Es kann für jedes Frontend-Framework wie Bootstrap, Materialise, Foundation usw. verwendet werden. Es heißt Widget-Tweaks. Dokumentation: Widget-Tweaks

  1. Sie können es mit den allgemeinen Ansichten von Django verwenden
  2. Oder mit Ihren eigenen Formularen:

aus Django-Importformularen

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

Anstatt Standard zu verwenden:

{{ form.as_p }} or {{ form.as_ul }}

Sie können es auf Ihre eigene Weise bearbeiten, indem Sie das Attribut render_field verwenden, mit dem Sie es wie in diesem Beispiel HTML-ähnlicher gestalten können:

template.html

{% load widget_tweaks %}

<div class="container">
   <div class="col-md-4">
      {% render_field form.subject class+="form-control myCSSclass" placeholder="Enter your subject here" %}
   </div>
   <div class="col-md-4">
      {% render_field form.email type="email" class+="myCSSclassX myCSSclass2" %}
   </div>
   <div class="col-md-4">
      {% render_field form.message class+="myCSSclass" rows="4" cols="6" placeholder=form.message.label %}
   </div>
</div>

Diese Bibliothek bietet Ihnen die Möglichkeit, Ihr Frontend gut von Ihrem Backend zu trennen

Alam Téllez
quelle
1

In Django 1.10 (möglicherweise auch früher) können Sie dies wie folgt tun.

Modell:

class Todo(models.Model):
    todo_name = models.CharField(max_length=200)
    todo_description = models.CharField(max_length=200, default="")
    todo_created = models.DateTimeField('date created')
    todo_completed = models.BooleanField(default=False)

    def __str__(self):
        return self.todo_name

Bilden:

class TodoUpdateForm(forms.ModelForm):
    class Meta:
        model = Todo
        exclude = ('todo_created','todo_completed')

Vorlage:

<form action="" method="post">{% csrf_token %}
    {{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.todo_name.errors }}
    <label for="{{ form.name.id_for_label }}">Name:</label>
    {{ form.todo_name }}
</div>
<div class="fieldWrapper">
    {{ form.todo_description.errors }}
    <label for="{{ form.todo_description.id_for_label }}">Description</label>
    {{ form.todo_description }}
</div>
    <input type="submit" value="Update" />
</form>
MadPhysicist
quelle
0

Bearbeiten: Eine andere (etwas bessere) Möglichkeit, das zu tun, was ich vorschlage, wird hier beantwortet: Django-Formular-Eingabefeld-Styling

Alle oben genannten Optionen sind fantastisch, ich dachte nur, ich würde diese einwerfen, weil sie anders ist.

Wenn Sie benutzerdefinierte Stile, Klassen usw. für Ihre Formulare wünschen, können Sie in Ihrer Vorlage eine HTML-Eingabe vornehmen, die Ihrem Formularfeld entspricht. Angenommen, TextInputSie möchten für ein CharField (Standard-Widget ist ) eine Texteingabe mit Bootstrap-Aussehen. Sie würden so etwas tun:

<input type="text" class="form-control" name="form_field_name_here">

Solange der Name des Formularfelds mit dem HTML- nameAttribut übereinstimmt (und das Widget wahrscheinlich auch mit dem Eingabetyp übereinstimmen muss), führt Django beim Ausführen von validateoder form.is_valid()und dieselben Validatoren für dieses Feld aus

Das Stylen anderer Dinge wie Beschriftungen, Fehlermeldungen und Hilfetexte erfordert nicht viel Problemumgehung, da Sie so etwas tun form.field.error.as_textund stylen können, wie Sie möchten. Die eigentlichen Felder erfordern ein wenig Fummeln.

Ich weiß nicht, ob dies der beste Weg ist oder der Weg, den ich empfehlen würde, aber es ist ein Weg, und es könnte für jemanden richtig sein.

Hier finden Sie eine nützliche Anleitung zum Stylen von Formularen. Sie enthält die meisten Antworten, die in SO aufgeführt sind (z. B. die Verwendung des Attributs für Widgets und Widget-Optimierungen). https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html

Kimbo
quelle
0

Styling von Widget-Instanzen

Wenn Sie möchten, dass eine Widget-Instanz anders aussieht als eine andere, müssen Sie zusätzliche Attribute angeben, wenn das Widget-Objekt instanziiert und einem Formularfeld zugewiesen wird (und möglicherweise Ihren CSS-Dateien einige Regeln hinzufügen).

https://docs.djangoproject.com/de/2.2/ref/forms/widgets/

Dazu verwenden Sie beim Erstellen des Widgets das Argument Widget.attrs:

class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

Sie können auch ein Widget in der Formulardefinition ändern:

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({'class': 'special'})
    comment.widget.attrs.update(size='40')

Wenn das Feld nicht direkt im Formular deklariert ist (z. B. Modellformularfelder), können Sie das Attribut Form.fields verwenden:

class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'special'})
        self.fields['comment'].widget.attrs.update(size='40')

Django wird dann die zusätzlichen Attribute in die gerenderte Ausgabe aufnehmen:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>
Freman Zhang
quelle