I'm setting up a flask application to run an anonymous online experiment. How can I track anonymous participants via the the current_user
object of the Login-manager?
When a user is anonymous the current_user
is set to AnonymousUserMixin
. I tried to assign AnonymousUserMixin
an id variable (through uuid.uuid4() for instance) to not have current_user=None
but then it's not an ORM object anymore. I tried to follow the advice of the second answer of this post (How to track anonymous users with Flask), but I'm lacking knowledge how to transform the described way into actual code.
So I ended up with the error message 'AnonymousUserMixin' object has no attribute '_sa_instance_state' which I can't seem to get solved.
Any suggestions on how to use the current_user
object with anonymous users?
Here some relevant code parts [EDIT: code was adjusted based on @Roch's suggestion] :
models.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}')"
routes.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')
Do you want to keep track of the user during the session or after the session ?
If you need to keep some data on the anonymous user during his time using your app, you could easily use Flask session : 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)
If you desire to keep the data of the user after the session is ended, I think the logical thing to do would be to create a user on the fly and log him.
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