2013-05-10 9 views
11

Ho alcuni campi nella pagina con disabilità come ad esempio: (utilizzando il sistema di template Jinja2)campo disabili è considerata per la convalida in WTForms e Flask

<html> 
<body> 
<form action="" method=POST> 
    {{ form.name(disabled=True) }} 
    {{ form.title }} 
    -- submit button -- 
</form> 
</body> 
</html> 

campo è disabilitato nella forma come previsto.

In my views.py: quando si esegue validate_on_submit() sul modulo di invio, non riesce con errore di convalida sul campo "nome" che è disabilitato. Speravo che la validazione ignorasse il campo disattivato. È il comportamento giusto? Se sì, puoi per favore sapere come gestire un caso del genere?

Aggiornato:

class TeamForm(wtf.Form): 
    name = wtf.TextField("Team Name", validators=[validators.Required()]) 
    title = wtf.TextField("Title", validators=[validators.Required()]) 
+0

puoi condividere il tuo codice dei moduli per favore? – codegeek

+0

@codegeek: aggiornato con il codice dei moduli. – rajpy

+0

Puoi fornire qualche informazione su quale sia il tuo obiettivo? 'name' è un campo obbligatorio, ma non stai permettendo che venga fornito un valore. Stai programmando di iniettarne uno a livello di programmazione? – dirn

risposta

19

Questo è in realtà un problema interessante, e il modo in cui risolve WTForms è intenzionalmente qualcosa che richiede esplicitazione, perché ha a che fare con la sicurezza e non permettendo agli utenti di inserire falso.

Quindi l'intento è che i "gestori" non possono modificare il nome, mentre "amministratori" possono.

A prima vista questo sembra ovvio, basta disabilitare il campo in HTML, e scrivere il panorama come questo:

def edit_team(): 
    form = TeamForm(request.POST, obj=team) 
    if request.POST and form.validate(): 
     form.populate_obj(team) # <-- This is the dangerous part here 
     return redirect('/teams') 
    return render('edit_team.html') 

Come scritto, questo è un grande rischio per la sicurezza, perché la proprietà disabile in moduli HTML è lato client solo. Chiunque con un ispettore HTML (ad esempio Firebug, WebKit Controllo documento, ecc) può rimuovere questa proprietà, o qualcuno potrebbe semplicemente fare una richiesta in questo modo:

POST /edit_team/7 HTTP/1.0 
Content-Type: application/x-urlencoded 

team=EVILTEAMNAME&title=foo 

Il problema allora è, naturalmente, come facciamo a porta questo correttamente sul lato server, corrispondente al modo appropriato di farlo? L'approccio corretto con WTForms è a non avere il campo in primo luogo. Ci sono alcuni modi per farlo, uno è usare la composizione del modulo e avere ad es. ManagerTeamForm e AdminTeamForm (a volte è meglio), ma altre volte è più semplice da eseguire su use del to remove specific fields.

Quindi, ecco come si può scrivere la vostra vista, e non hanno i problemi di convalida:

def edit_team(): 
    form = TeamForm(request.POST, obj=team) 
    if user.role == 'manager': 
     del form.name 
    if request.POST and form.validate(): 
     form.populate_obj(team) 
     return redirect('/teams') 
    return render('edit_team.html') 

e una rapida modifica al modello:

<html> 
<body> 
<form action="" method=POST> 
    {% if 'name' in form %} 
     {{ form.name() }} 
    {% else %} 
     {{ team.name|e }} 
    {% endif %} 
    {{ form.title }} 
    -- submit button -- 
</form> 
</body> 
</html> 

Alcuni pezzi di riferimento per wtforms best- pratiche:

+0

Grazie per la spiegazione dettagliata. Ho finito con l'eliminare i campi del modulo come hai detto tu. Ma il campo idealmente "disabilitato" non verrà inviato per l'elaborazione dei moduli. Non è giusto? – rajpy

+0

WTForms non interpreta gli attributi di visualizzazione nel tuo modello come disabilitato, display, visibilità, readonly, ecc (ce ne sono così tanti e sono così vari), considera anche che il rendering avvenga dopo la validazione (e il rendering generalmente non avviene se il form validates) quindi l'unico modo per dire a wtforms che non deve essere guardato è quello di eliminare il campo. – Crast

+1

@rajpy, forse "disabilitato" è un termine improprio. L'attributo controlla se l'utente è autorizzato a modificare il valore, non se influenza effettivamente il comportamento sul server. A volte è utile mostrare all'utente quali dati vengono inviati al server ma non consentire loro di modificare il valore. – MageWind

1

Hai bisogno di fare il campo nome opzionale per la definizione del modulo.

name = wtf.TextField("Team Name", validators=[validators.Optional()]) 

Poi, nel vostro punto di vista, passare una variabile denominata "ruolo" e impostarlo a uno manager o amministratore a seconda dell'utente.

<form action="" method=POST> 
{% if role == 'manager' % } 
    {{ form.name(disabled=True) }} 
{% else % } 
    {{ form.name() }} 
{{ form.title }} 
-- submit button -- 
</form> 
+0

In questo caso, funzionerà. Ma voglio che il nome venga fornito da admin durante la creazione del team e non dovrebbe essere facoltativo. – rajpy

+2

Questo è anche un rischio per la sicurezza, perché un "manager" di posta potrebbe ancora inviare i dati, anche se il campo è disabilitato sul lato client e chiunque è autorizzato a cancellare i dati. – Crast

+0

Funziona ma effettua una convalida di sicurezza prima di salvare i valori. – Thiago

0

ho definito il mio validatore per questo problema:

from wtforms.validators import Optional 

class OptionalIfDisabled(Optional): 

    def __call__(self, form, field): 
     if field.render_kw is not None and field.render_kw.get('disabled', False): 
      field.flags.disabled = True 
      super(OptionalIfDisabled, self).__call__(form, field) 

E poi ho definito una nuova base per i miei moduli:

Ora ogni modulo può estendere il BaseForm e campi di disabilitare come questo:

from wtforms.fields import StringField, SubmitField 

class TeamForm(BaseForm): 
    team = StringField(label='Team Name', 
         validators=[OptionalIfDisabled(), InputRequired()] 
    submit = SubmitField(label='Submit') 

    def __init__(self, *args, **kwargs): 
     super(TeamForm, self).__init__(*args, **kwargs) 
     # disable the fields if you want to 
     if some_condition: 
      self.team.render_kw = {'disabled': True} 

Dopo la convalida del TeamForm, è possibile utilizzare populate_obj per copiare i dati del modulo abilitati in qualsiasi oggetto. Ignorerà i campi disabilitati.

Problemi correlati