2011-04-05 27 views
3

我有一個位置模型和一個關聯窗體,它將「location」字段顯示爲一堆單選按鈕(使用窗體queryset顯示值)。有少數地點,但他們需要動態。我想在每個收音機選項旁邊顯示位置說明,以便用戶瞭解位置信息。Django Rendering Rendering單選按鈕選項包含來自Model的額外信息

假裝這是單選按鈕的列表,這是想什麼我它看起來像:

<>東 - 這個位置是東。 <>西 - 這是西部的位置! <>北 - 這是北位置

我有類似如下的模式:

class Location(models.Models): 
    location = models.CharField(max_length=50) 
    description = models.TextField(blank=True, null=True) 

和一個表單這樣:

class LocationForm(forms.Form): 
    location = ExtraModelChoiceField(
       widget=RadioSelect(renderer=ExtraHorizRadioRenderer), 
       queryset = models.Locations.objects.filter(active=True)) 

我似乎無法找到一個很好的方式來呈現表單,以便我可以顯示說明以及每個選擇選項。我做了很多壓倒性的事,但沒有太多的運氣。

MY試圖解決(但沒有運氣YET):

從我所收集,通常如果查詢集設置在表單字段,Django的形式邏輯轉換到這一點tupals的選擇tupal。每個「subtupal」包含一個id和標籤,它在渲染時顯示。我正在嘗試向那些將作爲描述的「子小組」添加第三個值。

我定義了一個自定義渲染器來水平顯示我的單選按鈕並傳入我的自定義選項。

class ExtraHorizRadioRenderer(forms.RadioSelect.renderer): 
    def render(self): 
     return mark_safe(u'\n'.join([u'%s\n' % w for w in self])) 

    def __iter__(self): 
     for i, choice in enumerate(self.choices): 
      yield ExtraRadioInput(self.name, self.value, 
            self.attrs.copy(), choice, i) 

    def __getitem__(self, idx): 
     choice = self.choices[idx] # Let the IndexError propogate 
     return ExtraRadioInput(self.name, self.value, 
           self.attrs.copy(), choice, idx) 

我重寫了Django RadioInput類,因此我可以添加我需要在Radio Buttons旁邊顯示的描述信息。

class ExtraRadioInput(forms.widgets.RadioInput): 

    def __init__(self, name, value, attrs, choice, index): 
     self.name, self.value = name, value 
     self.attrs = attrs 
     self.choice_value = force_unicode(choice[0]) 
     self.choice_label = force_unicode(choice[1]) 
     self.choice_description = force_unicode(choice[2]) # <--- MY ADDITION; FAILS 
     self.index = index 

    def __unicode__(self): 
     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'<label%s>%s %s</label>' % (
      label_for, self.tag(), choice_label)) 

    def tag(self): 
     if 'id' in self.attrs: 
      self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) 
     final_attrs = dict(self.attrs, type='radio', name=self.name, 
         value=self.choice_value) 
     if self.is_checked(): 
      final_attrs['checked'] = 'checked' 
     return mark_safe(
      u'<input%s /><span class="description">%s</span>' % \ 
      (flatatt(final_attrs),self.choice_description)) # <--- MY ADDTIONS 

我也重寫了下面兩個Django類,希望能夠傳遞我修改過的選擇tupals。

class ExtraModelChoiceIterator(forms.models.ModelChoiceIterator ):  

    def choice(self, obj): 
     if self.field.to_field_name: 
      key = obj.serializable_value(self.field.to_field_name) 
     else: 
      key = obj.pk 

     if obj.description: # <-- MY ADDITIONS 
      description = obj.description 
     else: 
      description = "" 
     return (key, self.field.label_from_instance(obj),description) 


class ExtraModelChoiceField(forms.models.ModelChoiceField): 

    def _get_choices(self): 
     if hasattr(self, '_choices'): 
      return self._choices 
     return ExtraModelChoiceIterator(self) # <-- Uses MY NEW ITERATOR 

使用上面的方法,我似乎無法繞過我的3值tupal。我得到了「元組索引超出範圍」失敗(上面標記了FAILURE的地方),表明我的tupal沒有額外的價值。

有沒有人在我的邏輯中看到缺陷,或者更普遍地有一種方法來顯示使用小部件的選項列表旁邊的描述?

感謝您的閱讀。任何意見都非常感謝。 Joe

+1

你有沒有考慮過使用CSS來做到這一點?對我來說似乎更容易。我覺得Python/Django開發人員不需要擔心使用服務器端代碼的格式。 – Spike 2011-04-05 21:21:08

回答

2

對不起回答我自己的問題,但我想我有一個方法來做到這一點。像往常一樣,它似乎比我之前做的更簡單。覆蓋擴展ModelChoiceField上的label_from_instance方法似乎允許我訪問模型對象實例,以便能夠打印出額外的信息。

from django.utils.encoding import smart_unicode, force_unicode 

class ExtraModelChoiceField(forms.models.ModelChoiceField): 

    def label_from_instance(self, obj): 
     return mark_safe(
      "<span>%s</span><span class=\"desc\" id=\"desc_%s\">%s</span>" % (
      mart_unicode(obj), obj.id, smart_unicode(obj.description),)) 


class HorizRadioRenderer(forms.RadioSelect.renderer): 
    # for displaying select options horizontally. 
    # https://wikis.utexas.edu/display/~bm6432/Django-Modifying+RadioSelect+Widget+to+have+horizontal+buttons 
    def render(self): 
     return mark_safe(u'\n'.join([u'%s\n' % w for w in self])) 


class LocationForm(forms.Form): 
    location = ExtraModelChoiceField(widget=forms.RadioSelect(renderer=HorizRadioRenderer), 
     queryset=models.Location.objects.filter(active=True)) 

如果你知道更好的方法,我會很高興看到它。否則,這將不得不做。謝謝閱讀。希望這節省了我的挫折感。

Joe