UndefinedError: "пользователь" - undefined
В настоящее время я разрабатываю приложение Flask (было в прошлом году), и я встречаю довольно... странную ошибку. У меня есть несколько файлов, которые всегда включены в мои шаблоны Jinja2 (navbars), и они используют имя и аватар пользователей. Как следствие, каждый раз, когда я создаю шаблон, я передаю его пользователю. Недавно я заметил ошибку на моем сервере prod:
<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
Это один из моих навигаторов. Метод, который отображает этот шаблон, использует это:
@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)
Как вы можете видеть, я передаю user = g.user. Я делаю это на каждом взгляде на свой сайт. И он работает повсюду, ЗА ИСКЛЮЧЕНИЕМ этого метода, который довольно мал. У меня есть много других подобных маршрутов, только с шаблоном рендеринга, поэтому я не понимаю, в чем проблема.
Я также получаю его по другому методу, больше, который всегда работал раньше:
@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())
Когда я впервые загружаю форму для добавления пользователя, она работает. Когда я добавляю его, по какой-то причине я получаю ошибку (и пользователь не сохраняется в базе данных).
Так как это отлично работает на локальном уровне, я начинаю подозревать проблему на самом производственном сервере. Мы используем nginx и uwsgi для приложения, и недавно я реализовал некоторые задачи Celery. Есть идеи?
Спасибо заранее.
Ответы
Ответ 1
Флажок источник для render_template:
Он просто вызывает template.render(context)
, но после вызова before_render_template.send(app, template=template, context=context)
Из этого, я думаю, есть некоторый обработчик before_render_template
, который изменяет установленный контекст.
Чтобы отладить это, я могу попытаться вызвать что-то вроде этого:
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,
))
Если это сработает, мне нужно будет выкопать, кто изменяет контекст в слоте before_render_template
.
Ответ 2
Я подозреваю, что это нить. Если g - это какая-то глобальная ссылка, вам может потребоваться убедиться, что она настроена на threading.local или что блокировки потоков используются, чтобы гарантировать, что нить не сможет захватить g.user до того, как некоторые "другие" потоки с ним.
См. как сделать файлообменник контекста 2.7 на уровне python таким образом, чтобы обращаться с глобальными ключами, не жертвуя безопасностью потоков.