2012-04-24 19 views
12

RadioSelect küçük aracını kullanarak ModelChoiceField içeren bir ModelForm'um var.ModelChoiceField örneklerini şablonda nasıl edinilir

class MyAForm(forms.ModelForm): 
    one_property = models.ModelChoiceField(
     widget=forms.RadioSelect, 
     queryset=MyBModel.objects.filter(visible=True), 
     empty_label=None) 
    class Meta: 
     model = MyAModel 

MyBModel'de, radyo düğmesinin yanında görüntülemek istediğim özellikler vardır. ModelChoiceField'ın bir alt sınıfında label_from_instance'u geçersiz kılardım, ancak bu, radyo düğmesinin, her seçim öğesi için bir satırı olan bir tablonun içinde görünmesini istediğim şekilde istediğim şeyi yapmama izin vermiyor.

Yani bir yerde benim şablonunda ben

{% for field in form.visible_fields %} 
    {% if field.name == "one_property" %} 
    <table> 
     {% for choice in field.choices %} 
      <tr> 
       <td><input value="{{choice.id}}" type="radio" name="one_property" />{{choice.description}}</td> 
       <td><img src="{{choice.img_url}}" /></td> 
      </tr> 
     {% endfor %} 
    </table> 
    {% endif %} 
{% endfor %} 

Maalesef döner nesnenin kimliği tuple ve etiket değil sorgu grubu bir örneği field.choices ... gibi bir şey istiyorum.

Bir model içinde kullanılacak bir ModelChoiceField seçeneğinin örneklerini almanın basit bir yolu var mı?

cevap

10

ModelChoiceField için django kaynağını inceledikten sonra, bir "queryset" özelliğine sahip olduğunu keşfettim.

Ben böyle bir şey kullanmak başardı

...

{% for field in form.visible_fields %} 
    {% if field.name == "one_property" %} 
    <table> 
     {% for choice in field.queryset %} 
      <tr> 
       <td><input value="{{choice.id}}" type="radio" name="one_property" />{{choice.description}}</td> 
       <td><img src="{{choice.img_url}}" /></td> 
      </tr> 
     {% endfor %} 
    </table> 
    {% endif %} 
{% endfor %} 
+0

Merhaba, Bunu yazdıysam ** {{field.name}} ** sonra alanların tüm adlarını yazdırır, ancak eğer '{% if field.name = "öznitelikleri"%} "durumunda kullanılırsa ya da '{% field.name = attributes%}' ise ve bu durumun başarısı üzerine bir şeyler yazdırmaya çalışın, sonra hiçbir şey yazdırmaz, koşulun false değerini döndürdüğü anlamına gelir. Ama bu durumda kullandığım alan adı yazdırdığıdır. ** NEDEN? ** – Inforian

+1

Tek biriniz var = = olmalı == –

2

Genellikle gerçek nesneyi, ama onun yorumunu gerekmez.

class LabelledHiddenWidget(forms.HiddenInput): 

    def __init__(self, get_object, *args, **kwargs): 
     super(LabelledHiddenWidget, self).__init__(*args, **kwargs) 
     self.get_object = get_object 

    def render(self, name, value, attrs=None): 
     s = super(LabelledHiddenWidget, self).render(name, value, attrs) 
     if value: 
      s += SafeUnicode("<span>%s</span>" % self.get_object(value)) 
     return s 

Sonra bu gibi kullanabilirsiniz: Şablon kodunda Sonra

class SomeForm(forms.Form): 
    object = forms.ModelChoiceField(
     SomeModel.objects.all(), 
     widget=LabelledHiddenWidget(get_object=lambda id: get_object_or_404(SomeModel, id=id))) 

, {{ form.object }} irade çıktı nesne kimliği ile gizli bir alan, bazı ile birleştirilmiş

bu kodu düşünün etiket. Elbette, SomeModel'iniz __unicode__ veya güzel, insan tarafından okunabilir bir etiket veren başka bir yöntem uygulamalıdır.

4

OP'nin sorusuyla neredeyse aynı olan bir şey yapmak istedim (tablo ve hepsi), aynı şekilde Django'nun işbirliği eksikliği yüzünden hayal kırıklığına uğramıştı ve benzer şekilde kendi uygulamamla başa çıkmak için kaynağa düştüler. Geldiğim şey kabul edilen cevaptan biraz farklı ve ben de daha iyi beğendim çünkü şablonumda basit bir {{ form.as_table }} kullanıyordum ve visible_fields arasında döngü yapmak zorunda kalmak istemedim veya gereksiz yere bir radyo düğmesi Sadece Django'nun mevcut uygulamasına benzeyen şablon (bu değişebilir). İşte bunun yerine did:

RadioInput ve RadioFieldRenderer

Django'nın RadioSelect Widget radyo düğmeleri render asıl işi olan bir generatorRadioInputs ait verim RadioFieldRenderer kullanır. RadioSelect, belgesini, bu varsayılandan farklı bir oluşturucuya aktarabileceğiniz belgelenmemiş bir özelliğe sahip gibi görünüyor; böylece OP'nin istediği şeyi almak için bunların alt sınıflarını da alt sınıflara ayırabilirsiniz.

... 
radio = forms.ChoiceField(widget=forms.RadioSelect(renderer=CustomTableFieldRenderer), 
          choices=...) 
... 

Ve işte bu kadar:

Ile bitmiş
from django import forms 
from django.utils.safestring import mark_safe 

class CustomTableRadioInput(forms.widgets.RadioInput): 

    # We can override the render method to display our table rows 
    def render(self, *args, **kwargs): 
     # default_html will hold the normally rendered radio button 
     # which we can then use somewhere in our table 
     default_html = super(CustomTableRadioInput, self).render(*args, **kwargs) 
     # Do whatever you want to the input, then return it, remembering to use 
     # either django.utils.safestring.mark_safe or django.utils.html.format_html 
     # ... 
     return mark_safe(new_html) 

class CustomTableFieldRenderer(forms.widget.RadioFieldRenderer): 
    # Here we just need to override the two methods that yield RadioInputs 
    # and make them yield our custom subclass instead 
    def __iter__(self): 
     for i, choice in enumerate(self.choices): 
      yield CustomTableRadioInput(self.name, self.value, 
              self.attrs.copy(), choice, i) 

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

, biz sadece bizim formu kodunda yere istediğim zaman bizim özel oluşturucuyu kullanmak RadioSelect widget'ı anlatmak gerekiyor!Bu yerine

<table> 
    <tbody> 
    {% for tr in form.radio %} 
    <tr>{{ tr }}</tr> 
    {% endfor %} 
    </tbody> 
</table> 

:

, muhtemelen bu yani oldukça doğrudan çağırmaktan daha alanın üzerine döngü isteyeceksiniz o şablonda kullanmak için dikkat edin

<table> 
    <tbody>{{ form.radio }}</tbody> 
</table> 

İkincisini yaparsanız, tablo öğelerinizi <ul><li>...</li></ul> içine sarmayı deneyecektir.

İlgili konular