urls tutorial template desde cero python django django-forms

python - tutorial - django forma de diseño de entrada de radio



django urls (4)

¿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 elecciones 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 su opción de radio no está seleccionada. Cuando se procesa, quiero que aparezca como a continuación:

<ul> <li><label for="id_rad_0"><input type="radio" id="id_rad_0" value="none" name="rad" /> No Textbox</label></li> <li><label for="id_rad_1"><input type="radio" id="id_rad_1" value="one" name="rad" /> One Textbox: <input type="text" name="bar" id="id_bar" /></label></li> </ul>

Sin embargo, no puedo simplemente producir esto en mi plantilla, porque las opciones de radio no están expuestas. No veo la manera de hacerlo sin combinar 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 solo un problema oscuro, pero no estoy seguro de qué otra información puedo proporcionar para inspirar a alguien que me ayude con esto. Soy un programador de back-end mucho mejor que un diseñador web, y estoy solo en este proyecto, entonces tal vez sea una falta de educación. ¿Es lo que describí simplemente como un diseño pobre? ¿Debo simplemente diseñar esto de otra manera? Estoy realmente abierto a cualquier sugerencia que me ayude a superar esto.

editar 2

Por solicitud, el código actual, abreviado para guardar cordura, cambió los nombres 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)


Haría esto 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

Entonces la plantilla:

#my_radio_widget.html <ul> {% for choice in field %} <li> <label for="id_{{ field.name }}_{{ forloop.counter0 }}"> <input type="radio" name="{{ field.name }}" value="{{ choice.choice_value }}" id="id_{{ field.name }}_{{ forloop.counter0 }}" {% if field.value == choice.choice_value %} checked=''checked'' {% endif %}/> {{ choice.choice_label }} </label> </li> {% endfor %} </ul>


La respuesta de Anton funcionó, y fue una respuesta decente por un tiempo allí, pero desafortunadamente se volvió imposible de mantener. Así que, siguiendo el ejemplo de un diff adjunto al ticket de django # 9230 , acabo de parchear django.forms.forms.BoundField

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, usando {{ form.field.0.tag }} , o mediante iteración - {% for radio in form.field %} {{ radio.tag }} {% endfor %} . ¡Mucho más fácil de cuidar!


Las elecciones 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


Si entiendo su problema correctamente, puede acceder a las opciones tuple en la plantilla:

<ul> {# Assuming {{ field }} here is {{ form.rad }} #} {% for choice in field.field.choices %} <li> <label for="id_{{ field.html_name }}_{{ forloop.counter0 }}"> <input type="radio" id="id_{{ field.html_name }}_{{ forloop.counter0 }}" value="{{ choice.0 }}" name="{{ field.html_name }}" /> {{ choice.1 }} {% if choice.0 == ''one'' %} {# Necessary field here #} {{ form.bar }} {% else %} No Textbox {% endif %} </label> </li> {% endfor %} </ul>