Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: need to render form options manually

Tags:

django

I need to replicate this form:

Live web page URL:

https://www.stickermule.com/products/die-cut-stickers

enter image description here

I've been reading the docs on how to render fields manually, but cannot render the radio inputs and their values manually.

https://docs.djangoproject.com/en/2.1/topics/forms/#rendering-fields-manually

My problem specifically is with the "Select a quantity part".

1) My form inherits from forms.ModelForm and only contains the quantity, not the cost (in $) neither the savings part.

That's why I need to put the quantity in a tag, pulling it from the form, and use other 2 tags in pure html to manually put the cost and the savings.

Unless there is a way to put these values in the model as others fields, but related to the field quantity (cantidad, in Spanish).

Desired HTML:

Copied from this page I need to replicate:

https://www.stickermule.com/products/die-cut-stickers

<form>
<div id="variants" class="product-option-group">      
 <legend>Select a size</legend>
 <ul id="variant-options" class="options">
   <li>
      <input id="variant_79" name="variant_id" readonly="" type="radio" value="79">
      <label for="variant_79"> 2" x 2"</label>
   </li>
   <li>
      <input id="variant_78" name="variant_id" type="radio" value="78">
      <label for="variant_78"> 3" x 3"</label>
   </li>
   <li>
      <input id="variant_80" name="variant_id" type="radio" value="80">
      <label for="variant_80"> 4" x 4"</label>
   </li>
   <li>
      <input id="variant_81" name="variant_id" type="radio" value="81">
      <label for="variant_81"> 5" x 5"</label>
   </li>
   <li>
      <input id="variant_77" name="variant_id" type="radio" value="77">
      <label for="variant_77"> Custom size</label>
   </li>
 </ul>
</div>
<div id="quantities">
   <legend>"Select a quantity"</legend>
   <ul>
      <li>
          <span class="table-cell">
            <input type="radio">
            <label>50</label>
          </span>
          <span id="price_50_id" class="table-cell  price">$57</span>
          <span class="table-cell savings"></span>
      </li>
      <li class=" quantity-item">
          <span class="table-cell">
              <input id="quantity_100" readonly="" name="quantity" type="radio" value="100">
              <label for="quantity_100" class=" quantity"> 100</label>
          </span>
          <span id="price_100_id" class="table-cell   price">$69</span>
          <span class="table-cell savings">Save 39%</span>
       </li>
  </ul>
</div>

models.py:

class TamaniosCantidades(models.Model):
    TAMANIOS = (('2x2', '2" x 2"',), ('3x3', '3" x 3"',),
               ('4x4', '4" x 4"',), ('5x5', '5" x 5"',))

    CANTIDADES = (('50', '50',), ('100', '100',),
                ('150', '150',))

    tamanios = models.CharField(max_length=10, choices=TAMANIOS)
    cantidades = models.CharField(max_length=10, choices=CANTIDADES)

forms.py:

class TamaniosCantidadesForm(forms.ModelForm):
    tamanios = forms.ChoiceField(choices=TAMANIOS, widget=forms.RadioSelect(), label='Selecciona un tamaño')
    cantidades = forms.ChoiceField(choices=CANTIDADES, widget=forms.RadioSelect(), label='Selecciona la cantidad')
    class Meta:
        model = TamaniosCantidades
        fields = ['tamanios', 'cantidades']

    def __str__(self):
        return self.tamanios

My HTML:

<form action="/post_url_tamanioscantidades/" method="post">
    {% csrf_token %}
    {{ tamanioscantidades_form.as_p }}
    <input type="submit" value="Submit"/>
</form>

In Summary:

I would like to call the fields like:

<form>
   <div id="quantities">
     <legend> {{ tamanioscantidades_form.label }} </legend>

     <ul>
        <li>
        <span>
             <input type="radio" id="{{ tamanioscantidades_form.input1_id }}>
             <label> {{ tamanioscantidades_form.label }} </label>
        </span>
        <span>
             <label>$57</label>
        </span>
        <span>
             <label>""</label>
        </span>
       </li>
     </ul>
    </div>
</form>

UPDATE 1:

With the answer from I can now render the radio button, but not the label.

class TamaniosCantidadesForm(forms.ModelForm):
    tamanios = forms.ChoiceField(choices=TAMANIOS, widget=forms.RadioSelect(), label='Selecciona un tamaño')
    cantidades = forms.ChoiceField(choices=CANTIDADES, widget=forms.RadioSelect(), label='Selecciona la cantidad')
    class Meta:
        model = TamaniosCantidades
        fields = ['tamanios', 'cantidades']

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

        self.cantidades_options = [option for option in self['cantidades']]

    def __str__(self):
        return self.tamanios

HTML:

The label from the first option {{ tamanioscantidades_form.cantidades_options.0.label }} won't render

<ul>
  <h1>{{ tamanioscantidades_form.cantidades.label }}</h1> #This renders
  <li>
     <span> {{ tamanioscantidades_form.cantidades_options.0.tag }}
     <label> {{ tamanioscantidades_form.cantidades_options.0.label }} </label> #This does not render
   </span>
 </li>

like image 208
Omar Gonzales Avatar asked Oct 28 '18 14:10

Omar Gonzales


1 Answers

If I remember correctly RadioSelect widget in template can be iterated. You can read more about it in the documentation.

You are aware that approach below is not the preferred one. Nevertheless, I'm providing it since I'm not sure exactly why you are unable to create relation to cost and savings.

If you provide more information on quantity, cost, savings I might be able to help.


Solution using index of options

Unfortunately what you ask is not possible out of the box. But can be fairly easy done by something like this.

class TamaniosCantidadesForm(forms.ModelForm):
    tamanios = forms.ChoiceField(choices=TAMANIOS, widget=forms.RadioSelect(), label='Selecciona un tamaño')
    cantidades = forms.ChoiceField(choices=CANTIDADES, widget=forms.RadioSelect(), label='Selecciona la cantidad')
    class Meta:
        model = TamaniosCantidades
        fields = ['tamanios', 'cantidades']

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

        self.cantidades_options = [option for option in self['cantidades']]

    def __str__(self):
        return self.tamanios

And then in your template you should be able to do:

<form>
   <div id="quantities">
     <legend> {{ tamanioscantidades_form.cantidades.label }} </legend>

     <ul>
        <li>
        <span>
             {{ tamanioscantidades_form.cantidades_options.0.tag }}
             <label> {{ tamanioscantidades_form.cantidades_options.0.choice_label }} </label>
        </span>
        <span>
             <label>$57</label>
        </span>
        <span>
             <label>""</label>
        </span>
       </li>
     </ul>
    </div>
</form>
like image 125
Kamil Niski Avatar answered Oct 07 '22 18:10

Kamil Niski