Kiểu CSS ở dạng Django


150

Tôi muốn tạo kiểu như sau:

biểu mẫu:

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>

Ví dụ, làm thế nào để tôi đặt một lớp hoặc ID cho subject, email, messageđể cung cấp một style sheet bên ngoài để?

Câu trả lời:


192

Lấy từ câu trả lời của tôi để: Cách đánh dấu các trường mẫu bằng <div class = 'field_type'> trong Django

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

hoặc là

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

hoặc là

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

--- EDIT ---
Trên đây là thay đổi dễ dàng nhất để thực hiện mã của câu hỏi ban đầu để thực hiện những gì đã được hỏi. Nó cũng giúp bạn không lặp lại chính mình nếu bạn sử dụng lại biểu mẫu ở những nơi khác; các lớp của bạn hoặc các thuộc tính khác chỉ hoạt động nếu bạn sử dụng các phương thức biểu mẫu as_table / as_ul / as_p của Django. Nếu bạn cần toàn quyền kiểm soát để hiển thị hoàn toàn tùy chỉnh, điều này được ghi lại rõ ràng

- EDIT 2 ---
Đã thêm một cách mới hơn để chỉ định widget và attrs cho ModelForm.


27
Mặc dù không nên kết hợp trình bày với logic kinh doanh.
Torsten Engelbrecht

8
Bài thuyết trình này thế nào? Bạn đang cung cấp cho phần tử một lớp, đây chỉ là một định danh hoặc phân loại. Bạn vẫn phải xác định những gì làm ở nơi khác
shadfc

9
Có và không. Các lớp CSS đầu tiên theo quy ước được sử dụng để tạo kiểu, nếu bạn cần một mã định danh duy nhất thì tốt hơn để sử dụng id. Thứ hai, nó thường là khuôn mẫu có trách nhiệm thực hiện việc này, đặc biệt nếu bạn sẽ truy cập lớp này thông qua các phương thức frontend (js, css). Tôi không nói câu trả lời của bạn là sai. Theo tôi đó chỉ là thực tiễn tồi tệ (đặc biệt là khi bạn làm việc trong một nhóm với các nhà phát triển frontend và backend).
Torsten Engelbrecht

6
Điều này có vẻ vô lý, chỉ cần thêm một lớp bạn cần nhiều mã này? Dường như việc mã hóa HTML / CSS trong các lĩnh vực này trở nên dễ dàng hơn (đặc biệt đối với một trang web nặng CSS).
David542

9
Đó là django điên rồ làm cho điều này rất khó xử!
Bryce

103

Điều này có thể được thực hiện bằng cách sử dụng bộ lọc mẫu tùy chỉnh. Xem xét kết xuất biểu mẫu của bạn theo cách này:

<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.subjectlà một ví dụ trong BoundFieldđó có as_widget()phương thức.

Bạn có thể tạo bộ lọc tùy chỉnh addclasstrong 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})

Và sau đó áp dụng bộ lọc của bạ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.subjectssau đó sẽ được kết xuất với MyClasslớp CSS.


5
Đây là một trong những giải pháp dễ thực hiện và dễ thực hiện hơn
người dùng

5
Câu trả lời này nên là câu trả lời hàng đầu !!! Nó thực sự sạch hơn giải pháp đề xuất Django! Làm tốt lắm @Charlểk
David D.

4
Siêu hữu ích. Ban đầu tôi không rõ ràng, nhưng bạn cũng có thể sử dụng điều này để thêm nhiều lớp:{{ form.subject|addclass:'myclass1 myclass2' }}
smg

Tôi thích điều này cho phép giữ các lớp HTML trong các tệp HTML. Khi làm việc với kiểu dáng, tôi nhảy qua lại giữa các bảng định kiểu và cấu trúc, không phải mô hình và / hoặc biểu mẫu.
Kevin

29

Nếu bạn không muốn thêm bất kỳ mã vào biểu mẫu (như được đề cập trong các nhận xét cho Câu trả lời của @ shadfc), thì chắc chắn là có thể, đây là hai tùy chọn.

Trước tiên, bạn chỉ cần tham chiếu các trường riêng lẻ trong HTML, thay vì toàn bộ biểu mẫu cùng một lúc:

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

(Lưu ý rằng tôi cũng đã thay đổi nó thành một danh sách chưa sắp xếp .)

Thứ hai, lưu ý trong các tài liệu về việc xuất các biểu mẫu dưới dạng HTML , Django:

Id trường, được tạo bằng cách thêm 'id_' vào tên trường. Các thuộc tính và thẻ id được bao gồm trong đầu ra theo mặc định.

Tất cả các trường mẫu của bạn đã có một id duy nhất . Vì vậy, bạn sẽ tham chiếu id_subject trong tệp CSS của mình để định kiểu trường chủ đề . Tôi nên lưu ý, đây là cách biểu mẫu ứng xử khi bạn thực hiện HTML mặc định , yêu cầu chỉ in biểu mẫu, không phải các trường riêng lẻ:

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

Xem liên kết trước để biết các tùy chọn khác khi xuất các biểu mẫu (bạn có thể thực hiện các bảng, v.v.).

Lưu ý - Tôi nhận ra điều này không giống với việc thêm một lớp cho mỗi thành phần (nếu bạn đã thêm một trường vào Biểu mẫu, bạn cũng cần cập nhật CSS) - nhưng nó đủ dễ để tham chiếu tất cả các trường theo id trong CSS của bạn như thế này:

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

Tôi đã thử giải pháp thứ hai của bạn nhưng nó không hoạt động. Tôi đã tạo lớp cho id_email và nó không tạo ra kết quả nào.
gần như là người mới bắt đầu

@al Maximumabeginner một điều tôi có thể đề xuất để gỡ lỗi - một khi bạn thấy trang trong trình duyệt, hãy sử dụng Xem trang Nguồn (nói chung bằng cách nhấp chuột phải) và xem trang đầy đủ thực tế mà Django đang tạo. Xem nếu các trường tồn tại, với định danh id hoặc lớp mà bạn mong đợi. Ngoài ra, hầu hết các trình duyệt (có thể bằng cách cài đặt plugin) có thể chạy trình gỡ lỗi hiển thị cho bạn css được áp dụng cho một trang, cũng hữu ích để xem những gì đang diễn ra.
John C

@al ultraabeginner cũng lưu ý, tôi đã thêm một chút mã mẫu. Trong trường hợp không rõ ràng từ văn bản một mình - bạn phải tham chiếu chính biểu mẫu, không phải các trường riêng lẻ, tại thời điểm đó, biểu mẫu tự động tạo HTML có chứa id , như được mô tả. Hy vọng rằng sẽ giúp.
John C

1
Cảm ơn sự giúp đỡ, vấn đề không phải là css của tôi, vấn đề liên quan đến bộ đệm. Vì vậy, css cũ của tôi đã được lưu trữ do đó không có thay đổi nào sẽ hiển thị. Tôi vừa xóa bộ nhớ cache từ chrome và tất cả các bản cập nhật bắt đầu hiển thị.
gần như là người mới bắt đầu

15

Mỗi bài đăng trên blog này , bạn có thể thêm các lớp css vào các trường của mình bằng bộ lọc mẫu tùy chỉnh.

from django import template
register = template.Library()

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

Đặt cái này vào templatetags / thư mục của ứng dụng của bạn và bây giờ bạn có thể làm

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

2
điều này nên được chấp nhận như là câu trả lời thực sự cho bài đăng này :)
mvdb

Giải pháp tốt nhất cho đến nay.
Mods Vs Rockers

1
Rực rỡ, cảm ơn! Đừng quên thực sự tải thẻ. Ngoài ra, trong Django 2.1 cách duy nhất tôi có thể khiến Django tìm thấy mẫu là bằng cách thêm một tùy chọn trong settings.py: 'library': {'add_css': 'app.templatetags.tag_name',}
simonbogarde

11

Bạn có thể làm như thế này:

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

Hy vọng rằng hoạt động.

Bỏ qua


Cảm ơn Ignas. Câu trả lời chính xác!
Rudresh Ajgaonkar

9

Bạn có thể sử dụng thư viện này: https://pypi.python.org/pypi/django-widget-tweaks

Nó cho phép bạn làm như sau:

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

1
Hãy xem giải pháp Charlểk, nó giống nhau mà không cần thêm thư viện :)
David D.

@DavidW.: Có, nhưng Widget Tweaks có nhiều bộ lọc hơn, chẳng hạn như render_field.
mrdaliri

5

Bạn có thể làm:

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

Sau đó, bạn có thể thêm các lớp / id để ví dụ <td>thẻ. Tất nhiên bạn có thể sử dụng bất kỳ thẻ nào khác mà bạn muốn. Kiểm tra Làm việc với các biểu mẫu Django làm ví dụ những gì có sẵn cho mỗi fieldbiểu mẫu ( {{field}}ví dụ: chỉ xuất ra thẻ đầu vào, không phải nhãn và vv).


3

Một giải pháp là sử dụng JavaScript để thêm các lớp CSS cần thiết sau khi trang sẵn sàng. Ví dụ: tạo kiểu đầu ra biểu mẫu django với các lớp bootstrap (jQuery được sử dụng cho ngắn gọn):

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

Điều này tránh sự xấu xí của việc trộn các chi tiết cụ thể với logic kinh doanh của bạn.


3

Viết biểu mẫu của bạn như sau:

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

Trong trường HTML của bạn, hãy làm một cái gì đó như:

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

Sau đó, trong CSS của bạn viết một cái gì đó như:

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

Hy vọng câu trả lời này là đáng thử! Lưu ý rằng bạn phải viết các quan điểm của mình để hiển thị tệp HTML có chứa biểu mẫu.


Cảm ơn. nhưng làm thế nào tôi có thể viết một văn bản nhãn cụ thể?
gakeko betsi

2

Bạn có thể không cần ghi đè lớp biểu mẫu của mình ' __init__, vì Django đặt name& idthuộc tính trong HTML inputs. Bạn có thể có CSS ​​như thế này:

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

1
Để thêm vào điều này. Cho "chủ đề = biểu mẫu ...", id = "id_subject" và name = "chủ đề" là quy ước Django cho các thuộc tính này. Do đó, bạn cũng có thể thực hiện #id_subject {...}
solartic

@solartic: Bạn nói đúng, cảm ơn. Tôi đã không đề cập đến điều này bởi vì idtrường được tạo bởi Django cho các bộ định dạng có nhiều lông
tehfink

2

Không thấy cái này thực sự ...

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

Đầu ra chi tiết hơn

Các phương thức as_p (), as_ul () và as_table () chỉ đơn giản là các phím tắt cho các nhà phát triển lười biếng - chúng không phải là cách duy nhất một đối tượng biểu mẫu có thể được hiển thị.

class BoundField Được sử dụng để hiển thị HTML hoặc truy cập các thuộc tính cho một trường của một thể hiện Form.

Phương thức str () ( unicode trên Python 2) của đối tượng này hiển thị HTML cho trường này.

Để truy xuất một BoundField duy nhất, hãy sử dụng cú pháp tra cứu từ điển trên biểu mẫu của bạn bằng cách sử dụng tên của trường làm khóa:

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

Để lấy tất cả các đối tượng BoundField, hãy lặp lại biểu mẫu:

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

Đầu ra dành riêng cho trường tôn vinh cài đặt auto_id của đối tượng biểu mẫu:

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

2

Có một công cụ rất dễ cài đặt và tuyệt vời được tạo cho Django mà tôi sử dụng để tạo kiểu và nó có thể được sử dụng cho mọi khung công tác như Bootstrap, Materialize, Foundation, v.v. Nó được gọi là widget-chỉnh sửa Tài liệu: Widget Tweaks

  1. Bạn có thể sử dụng nó với quan điểm chung của Django
  2. Hoặc với các hình thức của riêng bạn:

từ các hình thức nhập khẩu django

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

Thay vì sử dụng mặc định:

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

Bạn có thể chỉnh sửa nó theo cách riêng của mình bằng cách sử dụng thuộc tính render_field cung cấp cho bạn cách tạo kiểu giống như html hơn như ví dụ này:

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>

Thư viện này cung cấp cho bạn cơ hội để tách biệt giao diện người dùng với phần cuối của bạn


1

Trong Django 1.10 (có thể sớm hơn) bạn có thể làm như sau.

Mô hình:

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

Hình thức:

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

Bản mẫu:

<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

Chỉnh sửa: Một cách khác (tốt hơn một chút) để thực hiện những gì tôi đề xuất được trả lời ở đây: Kiểu mẫu trường nhập của Django

Tất cả các tùy chọn trên đều tuyệt vời, chỉ cần nghĩ rằng tôi sẽ ném cái này vì nó khác.

Nếu bạn muốn tạo kiểu tùy chỉnh, các lớp, v.v. trên biểu mẫu của mình, bạn có thể tạo đầu vào html trong mẫu phù hợp với trường biểu mẫu của bạn. Ví dụ, đối với CharField, (tiện ích mặc định là TextInput), giả sử bạn muốn có một kiểu nhập văn bản trông giống bootstrap. Bạn sẽ làm một cái gì đó như thế này:

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

Và miễn là bạn đặt tên trường biểu mẫu khớp với biểu thức html name, (và tiện ích cũng có thể cần phải khớp với kiểu nhập) Django sẽ chạy tất cả các trình xác nhận tương tự trên trường đó khi bạn chạy validatehoặc form.is_valid()

Tạo kiểu cho những thứ khác như nhãn, thông báo lỗi và văn bản trợ giúp không yêu cầu nhiều cách giải quyết vì bạn có thể làm điều gì đó thích form.field.error.as_textvà tạo kiểu cho chúng theo cách bạn muốn. Các lĩnh vực thực tế là những người đòi hỏi một số khó khăn.

Tôi không biết đây là cách tốt nhất hay cách tôi muốn giới thiệu, nhưng đó là một cách, và nó có thể phù hợp với ai đó.

Đây là một hướng dẫn hữu ích của các biểu mẫu kiểu dáng và nó bao gồm hầu hết các câu trả lời được liệt kê trên SO (như sử dụng attr trên các widget và chỉnh sửa widget). https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manual.html


0

Các trường hợp widget kiểu dáng

Nếu bạn muốn làm cho một cá thể widget trông khác với một thể hiện khác, bạn sẽ cần chỉ định các thuộc tính bổ sung tại thời điểm khi đối tượng widget được khởi tạo và được gán cho một trường biểu mẫu (và có thể thêm một số quy tắc vào các tệp CSS của bạn).

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

Để thực hiện việc này, bạn sử dụng đối số Widget.attrs khi tạo tiện ích:

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

Bạn cũng có thể sửa đổi một widget trong định nghĩa biểu mẫu:

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

Hoặc nếu trường không được khai báo trực tiếp trên biểu mẫu (chẳng hạn như trường mẫu biểu mẫu), bạn có thể sử dụng thuộc tính 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 sau đó sẽ bao gồm các thuộc tính bổ sung trong đầu ra được kết xuất:

>>> 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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.