Проблемы со входом в Flask-Security: у пользователя нет атрибута 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'
Когда я копался в Фляске-Безопасности datasource.py
Я вижу следующий метод:
def get_user(self, id_or_email):
"""Returns a user matching the specified ID or email address."""
raise NotImplementedError
Это похоже на абстрактный метод и должно быть реализовано в моем User
модель. Если это правда, почему ни один из примеров Flask-Security не реализует этот метод? Если я попытаюсь добавить метод в мой 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
'''
Приведенный выше подход приводит либо к missing 1 required positional argument
если я не использую *args
, Как написано выше, приложение не аварийно завершает работу, а говорит: "Указанный пользователь не существует", что не так, как я вижу пользователя в CLI базы данных. Итак, мне нужно реализовать get_user
метод?
1 ответ
Проблема была в приложении Flask __init__
, Как и предполагалось, Flask-Security пытается позвонить get_user
использование модели User показало, что при вызове был передан неверный объект security.init_app(app, user_datastore)
, Те же параметры из экземпляра user_datastore
были повторно использованы для security.init_app()
именно поэтому к модели User был получен ошибочный доступ.