Xác định lớp css trong biểu mẫu django


192

Giả sử tôi có một hình thức

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

Có cách nào để tôi xác định các lớp css trên mỗi trường để sau đó tôi có thể sử dụng jQuery dựa trên lớp trong trang được hiển thị của mình không?

Tôi đã hy vọng không phải tự xây dựng biểu mẫu.


9
wow, mọi người bình chọn cái này à? docs.djangoproject.com/en/dev/ref/forms/widgets/ khăn
Skylar Saveland

10
@skyl Tôi sẽ coi đó là một dấu hiệu cho thấy không dễ tìm thấy trong các tài liệu django. Tôi đã duyệt và thực hiện một số tìm kiếm trên google và không thể tìm thấy điều này, vì vậy tôi rất vui vì câu hỏi và nó nhận được sự ủng hộ của tôi.
Nils

Tôi biết đó là một chủ đề cũ nhưng trong các trường mẫu Django hiện có một lớp id_fieldname.
ratsimihah

1
Xem câu trả lời này về cách xác định các lớp cho trường biểu mẫu trong mẫu trong khi tôn trọng các lớp trường hiện có
dimyG

Câu trả lời:


182

Tuy nhiên, một giải pháp khác không yêu cầu thay đổi mã python và vì vậy tốt hơn cho các nhà thiết kế và thay đổi trình bày một lần: django-widget-chỉnh . Hy vọng ai đó sẽ tìm thấy nó hữu ích.


61
Các giải pháp lành mạnh duy nhất , tôi phải nói. Cảm ơn bạn!. Mã Python, và đặc biệt là trong định nghĩa của biểu mẫu, là nơi cuối cùng để đặt công cụ để tạo kiểu - những thứ này chắc chắn thuộc về các mẫu.
Boris Chervenkov

5
Đây là một thư viện tuyệt vời! Thật xấu hổ khi câu trả lời này bị chôn vùi dưới đáy.
Chris Lacasse

1
Tuyệt vời cho các nhà thiết kế! :-)
hobbes3

1
Thông minh! Tôi đã phát triển một số bộ lọc để làm những thứ này, nhưng dự án này mạnh hơn nhiều. Cảm ơn!
msbrogli

1
trên thực tế, nó cũng hoạt động với Jinja2 :-) Tôi đã thay đổi thứ tự của fileter an toàn và thêm dấu ngoặc đơn thay vì dấu hai chấm {{myform.email | add_group ("css_group_1 css_group_2") | safe}} cảm ơn vì đã viết bài này. nó nên là một phần của Django.
David Deh Afghanistan

92

Trả lời câu hỏi của riêng tôi. Thở dài

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

Tôi không nhận ra nó đã được chuyển vào hàm tạo widget.


2
điều đó có nghĩa là nó không thể được sử dụng với lớp ModelForm?
xster

2
Không, bạn chỉ cần xác định rõ ràng trường biểu mẫu trong biểu mẫu mô hình để bạn có thể xác định tiện ích con. Hoặc sử dụng giải pháp được liệt kê dưới đây để tránh phải muck với trường mẫu.
Tom

78

Đây là một giải pháp khác để thêm các định nghĩa lớp vào các widget sau khi khai báo các trường trong lớp.

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

4
Đối với ModelForms, điều này thường tốt hơn vì bạn không cần phải biết trường biểu mẫu mặc định đang được sử dụng và bạn có thể tự động thiết lập các lớp khác nhau dựa trên các điều kiện thời gian chạy. Sạch hơn so với hack mã hóa meta ...
Daniel Naab

1
Điều đó giả định rằng bạn muốn có một đầu vào cho mọi trường trong một biểu mẫu, thường không phải là trường hợp. Một hình thức không nhất thiết phải gắn với một mô hình - nó có thể được gắn với nhiều mô hình. Trong trường hợp các trường mô hình và các trường biểu mẫu có mối quan hệ 1: 1, thì có, ModelForm là một lựa chọn tốt hơn nhiều.
ashchristopher

44

Sử dụng django-widget-chỉnh , nó rất dễ sử dụng và hoạt động khá tốt.

Nếu không, đ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 bạn 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 }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subject là một thể hiện của BoundField trong đó có các as_widget phương pháp.

bạn có thể tạo bộ lọc tùy chỉnh "addcss" trong "my_app / templatetags / myfilters.py"

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

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 }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

form.subjects sau đó sẽ được kết xuất với lớp css "MyClass".

Hy vọng điều này giúp đỡ.

CHỈNH SỬA 1

  • Cập nhật bộ lọc theo câu trả lời của dimyG

  • Thêm liên kết django-widget-chỉnh

CHỈNH SỬA 2

  • Cập nhật bộ lọc theo nhận xét của Bhyd

3
Điều đó thật tuyệt! Đó là DRY và nó tách lớp hiển thị khỏi lớp điều khiển. +1 từ tôi!
alekwisnia

1
Tuy nhiên, bây giờ tôi đã nhận thấy một nhược điểm. Nếu tôi định nghĩa lớp trong attrs widget, thì chúng bị ghi đè bởi bộ lọc 'addcss' này. Bạn có bất cứ ý tưởng làm thế nào để hợp nhất đó?
alekwisnia

1
Ý tôi là, as_widget () ghi đè attrs. Làm thế nào để đảm bảo nó sử dụng attrs hiện có và mở rộng chúng với cái mới?
alekwisnia

Xem câu trả lời này về cách tôn trọng các lớp hiện tại
dimyG

get('class', None).split(' ')sẽ thất bại nếu thẻ không có thuộc tính lớp, như Noneđược trả về. Thay đổi nó thành get('class', '').split(' ')hoạt động
dtasev

32

Mở rộng về phương thức được trỏ đến tại docs.djangoproject.com:

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

Tôi nghĩ thật rắc rối khi phải biết loại widget gốc cho mọi trường và nghĩ thật buồn cười khi ghi đè mặc định chỉ để đặt tên lớp trên trường biểu mẫu. Điều này dường như làm việc cho tôi:

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'

Điều này có vẻ sạch sẽ hơn với tôi.


Đây chính xác là những gì người khác đã nói, từ rất lâu rồi, ngoại trừ việc bạn đang thực hiện nó với "kích thước" chứ không phải "lớp" được yêu cầu.
Chris Morgan

3
@Chris Morgan Trên thực tế, anh ấy là người đầu tiên đề xuất sử dụng "comment.widget.attrs" trong chính khai báo Biểu mẫu (thay vì gây rối với init hoặc thực hiện trong chế độ xem).
DarwinSurvivor

29

Nếu bạn muốn tất cả các trường trong biểu mẫu kế thừa một lớp nhất định, bạn chỉ cần xác định một lớp cha, kế thừa từ đó forms.ModelForm, và sau đó kế thừa từ nó

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

Điều này giúp tôi tự động thêm 'form-control'lớp vào tất cả các trường trên tất cả các biểu mẫu của ứng dụng của mình mà không cần thêm bản sao mã.


1
vui lòng bắt đầu tên lớp bằng chữ hoa (ngoài ra, BaseForm có vẻ như là tên tốt hơn cho nó)
Alvaro

16

Đây là cách đơn giản để thay đổi trong xem. thêm bên dưới trong chế độ xem ngay trước khi chuyển nó vào mẫu.

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

14

Đơn giản chỉ cần thêm các lớp vào mẫu của bạn như sau.

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

Đây là một biến thể ở trên sẽ cung cấp cho tất cả các trường cùng một lớp (ví dụ: các góc tròn đẹp của jquery).

  # 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

Bạn có thể thử điều này ..

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

Bạn có thể xem thêm thông tin trong: Django Widgets


2

Trong trường hợp bạn muốn thêm một lớp vào trường của biểu mẫu trong một mẫu (không phải trong view.py hoặc form.py), ví dụ trong trường hợp bạn muốn sửa đổi ứng dụng của bên thứ 3 mà không ghi đè chế độ xem của chúng, thì bộ lọc mẫu như được mô tả trong câu trả lời của Charlerak rất thuận tiện. Nhưng trong câu trả lời này, bộ lọc mẫu sẽ ghi đè bất kỳ lớp hiện có nào mà trường có thể có.

Tôi đã cố gắng thêm nó dưới dạng chỉnh sửa nhưng nó được đề nghị viết thành một câu trả lời mới.

Vì vậy, đây là một thẻ mẫu tôn trọng các lớp hiện có của trường:

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

Cảm ơn đề nghị của bạn. Tôi đã chỉnh sửa câu trả lời của mình theo cách tiếp cận "pythonic" hơn.
Charlerak

tuyệt vời !!, đó là những gì tôi đang tìm kiếm
ugali mềm

1

Hóa ra bạn có thể làm điều này trong hàm tạo biểu mẫu ( hàm init ) hoặc sau khi lớp biểu mẫu được bắt đầu. Điều này đôi khi được yêu cầu nếu bạn không viết biểu mẫu của riêng bạn và biểu mẫu đó đến từ nơi khác -

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

Bạn cũng có thể sử dụng Django Crispy Forms , đây là một công cụ tuyệt vời để xác định các biểu mẫu trong trường hợp bạn muốn sử dụng một số khung CSS như Bootstrap hoặc Foundation. Và thật dễ dàng để chỉ định các lớp cho các trường mẫu của bạn ở đó.

Lớp mẫu của bạn sẽ thích điều này sau đó:

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