diseño de entrada de radio de forma django

¿Cuál es la forma “djangoy” de abordar este problema:

En mi clase de formulario, tengo un forms.ChoiceField cuyo widget es un widget forms.RadioSelect, una de cuyas opciones debe presentarse con una entrada de texto en línea (que también es un campo en el formulario). Estoy usando la validación personalizada para ignorar el campo de texto cuando no se selecciona su opción de radio. Cuando esté renderizado, quiero que aparezca como a continuación:

Sin embargo, no puedo simplemente producir esto en mi plantilla, porque las opciones de radio no están expuestas. No puedo ver una manera de hacer esto sin unir fuertemente mi formulario a mi plantilla, o alternativamente, poner toda la lógica de presentación en la clase de formulario. ¿Cuál es la forma correcta de resolver este problema?

editar

Me doy cuenta de que lo anterior podría ser un problema oscuro, pero no estoy seguro de qué otra información puedo proporcionar para inspirar a alguien para que me ayude con esto. Soy mucho mejor progtwigdor de backend que diseñador web, y estoy solo en este proyecto, así que quizás sea una falta de educación. ¿Es lo que describí simplemente un diseño deficiente? ¿Debería estar diseñando esto de una manera diferente? Estoy realmente abierto a cualquier sugerencia aquí que me ayude a superar esto.

editar 2

Por solicitud, el código actual, acortado para ahorrar cordura, los nombres han sido cambiados para proteger a los inocentes:

 # forms.py from myapp.models import RatherComplicatedModel from django import forms class RatherComplicatedForm(forms.ModelForm): #various and sundry code... RADIO_CHOICES = ( ('none', "No Textbox"), ('one', "One Textbox: "), ) # although I've abbreviated the model, 'rad' does not appear in the model; # it merely provides input to the un-provided clean function rad = forms.ChoiceField(widget=forms.RadioSelect(),choices=RADIO_CHOICES) class Meta: model = RatherComplicatedModel 

 # models.py from django.db import models class RatherComplicatedModel(models.Model): #some other stuff... bar = models.IntegerField(blank=True,null=True) 

Si entiendo su problema correctamente, puede acceder a la tupla de opciones en la plantilla:

 
    {# Assuming {{ field }} here is {{ form.rad }} #} {% for choice in field.field.choices %}
  • {% endfor %}

La respuesta de Anton funcionó, y fue una respuesta decente por un tiempo allí, pero desafortunadamente se volvió inalcanzable. Por lo tanto, siguiendo el ejemplo de un archivo adjunto al boleto # 9230 de django , simplemente django.forms.forms.BoundField parcheado

 from django import forms def MonkeyPatchDjangoFormsBoundField(): def prepare_widget_render(self, widget=None, attrs=None, only_initial=False): """ Prepare the data needed for the widget rendering. """ if not widget: widget = self.field.widget attrs = attrs or {} auto_id = self.auto_id if auto_id and 'id' not in attrs and 'id' not in widget.attrs: if not only_initial: attrs['id'] = auto_id else: attrs['id'] = self.html_initial_id if not only_initial: name = self.html_name else: name = self.html_initial_name return widget, name, attrs def as_widget(self, widget=None, attrs=None, only_initial=False): """ Renders the field by rendering the passed widget, adding any HTML attributes passed as attrs. If no widget is specified, then the field's default widget will be used. """ widget, name, attrs = self.prepare_widget_render(widget, attrs, only_initial) return widget.render(name, self.value(), attrs=attrs) def __iter__(self): """ Check if current widget has a renderer and iterate renderer. """ widget, name, attrs = self.prepare_widget_render() if not hasattr(widget, 'get_renderer'): raise Exception, "Can not iterate over widget '%s'" % widget.__class__.__name__ renderer = widget.get_renderer(name, self.value(), attrs=attrs) for entry in renderer: yield entry def __getitem__(self,idx): """ Tries to use current widget's renderer, and then check attribute. """ widget, name, attrs = self.prepare_widget_render() try: renderer = widget.get_renderer(name, self.value(), attrs=attrs) return renderer[idx] except Exception: return getattr(self,idx) forms.forms.BoundField.prepare_widget_render = prepare_widget_render forms.forms.BoundField.as_widget = as_widget forms.forms.BoundField.__iter__ = __iter__ forms.forms.BoundField.__getitem__ = __getitem__ 

Esto me permitió poder acceder a las entradas de radio directamente, utilizando {{ form.field.0.tag }} , o mediante iteración – {% for radio in form.field %} {{ radio.tag }} {% endfor %} . ¡Mucho más fácil de cuidar!

Las opciones deben estar en el modelo:

 class RatherComplicatedModel(models.Model): BAR_CHOICES = ( (0, "No Textbox"), (1, "One Textbox: "), ) #some other stuff... bar = models.IntegerField(blank=True, null=True, choices=BAR_CHOICES) 

Entonces solo

 class RatherComplicatedForm(forms.ModelForm): #various and sundry code... bar = forms.ChoiceField(widget=forms.RadioSelect(), choices=RatherComplicatedModel.BAR_CHOICES) class Meta: model = RatherComplicatedModel 

Lo haría subclasificando RadioFieldRenderer y adjuntándolo a un widget personalizado:

 # forms.py from django import forms from django.forms.widgets import RadioSelect, RadioFieldRenderer from django.template.loader import render_to_string from myapp.models import RatherComplicatedModel class MyRadioFieldRenderer(RadioFieldRenderer): def render(self): return render_to_string( 'my_radio_widget.html', {'field': self}) class MyRadioSelect(RadioSelect): renderer = MyRadioFieldRenderer class RatherComplicatedForm(forms.ModelForm): RADIO_CHOICES = ( ('none', "No Textbox"), ('one', "One Textbox: "), ) rad = forms.ChoiceField(widget=MyRadioSelect(),choices=RADIO_CHOICES) class Meta: model = RatherComplicatedModel 

Luego la plantilla:

 #my_radio_widget.html 
    {% for choice in field %}
  • {% endfor %}