Проблемы со входом в 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 был получен ошибочный доступ.

Другие вопросы по тегам