Question

I'm just familiarizing myself with Flask, WTForms (and flask-WTF). I feel like I'm missing something.

According to the WTForms docs "your form field HTML can be generated for you, but we let you customize it in your templates. This allows you to maintain separation of code and presentation, and keep those messy parameters out of your python code."

The suggested method of modeling HTML radio inputs is:

class ExmapleForm(Form):
    language = RadioField(u'Programming Language', choices=[('py', 'Python'), ('js', 'JavaScript')])

....and the suggested way to template HTML radio inputs is:

{% for subfield in form.radio %}
    <tr>
        <td>{{ subfield }}</td>
        <td>{{ subfield.label }}</td>
    </tr>
{% endfor %}

With this approach, isn't the choices property "which is a sequence of (value, label) pairs" mixing the presentation with the models?

Is a way to move the label to the template and match it with the value?

Was it helpful?

Solution

Interesting question. If we think in terms of the MVC pattern I think the list of choices that go in a dropdown belong in the Model, not in the View. So I would not have these choices defined by the designer in a the template. I believe we agree on this, right?

Having the list of choices hardcoded in the form as in your example is better, but it is also not ideal. Presumably you have a Language model or similar entity, correct? That model is the authority on valid programming language choices, so it should be the one that provides the list of valid choices to anyone, be it a form or other subsystem.

As you mention in your question, each choice has an internal name and a display name. And since we are talking about display strings, let's not forget that the u'Programming Language' title for your field falls in the same category of display strings. Should these strings be the responsibility of the template designer? I don't know, this is a grey area between model and presentation, I think the designer should have authority on how things look, but not on the content.

If you wanted to have more control on how these display strings look you could use a translation toolkit such as gettext (through Flask-Babel, for example). If your application renders text through gettext you can map any strings from the code or the template into other strings. This is used to translate into other languages but you can also use it to have separate control on how strings display in the native language of the application. The mapping is done in an external data file, so I think this achieves the independence you are looking for.

OTHER TIPS

From purely theoretical point of view that doesn't seem to be a good idea. If you had to connect the label with actual value in the template then this would mean having a business logic in the template.

Furthermore how would you envision the exact code doing that? It would require subfield-context within the statement assigning the label. I cannot imagine that code looking good in the template. And would it be part of presentation logic as it should?

Here's the solution I came up with (to maintain separation). It may be overkill, but I'm going to try it out and see how it scales.

In forms.py:

import sys
sys.path.append("templates")
import constants

class ExmapleForm(Form):
    language = RadioField('language', choices=constants.languages['choices'], validators=constants.languages['validators'])

Then I created a file in the templates folder called constants.py:

from wtforms.validators import InputRequired

languages = {
    'choices': [
        ('py', 'Python'),
        ('js', 'JavaScript')
    ],
    'validators': [
        InputRequired(message = 'Please Select')
    ]
}

Hope it helps (and works out)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top