2012-07-19 67 views
5

所以我使用jQuery UI到skin the radio buttons,但我無法讓Django按照它必須完成的方式呈現我的窗體。使用RadioSelect小部件自定義Django窗體

我需要有這樣的結構:

<table> 
    <tr> 
     <td><label for="notify_new_friends">Notify when new friends join</label></td> 
     <td class="radio"> 
      <input type="radio" name="notify_new_friends" id="notify_new_friends_immediately" value="1" checked="checked"/><label for="notify_new_friends_immediately">Immediately</label> 
      <input type="radio" name="notify_new_friends" id="notify_new_friends_never" value="0"/><label for="notify_new_friends_never">Never</label> 
     </td> 
    </tr> 
</table> 

因此,要總結,我需要一個類(無線電)內的單選按鈕,他們有一個inputlabel for

當我渲染我與{{ profile_form.notify_new_friends }}模板的形式,我得到以下幾點:

<ul> 
    <li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li> 
    <li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li> 
</ul> 

這正是我想除了列表部分的內容。所以,我想遍歷它,給了我格式不同的標籤:這使我

{% for item in profile_form.notify_new_friends %} 
    {{ item }} 
{% endfor %} 

<label><input type="radio" name="notify_new_friends" value="0" /> Immediately</label> 
<label><input type="radio" name="notify_new_friends" value="1" /> Never</label> 

所以這裏的問題是,它停止使用label for,並且開始只使用label到wrapp它所有。

我也試過做這樣的事情,但然後labellabel_tag不渲染任何東西。

{{ profile_form.notify_new_friends.0 }} 
{{ profile_form.notify_new_friends.0.label_tag }} 
{{ profile_form.notify_new_friends.0.label }} 

所以沒有人知道我該如何正確渲染這個!

僅供參考,這是我的forms.py:

self.fields['notify_new_friends'] = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect, choices=NOTIFICATION_CHOICES) 
+0

https://docs.djangoproject.com/en/dev/ref/forms/widgets/#radioselect - 你讀過這個嗎? – 2012-07-19 08:24:54

+0

@ AlexanderA.Sosnovskiy是的,但我錯過了'choice_label'來獲取標籤標題,但不幸的是'{{radio.tag}}'不能提供給我一個ID,因此我不能'標籤'我需要做的。 – olofom 2012-07-19 08:33:19

+0

字段ID是自動生成嘗試,{{field.auto_id}} – 2012-07-19 08:47:00

回答

1

因爲它似乎並沒有被這樣做的好辦法,我選擇重新安排使用jQuery生成的代碼。

// First remove the ul and li tags 
$('.radio ul').contents().unwrap(); 
$('.radio li').contents().unwrap(); 
// Then move the input to outside of the label 
$('.radio > label > input').each(function() { 
    $(this).parent().before(this); 
}); 
// Then apply the jQuery UI buttonset 
$(".radio").buttonset(); 

這使得它去從:

<ul> 
    <li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li> 
    <li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li> 
</ul> 

到:

<input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /><label for="id_notify_new_friends_0"> Immediately</label></li> 
<input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /><label for="id_notify_new_friends_1"> Never</label></li> 

和我的jQuery UI的造型工作正常。

+0

我認爲如果有可能做到沒有javascript,我們應該避免js ...特別是在頁面加載 - 性能更差,更差的搜索引擎優化。如果我們使用JavaScript進行操作,它應該是動態操作,這會導致像交互一樣的原因。 – kspacja 2014-02-26 14:17:34

+0

我不相信只是重新排列頁面上相同內容的JavaScript可能會影響SEO。除此之外,這個解決方案可能在Django管理中運行得非常好,在那裏SEO是無關緊要的,控制HTML輸出將需要覆蓋多個Django類,如tnajdek的答案中所述。 – bpscott 2014-08-12 19:06:23

5

在我的代碼我發現從

forms.RadioSelect 

改變窗口小部件

forms.RadioSelect(attrs={'id': 'value'}) 

神奇地使所得tag值以包括id屬性與所附的項的索引。如果你在表單中使用

{% for radio in form.foo %} 
    <li> 
     {{ radio }} 
    </li> 
{% endfor %} 

你得到一個labelinput纏。如果你想接着label更傳統的input,你需要這樣做:

{% for radio in form.value %} 
    <li> 
     {{ radio.tag }} 
     <label for="value_{{ forloop.counter0 }}">{{ radio.choice_label }}</label> 
    </li> 
{% endfor %} 
0
Try like this , I got it.. 

from django.forms.widgets import RadioFieldRenderer 
from django.utils.encoding import force_unicode 
from django.utils.safestring import mark_safe 


class RadioCustomRenderer(RadioFieldRenderer): 
    def render(self): 
     return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self])) 

in form 

widgets = { 
      'validity': forms.RadioSelect(renderer=RadioCustomRenderer), 
     } 
1

不幸的是,這是更復雜的比它應該是,看來你需要重寫至少2類:RadioRendererRadioInput。以下內容可以幫助您開始,但您可能需要稍微調整一下。

首先創建一個自定義單選按鈕輸入小部件。我們覆蓋的渲染方法的唯一目的是爲了擺脫惱人的結構Django的強制執行(<label><input /></label>)其中,而不是我們希望我們的(<label /><input />)的:

class CustomRadioInput(RadioInput): 
    def render(self, name=None, value=None, attrs=None, choices=()): 
     name = name or self.name 
     value = value or self.value 
     attrs = attrs or self.attrs 
     if 'id' in self.attrs: 
      label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) 
     else: 
      label_for = '' 
      choice_label = conditional_escape(force_unicode(self.choice_label)) 
      return mark_safe(u'%s<label%s>%s</label>' % (self.tag(), label_for, choice_label)) 

現在,我們需要以覆蓋RadioRenderer到:

  1. 強制使用我們自定義的無線電輸入小部件
  2. 刪除<li>包木窗的每一個輸入字段和<ul>包裝所有輸入字段:

沿着這些線路的東西應該做的事:

class RadioCustomRenderer(RadioFieldRenderer): 
    def __iter__(self): 
     for i, choice in enumerate(self.choices): 
      yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i) 

    def __getitem__(self, idx): 
     choice = self.choices[idx] 
     return CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, idx) 

    def render(self): 
     return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self])) 

最後指示的Django使用自定義渲染

notify_new_friends = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect(renderer=RadioCustomRenderer), choices=NOTIFICATION_CHOICES) 

請記住:現在這輸出單選按鈕與包含<td>因此你在一起需要在模板中圍繞它建立一個表格,沿着這些線條:

<table> 
    <tr> 
    <td><label for="{{field.auto_id}}">{{field.label}}</label></td> 
    <td>{{ field.errors }} {{field}}</td> 
    </tr> 
</table> 
相關問題