2015-06-01 10 views
22

Attualmente sto sviluppando un'applicazione Flask (sono stato nell'ultimo anno) e sto incontrando un bug piuttosto strano. Ho alcuni file che sono sempre inclusi nei miei modelli Jinja2 (navbars) e usano il nome e l'avatar degli utenti. Di conseguenza, ogni volta che eseguo il rendering di un modello, lo passo all'utente. Di recente ho notato un errore sul mio server prod:UndefinedError: 'user' non è definito

<img alt="image" class="img-circle" src="{{ user.image }}" style="width: 48px;"/> 
    File "/usr/local/lib/python2.7/dist-packages/jinja2/environment.py", line 397, in getattr 
    return getattr(obj, attribute) 
jinja2.exceptions.UndefinedError: 'user' is undefined 

Questo è in uno dei miei navbar. Il metodo che rende questo modello utilizza questo:

@mod.route('/broken_pus', methods=['POST', 'GET']) 
def view_broken_pus(): 
    return render_template("view_broken_pus.html", user=g.user, urls_for_active_clients=DeletedURLs.objects()[0].urls_for_active_clients, other_urls=DeletedURLs.objects()[0].other_urls) 

Come si può vedere, ho passato l'utente = g.user. Lo faccio su ogni singola vista del mio sito web. E funziona ovunque, TRANNE su questo metodo, che è piuttosto piccolo. Ho molte altre rotte del genere, con solo un template di rendering, quindi non capisco quale sia il problema.

Ho anche su un altro metodo, più grande, che ha sempre lavorato prima:

@mod.route('/users/add', methods=['GET', 'POST']) 
@requires_roles("admin", "project-leader") 
def add(): 
    """ 
    Method adding a new user. 
    """ 
    # We do not use WTForms there since we need custom checkboxes for the role 
    # Instead we use basic HTML and treat the checkboxes here 
    if request.method == 'POST': 
     user = User(name=request.form.get('name'), 
        email=request.form.get('email')) 
     l = [] 
     # big switch assignement 
     user.role = l 
     try: 
      user.save() 
     except errors.NotUniqueError: 
      flash(u'User %s already in database.' % user.name, 'danger') 
      return redirect(url_for('home')) 
     flash(u'User %s registered.' % user.name, 'success') 
     return redirect(url_for('home')) 
    return render_template('add_user.html', page=url_for('users.add'), user=g.user, clients=Client.objects()) 

Quando ho caricare il modulo per l'aggiunta di un utente, funziona. Quando lo aggiungo, per qualche ragione, ottengo l'errore (e l'utente non è salvato nel database).

Dato che funziona perfettamente su locale, sto iniziando a sospettare un problema sul server di produzione stesso. Usiamo nginx e uwsgi per l'app e recentemente ho implementato alcune attività di Celery. Hai qualche idea?

Grazie in anticipo.

+0

È possibile stampare 'g.user' prima di' rendering_template' per vedere cosa succede? – skyline75489

+0

Lo visualizza come oggetto utente, quindi sembra che sia stato definito correttamente a questo punto! – lap0573

+0

Hai provato a rimuovere la proprietà 'urls_for_active' e lasci solo' user = g.user'? – skyline75489

risposta

1

Partenza pallone source for render_template:

Chiede solo template.render(context), ma dopo la chiamata a before_render_template.send(app, template=template, context=context)

Da questo, penso che ci sia qualche before_render_template gestore, che modifica installato contesto.

eseguire il debug di questo in giù, posso provare a chiamare qualcosa di simile:

from flask import app 

@mod.route('/broken_pus', methods=['POST', 'GET']) 
def view_broken_pus(): 
    template = app.jinja_env.get_or_select_template("view_broken_pus.html") 
    return template.render(dict(
     user=g.user, 
     urls_for_active_clients=DeletedURLs.objects()[0].urls_for_active_clients, 
     other_urls=DeletedURLs.objects()[0].other_urls, 
    )) 

Se questo lavoro, ho bisogno di scavare in chi modifica contesto in before_render_template slot.

0

Sospetto filettatura. Se g è una sorta di riferimento globale, potrebbe essere necessario assicurarsi che sia impostato su threading.local o che i lock di threading siano utilizzati per garantire che nessun thread possa accedere a g.user prima che un 'altro' thread lo danneggi .

Vedere how do I make a 2.7 python context manager threadsafe per un modo di gestire "globali" senza sacrificare la sicurezza del thread.