Apresentação separada da lógica com WTForms
-
21-12-2019 - |
Pergunta
Estou apenas me familiarizando com Flask, WTForms (e flask-WTF).Sinto que estou perdendo alguma coisa.
De acordo com Documentos WTForms "o HTML do seu campo de formulário pode ser gerado para você, mas permitimos que você o personalize em seus modelos.Isso permite que você mantenha a separação entre código e apresentação e mantenha esses parâmetros confusos fora do seu código python."
O método sugerido para modelar entradas de rádio HTML é:
class ExmapleForm(Form):
language = RadioField(u'Programming Language', choices=[('py', 'Python'), ('js', 'JavaScript')])
....e a maneira sugerida de modelar entradas de rádio HTML é:
{% for subfield in form.radio %}
<tr>
<td>{{ subfield }}</td>
<td>{{ subfield.label }}</td>
</tr>
{% endfor %}
Com essa abordagem, a propriedade de escolhas "que é uma sequência de pares (valor, rótulo)" não está misturando a apresentação com os modelos?
Existe uma maneira de mover o rótulo para o modelo e combiná-lo com o valor?
Solução
Pergunta interessante.Se pensarmos em termos do padrão MVC, acho que a lista de opções que aparece em um menu suspenso pertence ao Modelo, não à Visualização.Então eu não teria essas escolhas definidas pelo designer no template.Acredito que concordamos nisso, certo?
Ter a lista de opções codificadas no formulário como no seu exemplo é melhor, mas também não é o ideal.Provavelmente você tem um Language
modelo ou entidade semelhante, correto?Esse modelo é a autoridade em escolhas válidas de linguagem de programação, portanto deve ser aquele que fornece a lista de escolhas válidas para qualquer pessoa, seja um formulário ou outro subsistema.
Como você mencionou na sua pergunta, cada opção possui um nome interno e um nome de exibição.E já que estamos falando de strings de exibição, não vamos esquecer que o u'Programming Language'
o título do seu campo se enquadra na mesma categoria de strings de exibição.Essas strings deveriam ser de responsabilidade do designer do modelo?Não sei, isso é uma zona cinzenta entre modelo e apresentação, acho que o designer deveria ter autoridade na aparência das coisas, mas não no conteúdo.
Se você quiser ter mais controle sobre a aparência dessas strings de exibição, poderá usar um kit de ferramentas de tradução como o gettext (por meio do Flask-Babel, por exemplo).Se seu aplicativo renderizar texto por meio de gettext, você poderá mapear quaisquer strings do código ou do modelo para outras strings.Isso é usado para traduzir para outros idiomas, mas você também pode usá-lo para ter controle separado sobre como as strings são exibidas no idioma nativo do aplicativo.O mapeamento é feito em um arquivo de dados externo, então acho que isso alcança a independência que você procura.
Outras dicas
do ponto de vista puramente teórico que não parece ser uma boa ideia.Se você tivesse que conectar o rótulo com o valor real no modelo, isso significaria ter uma lógica de negócios no modelo.
Além disso, como você imagina o código exato fazendo isso?Isso exigiria o subcampo-contexto dentro da instrução atribuindo o rótulo.Eu não posso imaginar esse código é bom no modelo.E seria parte da lógica de apresentação como deveria?
Aqui está a solução que encontrei (para manter a separação).Pode ser um exagero, mas vou experimentar e ver como ele se adapta.
Em formulários.py:
import sys
sys.path.append("templates")
import constants
class ExmapleForm(Form):
language = RadioField('language', choices=constants.languages['choices'], validators=constants.languages['validators'])
Então criei um arquivo na pasta de templates chamado constantes.py:
from wtforms.validators import InputRequired
languages = {
'choices': [
('py', 'Python'),
('js', 'JavaScript')
],
'validators': [
InputRequired(message = 'Please Select')
]
}
Espero que ajude (e dê certo)