2010-11-08 70 views
32

Tôi đang xuất các trường của biểu mẫu trong một mẫu như thế này {{ form.first_name }} và tôi muốn thêm một lớp (ví dụ: bản thiết kế span-x -class) cho nó. Vì vậy, tôi muốn biết nếu có một giải pháp readymade tốt đẹp (bộ lọc mẫu) cho rằng, mà tôi có thể sử dụng trong thời trang {{ form.first_name|add_class:"span-4" }}? (Tôi chỉ muốn biết các nhà phát triển của Django hay bất kỳ ai đã nghĩ về điều đó mà không có kiến ​​thức của tôi trước khi tự mình làm)Django: Thêm các lớp CSS khi hiển thị các trường biểu mẫu trong một mẫu

Trả lời

22

Để giải quyết vấn đề này, tôi đã tạo bộ lọc mẫu của riêng mình, bạn có thể áp dụng nó trên bất kỳ thẻ nào, không chỉ các yếu tố đầu vào!

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') 
@register.filter 
def add_class(value, css_class): 
    string = unicode(value) 
    match = class_re.search(string) 
    if match: 
     m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                css_class, css_class), 
                match.group(1)) 
     print match.group(1) 
     if not m: 
      return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
              string)) 
    else: 
     return mark_safe(string.replace('>', ' class="%s">' % css_class)) 
    return value 
+2

Rất độc đáo thực hiện. Để làm cho nó hoạt động cho các trường kết thúc bằng '/>', tôi đã sử dụng 'return mark_safe (string.replace ('', 'class ="% s "'% css_class))' - đã sử dụng dấu cách thay vì '>' để nó tìm ra không gian đầu tiên và tiêm thuộc tính trước phần còn lại. – abstractpaper

+0

Regexp phù hợp với tham lam, nhưng phải phù hợp với lười biếng. Tôi đã thay đổi mã ở trên thành '' class_re = re.compile (r '(? <= Class = ["\']) (. *?) (? = [" \ '])') ''. Nếu không nó khớp với '' '' '' cuối cùng thay vì kết thúc của lớp –

0

Bạn cần chỉ định tiện ích một cách rõ ràng và thêm lớp bằng cách sử dụng attrs keyword argument. Không có cách nào khác mà tôi biết.

Tuy nhiên, nếu điều này quá cồng kềnh, bạn vẫn có thể bọc trường trong phần tử khác, chẳng hạn như div hoặc span và thêm lớp vào đó. Sau đó sửa đổi CSS của bạn cho phù hợp.

+1

Như tôi đã đề cập:

@register.filter def add_class(field, class_name): return field.as_widget(attrs={ "class": " ".join((field.css_classes(), class_name)) }) 

Và trong mẫu của bạn muốn làm điều đó trong mẫu, vì biểu mẫu có thể được hiển thị trong các lần xuất hiện khác nhau! –

+1

Để có kết quả tối ưu, bạn nên cân nhắc đọc về bố cục đáp ứng. Các mẫu và lớp của bạn sẽ không thay đổi và tất cả các phép thuật vẫn còn trên css. –

5

tôi vẫn đang học Django, nhưng bạn không thể làm một cái gì đó như thế này này -

from django import forms 

class SomeForm(forms.Form): 
    f = forms.CharField(label='x',widget=forms.TextInput(attrs={'class':'name'})) 

Tôi đoán không có nhu cầu để làm điều này ở mẫu mực (hoặc bộ lọc sử dụng), trừ khi bạn có một số yêu cầu mà tôi không hiểu.

+2

Nó sạch hơn nhiều để tách phong cách (css) khỏi chức năng (biểu mẫu). Ví dụ, làm thế nào để bạn có điều kiện thêm một lớp vào một trường biểu mẫu trong khuôn mẫu bằng cách sử dụng phương thức này? Ngoài ra, làm cách nào để bạn hiển thị biểu mẫu này theo các cách khác nhau mà không sao chép biểu mẫu, chẳng hạn như biểu mẫu thân thiện với thiết bị di động và biểu mẫu thân thiện với thiết bị di động không phải như vậy? Việc xác nhận được cung cấp bởi biểu mẫu không thay đổi, nhưng quan điểm của nó không. – varikin

+1

Lớp CSS được áp dụng ở cấp biểu mẫu không ảnh hưởng đến các màn hình khác nhau. Lớp biểu mẫu sẽ vẫn giữ nguyên trên bất kỳ thiết bị nào và bạn nên có cấu hình tệp css cụ thể chuyên dụng theo thiết bị, khi cần. –

+0

Đây là câu trả lời đúng cho hầu hết các trường hợp. Không cần phải lộn xộn xung quanh với regexes! Chỉ cần có thể cũng đề cập đến trường hợp cho ModelForm: 'lớp Meta: widgets = {'f': forms.TextInput (attrs = {'class': 'name'})}' – frnhr

12

Một vài lưu ý bổ sung về cách tìm hiểu giải pháp rất tiện lợi của Lazerscience. Dưới đây là cách tệp trông với nhập khẩu phụ thuộc:

import re 
from django.utils.safestring import mark_safe 
from django import template 
register = template.Library() 

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') 
@register.filter 
def add_class(value, css_class): 
    string = unicode(value) 
    match = class_re.search(string) 
    if match: 
     m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                css_class, css_class), 
                match.group(1)) 
     print match.group(1) 
     if not m: 
      return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
              string)) 
    else: 
     return mark_safe(string.replace('>', ' class="%s">' % css_class)) 
    return value 

Tôi đã dán tệp này vào tệp được gọi là add_class.py. Cấu trúc thư mục là: mydjangoproject> general_tools_app> templatetags> add_class.py

general_tools_app là một ứng dụng thu thập chức năng hữu ích như thế này mà tôi thêm vào dự án django mới.

(The general_tools_app và templatetags danh bạ cả hai đều có một __init__.py tập tin rỗng để họ được đăng ký một cách chính xác)

Trong settings.py, tuple INSTALLED_APPS tôi bao gồm các mục nhập 'mydjangoproject.general_tools_app'.

Để sử dụng bộ lọc trong mẫu, tôi thêm dòng {% load add_class %} ở đầu tệp. Nếu tôi muốn thêm lớp 'xóa' để một lĩnh vực, tôi muốn làm

{{ myfield|add_class:'delete' }} 
+1

Tôi tìm thấy định nghĩa 'class_re' hơi tham lam và kết thúc trong một số trường mà lớp đó được nhập vào thuộc tính' type' thay vì 'class'. Phiên bản sửa đổi của tôi:' class_re = re.compile (r '(? <= class = ["\']) ([^" \ '] *) (["\']) ')' – DanH

3

Thêm một ghi chú này về giải pháp lazerscience của: nếu bạn áp dụng điều này để một < chọn > yếu tố không có thuộc tính lớp, chuỗi thay thế trong trường hợp khác sẽ tạo ra một cái gì đó như thế này:

<select name="state" id="id_state" class="class1 class2"> 
    <option value="AL" class="class1 class2">Alabama</option class="class1 class2"> 
    <option value="AK" class="class1 class2">Alaska</option class="class1 class2"> 
    <option value="AZ" class="class1 class2">Arizona</option class="class1 class2"> 
</select class="class1 class2"> 

Tôi khá chắc chắn các trình duyệt loại bỏ các định nghĩa lớp không liên quan, nhưng đó là rất nhiều chuỗi thay thế khi bạn chỉ cần một. Một phương thuốc dễ dàng cho việc này:

return mark_safe(string.replace('>', ' class="%s">' % css_class, 1)) 

Đó tranh luận cuối cùng (1) sẽ đảm bảo rằng chỉ những trường hợp đầu tiên của ">" sẽ được thay thế bằng "class =" ... ">, đó là một cách logic chính xác cho bất kỳ phần tử biểu mẫu.

+0

Xin chào , cảm ơn vì nguồn cảm hứng, đoán tôi chưa bao giờ sử dụng nó với một 'lựa chọn' nào! –

46

Bạn chỉ cần phải cài đặt Django widget_tweaks

pip install django-widget-tweaks 

Sau khi bạn có thể làm điều gì đó như thế trên mẫu của bạn:

{{ form.search_query|attr:"type:search" }} 

-

Đọc tất cả về nó here.

+1

Tôi đang tìm cách thêm các lớp vào 'nhãn', tôi nhớ rằng việc thêm chúng một cách thủ công là đơn giản:' ' –

9

Một cách khác là sử dụng phương pháp as_widget trên một trường để thay đổi nó - đơn giản và an toàn hơn so với phương pháp tiếp cận regex và không yêu cầu bất kỳ phụ thuộc bổ sung nào.

Xác định một custom template filter: Tôi

{{ form.first_name|add_class:"span-4" }} 

Bạn cũng có thể sử dụng as_widget thêm các thuộc tính khác, như placeholder vv

+0

đủ đơn giản và hoạt động – Bwire

+0

Yêu thích giải pháp thanh lịch này, cộng với giờ tôi đã học cách sử dụng thẻ mẫu. Cảm ơn! – Matt

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