Penataan CSS dalam bentuk Django

150

Saya ingin merancang yang berikut ini:

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>

Misalnya, bagaimana cara menetapkan kelas atau ID untuk subject, email, messageuntuk memberikan style sheet eksternal untuk?

David542
sumber

Jawaban:

192

Diambil dari jawaban saya ke: Cara menandai kolom formulir dengan <div class = 'field_type'> di Django

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

atau

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

atau

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

--- EDIT ---
Di atas adalah perubahan termudah untuk membuat kode pertanyaan asli yang memenuhi apa yang ditanyakan. Ini juga mencegah Anda mengulangi diri sendiri jika menggunakan kembali formulir di tempat lain; kelas Anda atau atribut lainnya hanya berfungsi jika Anda menggunakan metode formulir as_table / as_ul / as_p Django. Jika Anda memerlukan kontrol penuh untuk rendering khusus, ini didokumentasikan dengan jelas

- EDIT 2 ---
Menambahkan cara yang lebih baru untuk menentukan widget dan attrs untuk ModelForm.

shadfc
sumber
27
Meskipun tidak disarankan untuk menggabungkan presentasi dengan logika bisnis.
Torsten Engelbrecht
8
Bagaimana presentasi ini? Anda memberi elemen kelas, yang hanya merupakan pengidentifikasi atau kategorisasi. Anda masih harus mendefinisikan apa yang dilakukan di tempat lain
shadfc
9
Iya dan tidak. Kelas CSS pertama adalah dengan konvensi yang digunakan untuk penataan, jika Anda memerlukan pengenal unik lebih baik digunakan id. Kedua biasanya responsobilty sisi template untuk melakukan hal ini, terutama jika Anda akan mengakses kelas ini melalui metode frontend (js, css). Saya tidak mengatakan jawaban Anda salah. Menurut pendapat saya itu hanya praktik yang buruk (terutama ketika Anda bekerja dalam tim dengan pengembang frontend dan backend).
Torsten Engelbrecht
6
Ini terlihat konyol, hanya untuk menambahkan kelas Anda memerlukan kode sebanyak ini? Tampaknya akan lebih mudah hanya dengan melakukan hard-code pada HTML / CSS di area ini (terutama untuk situs yang beratnya CSS).
David542
9
Itu gila Django membuat ini sangat canggung!
Bryce
103

Ini dapat dilakukan dengan menggunakan filter templat kustom. Pertimbangkan untuk menyerahkan formulir Anda dengan cara ini:

<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.subjectadalah contoh BoundFieldyang memiliki as_widget()metode.

Anda dapat membuat filter khusus addclassdi my_app / templatetags / myfilters.py :

from django import template

register = template.Library()

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

Lalu terapkan filter Anda:

{% 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.subjectskemudian akan diberikan dengan MyClasskelas CSS.

Charlesthk
sumber
5
Ini adalah salah satu solusi pembersih & mudah diimplementasikan
pengguna
5
Jawaban ini harus menjadi jawaban teratas !!! Ini benar-benar lebih bersih daripada solusi yang diusulkan Django! Kerja bagus @Charlesthk
David D.
4
Sangat membantu. Awalnya tidak jelas bagi saya, tetapi Anda dapat menggunakan ini untuk menambahkan beberapa kelas juga:{{ form.subject|addclass:'myclass1 myclass2' }}
smg
Saya suka ini memungkinkan menjaga kelas HTML dalam file HTML. Saat bekerja dengan gaya, saya melompat-lompat di antara lembar gaya dan struktur, bukan model dan / atau formulir.
Kevin
29

Jika Anda tidak ingin menambahkan kode apa pun ke formulir (seperti yang disebutkan dalam komentar di Jawaban @ shadfc), tentu saja mungkin, berikut adalah dua opsi.

Pertama, Anda hanya mereferensikan bidang secara individual dalam HTML, alih-alih seluruh formulir sekaligus:

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

(Perhatikan bahwa saya juga mengubahnya ke daftar yang tidak disortir .)

Kedua, perhatikan dalam dokumen tentang menghasilkan formulir sebagai HTML , Django:

Field id, dihasilkan dengan menambahkan 'id_' ke nama field. Atribut dan tag id termasuk dalam output secara default.

Semua bidang formulir Anda sudah memiliki id unik . Jadi Anda akan mereferensikan id_subject dalam file CSS Anda untuk menata bidang subjek . Saya harus perhatikan, ini adalah bagaimana berperilaku formulir ketika Anda mengambil HTML default , yang hanya membutuhkan mencetak formulir, bukan bidang individual:

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

Lihat tautan sebelumnya untuk opsi lain saat mengeluarkan formulir (Anda bisa membuat tabel, dll).

Catatan - Saya menyadari ini tidak sama dengan menambahkan kelas ke setiap elemen (jika Anda menambahkan bidang ke Formulir, Anda juga perlu memperbarui CSS) - tetapi cukup mudah untuk merujuk semua bidang dengan id di CSS Anda seperti ini:

#id_subject, #id_email, #email_message 
{color: red;}
John C
sumber
Saya mencoba solusi kedua Anda tetapi tidak berhasil. Saya membuat kelas untuk id_email dan gagal menghasilkan hasil apa pun.
Hampir seorang pemula
@almostabeginner satu hal yang bisa saya sarankan untuk debugging - setelah Anda melihat halaman di browser, gunakan View Page Source (umumnya dengan mengklik kanan), dan lihat halaman penuh sebenarnya yang dihasilkan Django. Lihat apakah ada bidang, dengan id atau pengidentifikasi kelas yang Anda harapkan. Juga sebagian besar browser (mungkin dengan menginstal sebuah plugin) dapat menjalankan debugger yang menunjukkan kepada Anda css yang diterapkan ke suatu halaman, juga membantu untuk melihat apa yang terjadi.
John C
@almostabeginner juga perhatikan, saya menambahkan sedikit kode sampel. Dalam hal itu tidak jelas dari teks saja - Anda harus merujuk formulir itu sendiri, bukan bidang individu, di mana titik otomatis menghasilkan HTML yang berisi id , seperti yang dijelaskan. Semoga itu bisa membantu.
John C
1
Terima kasih atas bantuannya, masalahnya bukan css saya sama sekali, masalah ini terkait dengan cache. Jadi css lama saya disimpan sehingga tidak ada perubahan yang akan ditampilkan. Saya baru saja membersihkan cache dari chrome dan semua pembaruan mulai muncul.
Hampir seorang pemula
15

Per posting blog ini , Anda dapat menambahkan kelas css ke bidang Anda menggunakan filter templat kustom.

from django import template
register = template.Library()

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

Letakkan ini di templatetag / folder aplikasi Anda dan sekarang Anda dapat melakukannya

{{field|addcss:"form-control"}}
Aashanand
sumber
2
ini seharusnya diterima sebagai jawaban nyata untuk posting ini :)
mvdb
Solusi terbaik sejauh ini.
Mods Vs Rockers
1
Cemerlang, terima kasih! Jangan lupa untuk benar-benar memuat tag. Juga, di Django 2.1 satu-satunya cara saya bisa mendapatkan Django untuk menemukan templat adalah dengan menambahkan opsi di settings.py: 'libraries': {'add_css': 'app.templatetags.tag_name',}
simonbogarde
11

Anda bisa melakukan ini:

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

Semoga itu berhasil.

Ignas

Ignas Butėnas
sumber
Terima kasih ignas. Jawaban yang tepat!
Rudresh Ajgaonkar
9

Anda dapat menggunakan perpustakaan ini: https://pypi.python.org/pypi/django-widget-tweaks

Ini memungkinkan Anda untuk melakukan hal berikut:

{% load widget_tweaks %}
<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}
Eamonn Faherty
sumber
1
Lihatlah solusi Charlesthk, itu sama tanpa menambahkan perpustakaan tambahan :)
David D.
@ Davidvid .: Ya, tetapi Widget Tweaks memiliki banyak filter lainnya, seperti render_field.
mrdaliri
5

Anda dapat melakukan:

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

Kemudian Anda dapat menambahkan kelas / id misalnya <td>tag. Tentu saja Anda dapat menggunakan tag orang lain yang Anda inginkan. Periksa Bekerja dengan formulir Django sebagai contoh apa yang tersedia untuk masing-masing fielddalam formulir ( {{field}}misalnya hanya mengeluarkan tag input, bukan label dan sebagainya).

Torsten Engelbrecht
sumber
3

Salah satu solusinya adalah menggunakan JavaScript untuk menambahkan kelas CSS yang diperlukan setelah halaman siap. Sebagai contoh, styling django form output dengan kelas bootstrap (jQuery digunakan untuk singkatnya):

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

Ini menghindari keburukan dari mencampur spesifik gaya dengan logika bisnis Anda.

Simon Feltman
sumber
3

Tulis formulir Anda seperti:

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

Di bidang HTML Anda, lakukan sesuatu seperti:

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

Kemudian di CSS Anda tulis sesuatu seperti:

.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 */
}

Semoga jawaban ini patut dicoba! Catatan Anda harus menulis pandangan Anda untuk membuat file HTML yang berisi formulir.

Aula
sumber
Terima kasih. tetapi bagaimana saya bisa menulis teks label tertentu?
gakeko betsi
2

Anda mungkin tidak perlu mengganti kelas formulir Anda __init__, karena Django menetapkan name& idatribut dalam HTML input. Anda dapat memiliki CSS seperti ini:

form input[name='subject'] {
    font-size: xx-large;
}
tehfink
sumber
1
Untuk menambah ini. Diberikan "subject = form ...", id = "id_subject" dan name = "subject" adalah konvensi Django untuk atribut ini. Karenanya, Anda juga dapat melakukan #id_subject {...}
solartic
@solartic: Anda benar, terima kasih. Saya tidak menyebutkan ini karena idbidang yang dibuat oleh Django untuk formets menjadi sangat berbulu ...
tehfink
2

Tidak melihat yang ini benar-benar ...

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

Output lebih granular

Metode as_p (), as_ul () dan as_table () hanyalah pintasan untuk pengembang yang malas - mereka bukan satu-satunya cara objek formulir dapat ditampilkan.

class BoundField Digunakan untuk menampilkan HTML atau mengakses atribut untuk bidang tunggal dari instance Form.

Metode str () ( unicode on Python 2) dari objek ini menampilkan HTML untuk bidang ini.

Untuk mengambil BoundField tunggal, gunakan sintaks pencarian kamus pada formulir Anda menggunakan nama bidang sebagai kunci:

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

Untuk mengambil semua objek BoundField, ulangi formulir:

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

Output khusus bidang menghormati pengaturan auto_id objek bentuk:

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

Ada sangat mudah untuk menginstal dan alat yang hebat yang dibuat untuk Django yang saya gunakan untuk styling dan dapat digunakan untuk setiap kerangka frontend seperti Bootstrap, Materialize, Foundation, dll. Ini disebut widget-tweaks Dokumentasi: Widget Tweaks

  1. Anda dapat menggunakannya dengan pandangan umum Django
  2. Atau dengan formulir Anda sendiri:

dari formulir impor Django

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

Alih-alih menggunakan default:

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

Anda dapat mengeditnya dengan cara Anda sendiri menggunakan atribut render_field yang memberi Anda cara styling yang lebih mirip html seperti contoh ini:

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>

Perpustakaan ini memberi Anda kesempatan untuk memisahkan ujung depan Anda dengan backend Anda

Alam Téllez
sumber
1

Dalam Django 1.10 (mungkin lebih awal juga) Anda dapat melakukannya sebagai berikut.

Model:

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

Bentuk:

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

Templat:

<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>
Ahli Psikis
sumber
0

Sunting: Cara lain (sedikit lebih baik) untuk melakukan apa yang saya sarankan dijawab di sini: Django membentuk style input field

Semua opsi di atas mengagumkan, hanya berpikir saya akan melemparkan yang ini karena berbeda.

Jika Anda ingin gaya kustom, kelas, dll pada formulir Anda, Anda bisa membuat input html di templat Anda yang cocok dengan bidang formulir Anda. Untuk CharField, misalnya, (widget default adalah TextInput), katakanlah Anda menginginkan input teks yang tampak seperti bootstrap. Anda akan melakukan sesuatu seperti ini:

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

Dan selama Anda memasukkan nama bidang formulir cocok dengan nameatribusi html , (dan widget mungkin perlu cocok dengan jenis input juga) Django akan menjalankan semua validator yang sama di bidang itu saat Anda menjalankan validateatauform.is_valid() dan

Mendesain hal-hal lain seperti label, pesan kesalahan, dan teks bantuan tidak memerlukan banyak solusi karena Anda dapat melakukan sesuatu seperti form.field.error.as_textdan gaya mereka seperti yang Anda inginkan. Bidang yang sebenarnya adalah bidang yang membutuhkan biola.

Saya tidak tahu apakah ini cara terbaik, atau cara saya akan merekomendasikan, tetapi ini adalah cara, dan itu mungkin tepat untuk seseorang.

Berikut adalah langkah-langkah berguna dari bentuk styling dan itu mencakup sebagian besar jawaban yang terdaftar di SO (seperti menggunakan attr pada widget dan tweak widget). https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html

kimbo
sumber
0

Contoh widget styling

Jika Anda ingin membuat satu instance widget terlihat berbeda dari yang lain, Anda harus menentukan atribut tambahan pada saat objek widget dipakai dan ditugaskan ke bidang formulir (dan mungkin menambahkan beberapa aturan ke file CSS Anda).

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

Untuk melakukan ini, Anda menggunakan argumen Widget.attrs saat membuat widget:

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

Anda juga dapat memodifikasi widget dalam definisi bentuk:

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

Atau jika bidang tidak dideklarasikan langsung pada formulir (seperti bidang formulir model), Anda dapat menggunakan atribut Form.fields:

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 kemudian akan menyertakan atribut tambahan dalam output yang diberikan:

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