2012-12-07 1 views
5

Sto tentando di utilizzare flask.g per memorizzare le variabili a cui è possibile accedere in altre funzioni, ma non sembra che stia facendo qualcosa correttamente. L'applicazione genera il seguente errore quando provo ad accedere a g.name: AttributeError: '_RequestGlobals' object has no attribute 'name'.Impossibile utilizzare flask.g per accedere alle variabili in altre funzioni

Il documentation per flask.g dice:

Proprio Negozio su questo quello che vuoi. Per esempio una connessione al database o l'utente attualmente connesso.

Ecco un completo esempio minimo che illustra l'errore che ricevo quando si cerca di accedere alla variabile al di fuori della funzione è stato creato in. Qualsiasi l'aiuto sarebbe molto apprezzato.

#!/usr/bin/env python 

from flask import Flask, render_template_string, request, redirect, url_for, g 
from wtforms import Form, TextField 

application = app = Flask('wsgi') 

@app.route('/', methods=['GET', 'POST']) 
def index(): 
    form = LoginForm(request.form) 

    if request.method == 'POST' and form.validate(): 
     name = form.name.data 
     g.name = name 

     # Need to create an instance of a class and access that in another route 
     #g.api = CustomApi(name) 

     return redirect(url_for('get_posts')) 

    else: 

     return render_template_string(template_form, form=form) 

@app.route('/posts', methods=['GET']) 
def get_posts(): 
    # Need to access the instance of CustomApi here 
    #api = g.api 
    name = g.name 
    return render_template_string(name_template, name=name) 


class LoginForm(Form): 
    name = TextField('Name') 

template_form = """ 
{% block content %} 
<h1>Enter your name</h1> 

<form method="POST" action="/"> 
    <div>{{ form.name.label }} {{ form.name() }}</div><br> 
    <button type="submit" class="btn">Submit</button>  
</form> 
{% endblock %} 

""" 

name_template = """ 
{% block content %} 

    <div>"Hello {{ name }}"</div><br> 

{% endblock %} 

""" 

if __name__ == '__main__': 
    app.run(debug=True) 

risposta

2

Se è necessario tracciare le informazioni di autenticazione, suggerirei uno dei plugin Flask come Flask-Login o Flask-Principal.

Ad esempio, utilizziamo Flask-Principal. Solleva il segnale caricato identità quando qualcuno autentica (o rileva un cookie di autenticazione). Quindi mappiamo la loro identità registrata con un utente nel nostro database. Qualcosa di simile a questo:

# not actual code 
@identity_loaded.connect_via(app) 
def on_identity_loaded(sender, identity): 
    user = Person.query.filter(Person.username==identity.person.username).one() 
    g.user = user 

e quindi possiamo utilizzare g.user in qualsiasi controller o modello. (Stiamo in realtà strappa un sacco di questo fuori, si trattava di un semplice, hack pigro che ha causato più problemi che ne vale la pena.)

Se non si desidera utilizzare un modulo, c'è un built-in segnale che si può agganciarsi all'inizio di ogni richiesta:

http://flask.pocoo.org/docs/tutorial/dbcon/

# This runs before every request 
@app.before_request 
def before_request(): 
    g.user = your_magic_user_function() 

e g.user sarebbe allora magicamente disponibile ovunque.

Spero che questo aiuti!

+0

Il problema con l'utilizzo di @ app.before_request nel mio caso è che ho bisogno di ottenere il nome utente e le informazioni sulle password da parte dell'utente per utilizzare il mio magic_user_function(). Controllo i moduli che hai menzionato. – Raj

+0

Pensavo che avrei seguito per farti sapere che questo era quello che ho finito per fare. Ho dovuto riscrivere il mio wrapper per supportare questo metodo, ma non era male. Grazie per le risposte alle mie domande sul Flask tra Rachel! – Raj

13

L'oggetto g è un oggetto di richiesta-based e non persiste tra le richieste, vale a dire g si ricrea tra la richiesta di index e la vostra richiesta a get_posts.

Application Globals in Flask:

Flask fornisce un oggetto speciale che assicura che è valido solo per la richiesta attiva e che restituirà valori diversi per ogni richiesta. In poche parole: fa la cosa giusta, come fa per richiesta e sessione.

Per la memorizzazione persistente di piccoli dati tra le richieste, utilizzare invece sessions. È possibile (ma non dovrebbe) evitare di archiviare i dati nell'oggetto app direttamente per lo stato dell'applicazione globale (tutte le sessioni), in modo analogo a ciò che fa config, se si trova una buona ragione per farlo.

Per i dati più complessi utilizzare i database.

+1

Capisco la vostra risposta per piccole porzioni di informazioni come variabili semplici, ma come faccio a creare un'istanza di una classe e di condivisione che tutta più funzioni? Nello specifico sto creando un'istanza di una classe che restituisce le informazioni di autenticazione e mi piacerebbe utilizzare i dati restituiti in più percorsi. – Raj

+0

Usare la 'sessione' per ricostruire i propri oggetti attraverso le richieste sarebbe la via più facile da percorrere. Come memorizzare il 'user_id', forse. Anche la serializzazione può funzionare. Scegli il metodo con meno overhead e più leggibilità e senso. – soulseekah

+1

@Raj Questa dovrebbe essere la risposta accettata in quanto definisce perché 'g.users' non ha funzionato per te. –

1

Basta usare le sessioni nel pallone. Nel tuo caso, vuoi solo salvare l'utente/nome nella richiesta e il modo più semplice è usare le sessioni.

from flask import session 
app.secret_key = 'some key for session' 

Poi, le funzioni potrebbe essere modificato come segue:

@app.route('/', methods=['GET', 'POST']) 
def index(): 
    form = LoginForm(request.form) 
    if request.method == 'POST' and form.validate(): 
     session['name'] = form.name.data 
     return redirect(url_for('get_posts')) 
    else: 
     return render_template_string(template_form, form=form) 

@app.route('/posts', methods=['GET']) 
def get_posts(): 
    if 'name' in session: 
     name = session['name'] 
    else: 
     name = "Unknown" 
    return render_template_string(name_template, name=name)