Flask-login — AttributeError: объект AnonymousUserMixin не имеет атрибута «_sa_instance_state»

Я настраиваю фляжное приложение для запуска анонимного онлайн-эксперимента. Как я могу отслеживать анонимных участников через объект current_user Логин-менеджера?

Когда пользователь является анонимным, current_user устанавливается на AnonymousUserMixin. Я попытался присвоить AnonymousUserMixin переменную id (например, через uuid.uuid4()), чтобы не было current_user=None, но тогда это больше не объект ORM. Я попытался последовать совету второго ответа на этот пост (Как отслеживать анонимные пользователей с Flask), но мне не хватает знаний, как превратить описанный способ в реальный код.

Итак, я получил сообщение об ошибке «У объекта AnonymousUserMixin» нет атрибута «_sa_instance_state», который я не могу решить.

Любые предложения о том, как использовать объект current_user с анонимными пользователями?

Вот некоторые соответствующие части кода [EDIT: код был скорректирован на основе предложения @Roch]:

модели.py

from website import db


# models for database structure
class DemographicData(db.Model):
    __tablename__ = 'demographic_data'
    id = db.Column(db.Integer, primary_key=True)
    gender = db.Column(db.String(1), nullable=False)
    age = db.Column(db.Integer, nullable=False)
    nationality = db.Column(db.String(50), nullable=False)
    # create relationships to the other models to link them to the demographicData
    consentRequest = db.relationship('ModalData', backref='participant_bref', lazy=True)


    def __repr__(self):
        return f"demographicData('{self.id}', '{self.gender}', '{self.age}', '{self.nationality}')"


class ModalData(db.Model):
    __tablename__ = 'modal_data'
    id = db.Column(db.Integer, primary_key=True)
    participantId = db.Column(db.Integer, db.ForeignKey('demographic_data.id'), nullable=False)
    consent = db.Column(db.String(3), nullable=False)

    def __repr__(self):
        return f"modalData('{self.participantId}', '{self.consent}')"

маршруты.py

from flask import render_template, url_for, redirect, request, session
from website import app, db
from website.models import DemographicData, ModalData
from website.questionnaires import DemographicsForm



@app.before_request
def make_session_permanent():
    session.permanent = True



# route to demographic information form
@app.route("/demographics", methods=['GET', 'POST'])
def demographics():
    form = DemographicsForm()
    if form.validate_on_submit():
        participant = DemographicData(gender=form.gender.data,
                                      age=form.age.data,
                                      nationality=form.nationality.data)
        session['anonymous_user_id'] = participant.id
        # save to database
        db.session.add(participant)
        db.session.commit()
        return redirect(url_for('megazine')) 
    return render_template('demographics.html', title='Demographic Information', form=form)



# route to a website I want to redirect to after demographics
@app.route("/megazine", methods=['GET', 'POST'])
def megazine():
    if request.method == 'POST':
        consentDecision = ModalData(participant_bref=session['anonymous_user_id'],
                                    consent=request.form['consentForm'])
        db.session.add(consentDecision)
        db.session.commit()
        return redirect(url_for('motivemag'))
    return render_template('/newswebsite_templates/megazine/index.html', title='Megazine')


person paulklee    schedule 04.02.2019    source источник


Ответы (1)


Вы хотите отслеживать пользователя во время сеанса или после сеанса?

Если вам нужно сохранить некоторые данные об анонимном пользователе во время его использования вашего приложения, вы можете легко использовать сеанс Flask: http://flask.pocoo.org/docs/1.0/api/#flask.session

from flask import session

@app.route('/my_url1')
def my_view1():
    data = None
    if session.new:
         # ... do something like save data in the session
         session['foo'] = 'bar'
    # ... do something like read data in the session
    data = session['foo']
    return render_template('/my_template.html', data=data)

Если вы хотите сохранить данные пользователя после завершения сеанса, я думаю, что логичным было бы создать пользователя на лету и зарегистрировать его.

from flask import session    
from models import User

@app.route('/my_url1')
def my_view1():
    data = None
    if session.new:
         user = User()
         session['anonymous_user_id'] = user.id
    else:
         user = User.query.get(session['anonymous_user_id'])
    # ... do whatever you like
person Roch    schedule 05.02.2019
comment
Я хотел бы создать уникальный случайный идентификатор для каждого анонимного пользователя, чтобы отслеживать пользователя между различными формами, к которым я его направлю. Я думал, что смогу сделать это с помощью модуля flask-login (сохранив идентификатор current_user в моей базе данных), но поскольку он ориентирован на вход/выход из системы, а не столько на анонимных пользователей, я не мог понять, как добавить идентификатор каждому анонимному пользователю. без получения ошибки, указанной в шапке. - person paulklee; 05.02.2019
comment
В этом случае просто используйте сеанс, предоставленный flask. Это делается для этой цели. - person Roch; 05.02.2019
comment
Но, как вы сказали, если я хочу сохранить данные пользователя после завершения сеанса, я должен создать пользователя на лету и зарегистрировать его. Можете ли вы указать мне направление, как лучше всего назначить идентификатор пользователю и зарегистрировать его (какой-нибудь пример кода?)? (учитывая, что сейчас я не использую модуль flask-login). Спасибо за вашу помощь. - person paulklee; 06.02.2019
comment
Как я уже сказал, в вашем случае вы можете использовать сеанс для сохранения данных, которые вам нужны для других запросов. Я обновил основной ответ, чтобы дать вам код. - person Roch; 06.02.2019
comment
Спасибо @Roch. Хотя я получаю следующую ошибку, когда пытаюсь использовать объект session.anonymous_user_id в другом @app.route (например, для ссылки через обратную ссылку на определенного пользователя user=session.anonymous_user_id): AttributeError: объект «SecureCookieSession» не имеет атрибута «anonymous_user_id» - person paulklee; 07.02.2019
comment
Не могли бы вы поделиться своим новым кодом в начальном вопросе? - person Roch; 08.02.2019
comment
отредактировал части кода. Так что в основном я получаю сообщение об ошибке, если использую session.anonymous_user_id в маршруте мегазина, возможно, потому, что он был создан в маршруте демографии. Но я думал, что идея сеансов заключается в том, что это возможно (связывание объектов по маршрутам). - person paulklee; 11.02.2019
comment
Привет. Я немного ошибся в своем примере. Данные, связанные с сеансом, хранятся как словарь, а не как атрибуты. Итак, вам нужно использовать: session['anonymous_user_id'] - person Roch; 11.02.2019
comment
Спасибо, это избавило от первоначальной ошибки, но каким-то образом связь между идентификатором, созданным в демографическом маршруте, к которому нужно снова обращаться в маршруте мегазина, по-прежнему не работает. Переменная consentDecision, которую я хочу добавить в базу данных в маршруте мегазина, всегда имеет None в качестве идентификатора участника, что означает, что она не может получить идентификатор, сохраненный в сеансе. Есть ли что-то еще, о чем следует помнить при работе с сессиями? Я опубликую ошибку, которую я получаю, в новом комментарии. (кстати, я снова изменил исходный код) - person paulklee; 12.02.2019
comment
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) Ошибка ограничения NOT NULL: modal_data.participantId [SQL: «ВСТАВИТЬ В modal_data (participantId, согласие) ЗНАЧЕНИЯ (?,?)»] [параметры: (Нет, «ДНК»)] (Справочная информация об этой ошибке: sqlalche.me/e/gkpj) - person paulklee; 12.02.2019
comment
Когда вы создаете пользователя, у него нет идентификатора до того, как он будет сохранен в базе данных. Так что session['anonymous_user_id'] = participant.id следует вызывать после db.session.commit() - person Roch; 14.02.2019
comment
Я понял это и вчера вечером, вы правы. Это была моя первая ошибка. Вторая ошибка заключалась в том, что я должен был сделать вызов базы данных в маршруте мегазина и присвоить идентификатор из DemographicsData какой-то переменной, которую затем я могу связать с обратной ссылкой в ​​ModalData participant = DemographicData.query.get(session['anonymous_user_id']). Спасибо за все ваши усилия. - person paulklee; 14.02.2019