Django formlarında CSS stili


159

Aşağıdakileri şekillendirmek istiyorum:

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>

Örneğin, nasıl bir ayarlarım sınıf veya kimliği için subject, email, messageharici stil sayfası sağlamak için?

Yanıtlar:


202

: Cevabım Alınan <div class = 'field_type'> Django ile form alanları biçimlendirme nasıl

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

veya

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

veya

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

--- DÜZENLE ---
Yukarıdakiler, sorulan şeyi gerçekleştiren orijinal soru kodunda yapılacak en kolay değişikliktir. Ayrıca formu başka yerlerde tekrar kullanırsanız kendinizi tekrarlamaktan da alıkoyar; Django'nun as_table / as_ul / as_p form yöntemlerini kullanırsanız sınıflarınız veya diğer öznitelikleriniz çalışır. Tamamen özel bir işleme için tam kontrole ihtiyacınız varsa, bu açıkça belgelenmiştir

- DÜZENLEME 2 ---
Bir ModelForm için pencere öğesi ve öznitelikleri belirtmenin daha yeni bir yolu eklendi.


29
Sunumun iş mantığı ile karıştırılması tavsiye edilmez.
Torsten Engelbrecht

8
Bu sunum nasıl? Öğeye, yalnızca bir tanımlayıcı veya sınıflandırma olan bir sınıf veriyorsunuz. Bunun başka yerde ne yaptığını hala tanımlamalısın
shadfc

9
Evet ve hayır. İlk CSS sınıfları, geleneksel olarak stil için kullanılır, benzersiz bir tanımlayıcıya ihtiyacınız varsa, kullanmak daha iyidir id. İkincisi, genellikle şablon tarafının bunu tam olarak yapma sorumluluğu, özellikle bu sınıfa ön uç yöntemleri (js, css) ile erişecekseniz. Cevabınızın yanlış olduğunu söylemedim. Bana göre bu kötü bir uygulama (özellikle ön uç ve arka uç geliştiricileriyle bir ekipte çalışırken).
Torsten Engelbrecht

7
Bu çok saçma görünüyor, sadece bir sınıf eklemek için bu kadar koda mı ihtiyacınız var? Bu alanlarda (özellikle CSS ağırlıklı bir site için) HTML / CSS'yi sabit kodlamak daha kolay gibi görünüyor.
David542

12
Bu çılgınca django bunu çok garip yapıyor!
Bryce

107

Bu, özel bir şablon filtresi kullanılarak yapılabilir. Formunuzu şu şekilde oluşturmayı düşünün:

<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.subjectyöntemi BoundFieldolan bir örnektir as_widget().

My_app / templatetags / myfilters.pyaddclass içinde özel bir filtre oluşturabilirsiniz :

from django import template

register = template.Library()

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

Ve sonra filtrenizi uygulayın:

{% 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.subjectsdaha sonra MyClassCSS sınıfı ile işlenecektir .


5
Bu temizleyici ve çözümleri uygulamak çok kolay biridir
kullanıcı

5
Bu cevap en iyi cevap olmalı !!! Django'nun önerdiği çözümden gerçekten daha temiz! Tebrikler @Charlesthk
David D.

5
Çok yardımcı oldu. İlk başta bana açık değildi, ancak bunu birden fazla sınıf eklemek için de kullanabilirsiniz:{{ form.subject|addclass:'myclass1 myclass2' }}
smg

Bunun HTML sınıflarının HTML dosyalarında tutulmasına izin vermesi hoşuma gidiyor. Stil ile çalışırken, modeller ve / veya formlar arasında değil, stil sayfaları ve yapı arasında gidip gelirim.
Kevin

Bu yöntem ile, bir sorun, bu filtre dönüştürür olmasıdır BoundFieldINTO SafeString, bu yüzden diğer (benzer) filtreleri zincirli edilemez. django-widget-tweaksdaha sağlam bir çözüm olması için alanları döndürür.
eksi

30

Forma herhangi bir kod eklemek istemiyorsanız (@ shadfc'nin Cevabına yapılan yorumlarda belirtildiği gibi), kesinlikle mümkündür, işte iki seçenek.

İlk olarak, tek seferde formun tamamı yerine HTML'deki alanlara tek tek başvurursunuz:

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

(Ayrıca sıralanmamış bir liste olarak değiştirdiğimi de unutmayın .)

İkinci olarak, formların çıktısını HTML , Django olarak almakla ilgili dokümanlardaki not :

Alan kimliği, Alan adının başına 'id_' eklenerek oluşturulur. İd nitelikleri ve etiketleri varsayılan olarak çıktıya dahil edilir.

Tüm form alanlarınızın zaten benzersiz bir kimliği var . Dolayısıyla , konu alanını biçimlendirmek için CSS dosyanızda id_subject'e başvurursunuz . Unutmamalıyım, varsayılan HTML'yi aldığınızda formun nasıl davrandığı , tek tek alanları değil, yalnızca formu yazdırmayı gerektirir:

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

Formların çıktısını alırken diğer seçenekler için önceki bağlantıya bakın (tablolar vb. Yapabilirsiniz).

Not - Bunun her öğeye bir sınıf eklemekle aynı olmadığını anlıyorum (Forma bir alan eklediyseniz, CSS'yi de güncellemeniz gerekir) - ancak tüm alanlara id ile başvurmak yeterince kolaydır CSS'nizde şöyle:

#id_subject, #id_email, #email_message 
{color: red;}

İkinci çözümünüzü denedim ama işe yaramadı. İd_email için sınıf oluşturdum ve herhangi bir sonuç üretemedi.
neredeyse başlangıç ​​seviyesi

@almostabeginner hata ayıklama için önerebileceğim bir şey - sayfayı bir tarayıcıda gördüğünüzde Sayfa Kaynağını Görüntüle'yi kullanın (genellikle sağ tıklayarak) ve Django'nun oluşturduğu gerçek tam sayfaya bakın. Alanların, beklediğiniz kimlik veya sınıf tanımlayıcıyla var olup olmadığına bakın . Ayrıca çoğu tarayıcı (muhtemelen bir eklenti yükleyerek) bir sayfaya uygulanan css'yi gösteren bir hata ayıklayıcı çalıştırabilir ve neler olup bittiğini görmenize de yardımcı olur.
John C

@almostabeginner ayrıca, biraz örnek kod ekledim. Tek başına metinden anlaşılamaması durumunda - tek tek alanlara değil formun kendisine başvurmanız gerekir; bu noktada form , açıklandığı gibi , kimlikleri içeren HTML'yi otomatik olarak oluşturur . Umarım bu yardımcı olur.
John C

1
Yardım için teşekkürler, sorun benim css'im değildi, sorun önbellekle ilgiliydi. Yani eski css'im depolandı, bu nedenle değişikliklerin hiçbiri görüntülenmedi. Önbelleği kromdan temizledim ve tüm güncellemeler gösterilmeye başladı.
neredeyse başlangıç ​​seviyesi

16

Başına bu blog yayınında, özel bir şablon filtresi kullanarak alanlara css sınıfları ekleyebilir.

from django import template
register = template.Library()

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

Bunu uygulamanızın templatetags / klasörüne koyun ve şimdi yapabilirsiniz

{{field|addcss:"form-control"}}

3
bu, bu
yazının

1
Şimdiye kadar en iyi çözüm.
Mods Vs Rockers

1
Harika, teşekkürler! Etiketi gerçekten yüklemeyi unutmayın. Ayrıca Django 2.1'de Django'nun şablonu bulmasını sağlamamın tek yolu settings.py: 'libraries': {'add_css': 'app.templatetags.tag_name',}
simonbogarde

Bu gerçekten şimdiye kadarki en basit ve en iyi çözüm.
Sherd

11

Bunu beğenebilirsin:

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

Umarım işe yarar.

Ignas


Teşekkürler ignas. Kesin cevap!
Rudresh Ajgaonkar

9

Bu kitaplığı kullanabilirsiniz: https://pypi.python.org/pypi/django-widget-tweaks

Aşağıdakileri yapmanızı sağlar:

{% load widget_tweaks %}
<!-- add 2 extra css classes to field element -->
{{ form.title|add_class:"css_class_1 css_class_2" }}

1
Charlesthk çözümüne bir göz atın, fazladan bir kitaplık eklemeden de aynı şey :)
David D.

@DavidW .: Evet, ancak Widget Tweaks gibi birçok filtreye sahip render_field.
mrdaliri

Charlesthk çözeltisi dönüştürür BoundFieldINTO SafeString, bu yüzden diğer (benzer) filtreleri zincirli edilemez. django-widget-tweaksdaha sağlam bir çözüm olması için alanları döndürür.
eksi

5

Yapabilirsin:

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

Daha sonra, örneğin <td>etikete sınıflar / id'ler ekleyebilirsiniz . Elbette istediğiniz diğer etiketleri de kullanabilirsiniz. Kontrol Django formları ile Çalışma her biri için mevcut olanı örnek olarak field(formda {{field}}örneğin sadece giriş etiketini değil, etiket ve benzeri çıktısı).


4

Formunuzu şöyle yazın:

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

HTML alanınızda şuna benzer bir şey yapın:

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

Ardından CSS'nizde şöyle bir şey yazın:

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

Umarım bu cevap denemeye değerdir! Formu içeren HTML dosyasını oluşturmak için görünümlerinizi yazmış olmanız gerektiğini unutmayın.


Teşekkürler. ancak belirli bir etiket metnini nasıl yazabilirim?
gakeko betsi

3

Bunu gerçekten görmedim ...

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

Daha ayrıntılı çıktı

As_p (), as_ul () ve as_table () yöntemleri tembel geliştiriciler için kısayollardır - bir form nesnesinin görüntülenmesinin tek yolu bunlar değildir.

class BoundField Bir Form örneğinin tek bir alanı için HTML'yi görüntülemek veya niteliklere erişmek için kullanılır.

Str () ( unicode bu nesne görüntüler bu alan için HTML yöntemine Python 2).

Tek bir BoundField almak için, alan adını anahtar olarak kullanarak formunuzda sözlük arama sözdizimini kullanın:

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

Tüm BoundField nesnelerini almak için formu yineleyin:

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

Alana özgü çıktı, form nesnesinin auto_id ayarına uygundur:

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

3

Çözümlerden biri, sayfa hazır olduktan sonra gerekli CSS sınıflarını eklemek için JavaScript kullanmaktır. Örneğin, django form çıktısının önyükleme sınıfları ile stilize edilmesi (kısalık için jQuery kullanılır):

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

Bu, stil özelliklerini iş mantığınızla karıştırmanın çirkinliğini önler.


2

Form sınıfınızı geçersiz kılmanız gerekmeyebilir __init__, çünkü Django HTML’lerde name& idöznitelikleri ayarlar input. Bunun gibi CSS'ye sahip olabilirsiniz:

form input[name='subject'] {
    font-size: xx-large;
}

1
Buna eklemek için. Verilen "konu = formlar ...", id = "id_subject" ve name = "konu", bu öznitelikler için Django kuralıdır. Bu nedenle, #id_subject {...}
solartic

@solartic: Haklısın, teşekkürler. Bundan bahsetmedim çünkü idDjango'nun
form setleri

2

Django için kurulumu çok kolay ve harika bir araç var ve bu araç Bootstrap, Materialize, Foundation vb. Gibi her ön uç çerçevesi için kullanılabilir. Buna widget-tweaks adı verilir Belgeleme: Widget Tweaks

  1. Django'nun genel görünümleriyle kullanabilirsiniz.
  2. Veya kendi formlarınızla:

django içe aktarma formlarından

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

Varsayılanı kullanmak yerine:

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

Bu örnekte olduğu gibi size daha html benzeri bir biçimlendirme sağlayan render_field özelliğini kullanarak bunu kendi yönteminizle düzenleyebilirsiniz:

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>

Bu kütüphane, ön ucunuzu arka ucunuzdan iyice ayırma fırsatı verir.


1

Django 1.10'da (muhtemelen daha önce de) bunu aşağıdaki gibi yapabilirsiniz.

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

Form:

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

Şablon:

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

0

Düzenleme: Önerdiğim şeyi yapmanın başka bir (biraz daha iyi) yolu burada yanıtlanıyor: Django form girdi alanı stili

Yukarıdaki tüm seçenekler harika, sadece farklı olduğu için bunu atayım dedim.

Formlarınızda özel stil, sınıflar vb. İstiyorsanız, şablonunuzda form alanınızla eşleşen bir html girişi yapabilirsiniz. Örneğin, bir CharField için (varsayılan widget TextInput), önyükleme görünümlü bir metin girişi istediğinizi varsayalım . Bunun gibi bir şey yaparsınız:

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

Ve form alanı adını html nameniteliğiyle eşleştirdiğiniz sürece (ve widget muhtemelen giriş tipiyle de eşleşmelidir) Django, çalıştırdığınızda o alanda aynı doğrulayıcıları çalıştırır validateveya form.is_valid()ve

Etiketler, hata mesajları ve yardım metni gibi diğer şeyleri biçimlendirmek çok geçici çözüm gerektirmez çünkü istediğiniz gibi form.field.error.as_textbunları yapabilir ve onlara stil verebilirsiniz. Gerçek alanlar, biraz uğraşmayı gerektiren alanlardır.

Bunun en iyi yol mu, yoksa benim önereceğim yol mu olduğunu bilmiyorum, ama bu bir yol ve birisi için doğru olabilir.

İşte şekillendirme formları için faydalı bir adım adım açıklamalı kılavuz ve SO'da listelenen yanıtların çoğunu içerir (örneğin, widget'larda ve widget ayarlarında attr'ı kullanma). https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html


0

Widget örneklerinin stilini belirleme

Bir pencere öğesi örneğinin diğerinden farklı görünmesini istiyorsanız, pencere öğesi nesnesinin somutlaştırıldığı ve bir form alanına atandığı sırada ek nitelikler belirlemeniz (ve belki de CSS dosyalarınıza bazı kurallar eklemeniz) gerekir.

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

Bunu yapmak için, pencere öğesini oluştururken Widget.attrs argümanını kullanırsınız:

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

Ayrıca, form tanımındaki bir pencere öğesini de değiştirebilirsiniz:

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

Veya alan doğrudan form üzerinde bildirilmezse (model form alanları gibi), Form.fields özniteliğini kullanabilirsiniz:

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 daha sonra işlenen çıktıya ekstra nitelikleri dahil edecektir:

>>> 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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.