Search code examples
pythondjangodjango-templatesdjango-template-filters

Django Template - Render a field from a form using a string


According to django's docs:

We don’t have to let Django unpack the form’s fields; we can do it manually if we like (allowing us to reorder the fields, for example). Each field is available as an attribute of the form using {{ form.name_of_field }}, and in a Django template, will be rendered appropriately.

Great! I want to make it more complicated... I want to do something to the effect of {{ form."somefield" }} so that way I can essentially do:

{% for i in '012345'|make_list %}
  {% with y=forloop.counter|stringformat:"s" %}
  {% with somefield="somefield"|add:y %}
  {{form.somefield}} #either this
  {{form.somefield|add:y}} #this
  {{form.somefield{{i}}}} #this
  {{form.somefield{{forloop.counter}}}} #this
  #or other variations of that
  {% endwith %}
  {% endwith %}
{% endfor %}

Basically I need to add some variable to the end of the "somefield" attribute to be able to referrence a field that has a number at the end of it.

---EDIT---

This is the full table schema represented in python

from django import forms


class NewGameForm(forms.Form):
    game_name = forms.CharField(max_length=50, required=True, label="", widget=forms.TextInput(attrs={'placeholder': 'Game Name', 'class': 'has-validation form-control'}))
    category1 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 1', 'class': 'form-control mt-1'}))
    category2 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 2', 'class': 'form-control mt-1'}))
    category3 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 3', 'class': 'form-control mt-1'}))
    category4 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 4', 'class': 'form-control mt-1'}))
    category5 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 5', 'class': 'form-control mt-1'}))
    category6 = forms.CharField(max_length=25, required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Category 6', 'class': 'form-control mt-1'}))
    q1values = forms.IntegerField(min_value=0, required=False, label="", widget=forms.TextInput(attrs={'placeholder': '200', 'class': 'form-control'}))
    c1q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c1a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c2q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c2a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c3q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c3a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c4q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c4a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c5q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c5a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c6q1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c6a1 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    q2values = forms.IntegerField(min_value=0, required=False, label="", widget=forms.TextInput(attrs={'placeholder': '400', 'class': 'form-control'}))
    c1q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c1a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c2q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c2a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c3q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c3a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c4q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c4a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c5q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c5a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c6q2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c6a2 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    q3values = forms.IntegerField(min_value=0, required=False, label="", widget=forms.TextInput(attrs={'placeholder': '600', 'class': 'form-control'}))
    c1q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c1a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c2q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c2a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c3q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c3a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c4q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c4a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c5q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c5a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c6q3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c6a3 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    q4values = forms.IntegerField(min_value=0, required=False, label="", widget=forms.TextInput(attrs={'placeholder': '800', 'class': 'form-control'}))
    c1q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c1a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c2q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c2a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c3q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c3a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c4q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c4a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c5q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c5a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c6q4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c6a4 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    q5values = forms.IntegerField(min_value=0, required=False, label="", widget=forms.TextInput(attrs={'placeholder': '1000', 'class': 'form-control'}))
    c1q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c1a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c2q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c2a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c3q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c3a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c4q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c4a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c5q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c5a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))
    c6q5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Question', 'class': 'form-control mt-1'}))
    c6a5 = forms.CharField(required=False, label="", widget=forms.TextInput(attrs={'placeholder': 'Answer', 'class': 'form-control mt-1 mb-1'}))

to give some context:

"category" + [1, 2, 3, 4, 5, 6] are obviously categories. "c1q1" is short for category 1 question 1.

To give an idea as to what the table looks like:

q-values Category1 Category2 Category3 Category4 Category5 Category6
q1values c1q1      c2q1      c3q1      c4q1      c5q1      c6q1
q2values c1q2      c2q2      c3q2      c4q2      c5q2      c6q2
q3values c1q3      c2q3      c3q3      c4q3      c5q3      c6q3
q4values c1q4      c2q4      c3q4      c4q4      c5q4      c6q4
q5values c1q5      c2q5      c3q5      c4q5      c5q5      c6q5

Solution

  • Create a custom template tag filter by creating a templatetags file. (https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/):

    <appname>/templatetags/<appname>_extras.py
    

    The filter has two arguments, the form itself and the field name as a string. Now you can access the fields dictionary. But, be aware that a bound field must be returned. This can be done by the get_bound_field function. (https://docs.djangoproject.com/en/3.2/ref/forms/api/#customizing-boundfield)

    from django import template
    
    register = template.Library()
    
    @register.filter
    def get_field(form, field_name):
        return form.fields[field_name].get_bound_field(form, field_name)
    

    Use it in your template like this:

    {% for i in '012345'|make_list %}
        {% with "somefield"|add:i as field_name %}
            {{ form|get_field:field_name }}
        {% endwith %}
    {% endfor %}
    

    Don't forget to load your custom filters:

    {% load <appname>_extras %}