'Flask: How to access current user when creating forms?
I have found this question asked in various ways slightly different but the answers seemed old or not quite what I was looking for. I have a functioning Flask application with Flask-Security and some WTF Forms. Users can login, fill up forms and all, everything is fine.
Now, I have the need to access a user setting (shirt size) while creating a form so it is displayed to the user as they fill the form (so this is not a validation problem).
I added to the form file:
from flask_security import current_user
to access the setting current_user.ts_size
but I am faced with the AttributeError: 'NoneType' object has no attribute 'ts_size'
I understand that this means that current_user is of NoneType, the question is why? I am using the same import line in the file that defines the views without any problem. The views are decorated with auth_required
so by the time a form needs to be created and displayed to the user, it is already check that the user is authenticated.
What am I missing?
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
from flask_security import current_user
class JacketForm(FlaskForm):
material = StringField(validators=[DataRequired()],)
size = StringField(validators=[DataRequired()], description=current_user.ts_size)
Solution 1:[1]
There are a few things going on on your code. First - remember that the field definitions are class variables - so those don't change when a form is instantiated. Second - StringField doesn't have a keyword argument 'cur_size' - it does have a keyword argument 'default' - which can be a callable!
So try something like:
size = StringField(validators=[DataRequired()], default=lambda: current_user.ts_size)
Solution 2:[2]
The statement:
size = StringField(validators=[DataRequired()], description=current_user.ts_size
may be correct, but not appropriate.
Remember Flask handles view functions, models, templates and forms separately. Therefore, the size field should only be allowed to pick a field which is Sting type, as you have specified and perhaps validators. Not the user
as you have specified above, if the concept of separation is to be maintained.
In the view
function is where you now link the size field
to the current user
. You can do this by: While in the view function
that calls the the JacketForm
, call the current user id using current_user.get_id
. With the user's id then use it query for the ts_size
field, pick the string value and store it there.
You will need the import statement from flask_login import current_user
in the view function to ensure that it is the current user, that is, the user logged in, is the one allowed to fill in the JacketForm
.
Remember also this will happen if your model - database correctly connects the user table
to the jacket table
or whichever name you have given it, through correct relationship.
I have just tried to explain what I will do without writing any code, mainly because you have only provided one form. It is not clear how you have defined your view functions or tables in the database to have an overall picture. And if you are able to it, then you will be learning. The take way is that the size
field in the JacketForm
should never have the user specified there, only the type of field and validators. What the field finally picks is provided in the view
function that makes use of the JacketForm
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jwag |
Solution 2 |