Подтвердить что ты не робот

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. Есть идеи?

Спасибо заранее.

4b9b3361

Ответ 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 таким образом, чтобы обращаться с глобальными ключами, не жертвуя безопасностью потоков.