使用 Flask-Security 登录时遇到问题:'User' 没有属性 'get_user'
Trouble logging in with Flask-Security: 'User' has no attribute 'get_user'
当我使用 Flask-Security 的登录表单时,出现以下错误。它告诉我我没有 get_user
方法(这是我的 user_datastore
的一部分)。
Traceback (most recent call last):
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1994, in __call__
return self.wsgi_app(environ, start_response)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/decorators.py", line 225, in wrapper
return f(*args, **kwargs)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/views.py", line 75, in login
if form.validate_on_submit():
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_wtf/form.py", line 101, in validate_on_submit
return self.is_submitted() and self.validate()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/forms.py", line 230, in validate
self.user = _datastore.get_user(self.email.data)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/werkzeug/local.py", line 343, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: type object 'User' has no attribute 'get_user'
当我深入研究 Flask-Security 的 datasource.py
时,我看到了以下方法:
def get_user(self, id_or_email):
"""Returns a user matching the specified ID or email address."""
raise NotImplementedError
这似乎是一个抽象方法,必须在我的 User
模型中实现。如果那是真的,为什么 Flask-Security examples 的 none 实现这个方法?如果我尝试将该方法添加到我的 User
模型中,事情也不会变得更好。这是我使用实验覆盖方法的模型:
from extensions import db
from blog.models import Post
from sentence.models import Sentence
from roster.models import Roster
from datetime import datetime
import datetime
from flask_security import UserMixin, RoleMixin
# Helper table for a many-to-many relationship
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
# general variables
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(155))
last_name = db.Column(db.String(155))
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean(), default=True)
confirmed_at = db.Column(db.DateTime())
# app-specific variables
paid_until = db.Column(db.DateTime, default=datetime.datetime.utcnow)
lifetime = db.Column(db.Boolean, default=False)
# relations
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
posts = db.relationship('Post', backref='user', lazy='dynamic')
sentences = db.relationship('Sentence', backref='user', lazy='dynamic')
def __init__(self, **kwargs):
self.password = kwargs['password']
self.email = kwargs['email']
if kwargs.get('first_name', False):
self.first_name = kwargs['first_name']
self.last_name = kwargs['last_name']
# create a roster
roster = Roster("default", self.email)
db.session.add(roster)
db.session.commit()
def __repr__(self):
return '<User %r>' % self.username
# __str__ is required by Flask-Admin (not using?), so we can have human-readable values for the Role when editing a User.
# If we were using Python 2.7, this would be __unicode__ instead.
def __str__(self):
return self.name
# __hash__ is required to avoid the exception TypeError: unhashable type: 'Role' when saving a User
def __hash__(self):
return hash(self.name)
def get_user(self, *args):
# I had to use *args or I'd always get missing 1 required positional argument
for arg in args:
user = User.query.filter_by(email=arg).first()
if user:
return user
'''
def find_user(self, *args, **kwargs):
"""Returns a user matching the provided parameters."""
raise NotImplementedError
def find_role(self, *args, **kwargs):
"""Returns a role matching the provided name."""
raise NotImplementedError
'''
如果我不使用 *args
,上述方法会导致 missing 1 required positional argument
。正如上面所写的模型,应用程序不会崩溃,但会显示 "Specified user does not exist",但事实并非如此,因为我可以在数据库 CLI 中看到用户。那么,我是否需要实施 get_user
方法?
问题出在 Flask 应用程序的 __init__
中。正如所怀疑的那样,Flask-Security 尝试使用用户模型调用 get_user
表明在调用 security.init_app(app, user_datastore)
时传递了错误的对象。来自 user_datastore
实例化的相同参数被重用于 security.init_app()
,这就是错误访问 User 模型的原因。
当我使用 Flask-Security 的登录表单时,出现以下错误。它告诉我我没有 get_user
方法(这是我的 user_datastore
的一部分)。
Traceback (most recent call last):
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1994, in __call__
return self.wsgi_app(environ, start_response)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/decorators.py", line 225, in wrapper
return f(*args, **kwargs)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/views.py", line 75, in login
if form.validate_on_submit():
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_wtf/form.py", line 101, in validate_on_submit
return self.is_submitted() and self.validate()
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/flask_security/forms.py", line 230, in validate
self.user = _datastore.get_user(self.email.data)
File "/home/ubuntu/workspace/my_app/venv/lib/python3.6/site-packages/werkzeug/local.py", line 343, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: type object 'User' has no attribute 'get_user'
当我深入研究 Flask-Security 的 datasource.py
时,我看到了以下方法:
def get_user(self, id_or_email):
"""Returns a user matching the specified ID or email address."""
raise NotImplementedError
这似乎是一个抽象方法,必须在我的 User
模型中实现。如果那是真的,为什么 Flask-Security examples 的 none 实现这个方法?如果我尝试将该方法添加到我的 User
模型中,事情也不会变得更好。这是我使用实验覆盖方法的模型:
from extensions import db
from blog.models import Post
from sentence.models import Sentence
from roster.models import Roster
from datetime import datetime
import datetime
from flask_security import UserMixin, RoleMixin
# Helper table for a many-to-many relationship
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
# general variables
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(155))
last_name = db.Column(db.String(155))
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean(), default=True)
confirmed_at = db.Column(db.DateTime())
# app-specific variables
paid_until = db.Column(db.DateTime, default=datetime.datetime.utcnow)
lifetime = db.Column(db.Boolean, default=False)
# relations
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
posts = db.relationship('Post', backref='user', lazy='dynamic')
sentences = db.relationship('Sentence', backref='user', lazy='dynamic')
def __init__(self, **kwargs):
self.password = kwargs['password']
self.email = kwargs['email']
if kwargs.get('first_name', False):
self.first_name = kwargs['first_name']
self.last_name = kwargs['last_name']
# create a roster
roster = Roster("default", self.email)
db.session.add(roster)
db.session.commit()
def __repr__(self):
return '<User %r>' % self.username
# __str__ is required by Flask-Admin (not using?), so we can have human-readable values for the Role when editing a User.
# If we were using Python 2.7, this would be __unicode__ instead.
def __str__(self):
return self.name
# __hash__ is required to avoid the exception TypeError: unhashable type: 'Role' when saving a User
def __hash__(self):
return hash(self.name)
def get_user(self, *args):
# I had to use *args or I'd always get missing 1 required positional argument
for arg in args:
user = User.query.filter_by(email=arg).first()
if user:
return user
'''
def find_user(self, *args, **kwargs):
"""Returns a user matching the provided parameters."""
raise NotImplementedError
def find_role(self, *args, **kwargs):
"""Returns a role matching the provided name."""
raise NotImplementedError
'''
如果我不使用 *args
,上述方法会导致 missing 1 required positional argument
。正如上面所写的模型,应用程序不会崩溃,但会显示 "Specified user does not exist",但事实并非如此,因为我可以在数据库 CLI 中看到用户。那么,我是否需要实施 get_user
方法?
问题出在 Flask 应用程序的 __init__
中。正如所怀疑的那样,Flask-Security 尝试使用用户模型调用 get_user
表明在调用 security.init_app(app, user_datastore)
时传递了错误的对象。来自 user_datastore
实例化的相同参数被重用于 security.init_app()
,这就是错误访问 User 模型的原因。