2011-09-26 28 views
14

Tôi có trường mẫu này:Làm thế nào để tôi có được các biểu mẫu Django để hiển thị thuộc tính yêu cầu html?

email = forms.EmailField(
    required=True, 
    max_length=100, 
) 

Nó đã thuộc tính bắt buộc, nhưng trong html nó không phải là cách thêm thuộc tính html required. Trong thực tế nó thậm chí không sử dụng email làm kiểu trường, nó đang sử dụng text ... mặc dù nó dường như nhận được max_length tốt.

Thực tế:

<input id="id_email" type="text" name="email" maxlength="100"> 

dự kiến:

<input id="id_email" type="email" name="email" maxlength="100" required="true"> 

Làm thế nào tôi có thể nhận được Django để sử dụng các thuộc tính đúng theo các hình thức html?

Trả lời

6

monkeypatching Widget là đặt cược tốt nhất của bạn:

from django.forms.widgets import Widget 
from django.contrib.admin.widgets import AdminFileWidget 
from django.forms import HiddenInput, FileInput 

old_build_attrs = Widget.build_attrs 

def build_attrs(self, extra_attrs=None, **kwargs): 
    attrs = old_build_attrs(self, extra_attrs, **kwargs) 

    # if required, and it's not a file widget since those can have files 
    # attached without seeming filled-in to the browser, and skip hidden "mock" 
    # fileds created for StackedInline and TabbedInline admin stuff 
    if (self.is_required 
      and type(self) not in (AdminFileWidget, HiddenInput, FileInput) 
      and "__prefix__" not in attrs.get("name", "")): 
     attrs['required'] = 'required' 

    return attrs 

Widget.build_attrs = build_attrs 
+3

Xin cảm ơn tôi !! –

+4

Tôi có thể đề nghị bạn thay đổi câu lệnh if để đọc: 'if self.is_required và gõ (self) không có trong (AdminFileWidget, HiddenInput, FileInput) và" __prefix__ "không có trong attrs [" name "]:' Điều đó sẽ ngăn chặn trình duyệt thêm từ 'required =" true "' khi một đối tượng đã có một tệp đính kèm với nó, cũng như bỏ qua các trường "mock" ẩn được tạo cho các công cụ quản trị StackedInline và TabbedInline. –

16

Thành phần biểu mẫu Django được viết trên <input /> vì nó tồn tại trong HTML 4, trong đó type="text" là tùy chọn chính xác cho địa chỉ e-mail. Cũng không có required="true".

Nếu bạn muốn thuộc tính HTML tùy chỉnh, bạn cần đối số từ khóa attrs cho tiện ích . Nó sẽ trông giống như sau:

email = forms.EmailField(
    max_length=100, 
    required=True, 
    widget=forms.TextInput(attrs={ 'required': 'true' }), 
) 

Bạn có thể xem thêm tài liệu về các tiện ích here. Thảo luận về attrs ở gần cuối trang đó.

Về type="email", bạn có thể gửi điều đó tới từ điển attrs và Django sẽ tự động ghi đè mặc định của từ điển đó. Nếu đó không phải là kết quả bạn nhận được, thì tuyến đường của bạn là để phân loại forms.TextInput và sau đó chuyển nó đến đối số từ khóa widget.

+0

Có cách nào để khỉ vá lớp cơ sở tiện ích biểu mẫu không? Dường như rất không có DRY phải chỉ định thuộc tính bắt buộc hai lần. –

+0

Tôi cho là vậy. Đó là 'django.forms.BaseForm'. –

7

Kết hợp Daniel và Daniel câu trả lời, tôi thường sử dụng mixin này cho các hình thức của tôi:

from django.contrib.admin.widgets import AdminFileWidget 
from django.forms.widgets import HiddenInput, FileInput 


class HTML5RequiredMixin(object): 

    def __init__(self, *args, **kwargs): 
     super(HTML5RequiredMixin, self).__init__(*args, **kwargs) 
     for field in self.fields: 
      if (self.fields[field].required and 
       type(self.fields[field].widget) not in 
        (AdminFileWidget, HiddenInput, FileInput) and 
       '__prefix__' not in self.fields[field].widget.attrs): 

        self.fields[field].widget.attrs['required'] = 'required' 
        if self.fields[field].label: 
         self.fields[field].label += ' *' 

Vì vậy, khi tôi có để tạo ra một hình thức mới hoặc modelform tôi chỉ sử dụng:

class NewForm(HTML5RequiredMixin, forms.Form): 
    ... 
+0

Trong trường hợp của tôi, tôi nhận 'đối tượng Form không có thuộc tính' fields '' vì python đánh giá '__init__' từ trái sang phải và đối tượng biểu mẫu không có sẵn tại thời điểm cuộc gọi HTML5RequiredMixin '__init__'. Sau khi tôi thay đổi thứ tự khai báo lớp như thế này và một phần của __init__ của NewForm nó đã làm việc. 'lớp NewForm (forms.Form, HTML5RequiredMixin)', sau đó __init__ của NewForm, gọi 'HTML5RequiredMixin .__ init__' – Hobaak

5

Ngoài ra còn có giải pháp chỉ lấy mẫu bằng bộ lọc. Tôi khuyên bạn nên django-widget-tweaks:

{% load widget_tweaks %} 

{{ form.email|attr:'required:true' }} 

Điều đó thật dễ dàng.

4

Như bạn đã nhận ra, việc đặt thuộc tính Trường bắt buộc là True chỉ dành cho xác thực phụ trợ, như được giải thích trong Django documentation.

gì bạn thực sự muốn là thêm một thuộc tính cần thiết để các Widget của lĩnh vực này:

email.widget.attrs["required"] = "required" 

Nhưng nếu bạn thực sự muốn viết tao nhã, mã DRY, bạn nên thực hiện một lớp hình thức cơ bản rằng động trông cho tất cả các trường bắt buộc của bạn và sửa đổi phụ tùng thuộc tính cần thiết của họ cho bạn (bạn có thể đặt tên cho nó bất cứ điều gì bạn muốn, nhưng "BaseForm" dường như apt):

from django.forms import ModelForm 

class BaseForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(BaseForm, self).__init__(*args, **kwargs) 
     for bound_field in self: 
      if hasattr(bound_field, "field") and bound_field.field.required: 
       bound_field.field.widget.attrs["required"] = "required" 

và sau đó có tất cả các đối tượng Form của bạn xuống từ nó:

class UserForm(BaseForm): 
    class Meta: 
     model = User 
     fields = [] 

    first_name = forms.CharField(required=True) 
    last_name = forms.CharField(required=True) 
    email = forms.EmailField(required=True, max_length=100) 
3

Kể từ Django 1.10, tính năng này được tích hợp sẵn.

Từ release notes:

lĩnh vực hình thức bắt buộc bây giờ có thuộc tính HTML cần thiết. Đặt thuộc tính Form.use_required_attribute mới thành False để vô hiệu hóa nó.

+0

Cảm ơn rất nhiều, tôi đã gặp khó khăn trong việc thiết lập thuộc tính này trong một thời gian khá dài. – quapka

Các vấn đề liên quan