AttributeError: объект 'User' не имеет атрибута 'get' - класс пользователя Flask-Login с PyMongo

Я создал пользовательский класс для Flask-Login, как показано ниже:

@login_manager.user_loader
def load_user(user_id):
    users = mongo.db.users
    u = users.find_one({"_id": user_id})
    return User(u)

class User(UserMixin):

    def __init__(self, user_json):
        self.user_json = user_json

    def is_authenticated(self):
        return True

    def is_anonymous(self):
        return False

    def is_active(self):
        return True

    def get_id(self):
        object_id = self.user_json.get('_id')
        return str(object_id)

    def get_reset_token(self, expires_sec=3600):
        s = Serializer(app.config['SECRET_KEY'], expires_sec)
        id = str(self.user_json.get('_id'))
        return s.dumps({'user_id': id}).decode('utf-8')


    @staticmethod
    def verify_reset_token(token):
        s = Serializer(app.config['SECRET_KEY'])
        try:
            user_id = s.loads(token)['user_id']
        except:
            return None
        return load_user(user_id)

и у меня есть маршрут учетной записи пользователя, где пользователь должен иметь возможность редактировать и удалять свою учетную запись. Однако, чтобы получить пользователя и обновить / удалить из базы данных, мне нужно использовать код pymongo:

users = mongo.db.users
user = users.find_one({'_id': user_id})

or

user = users.find_one({'email': user_email})

чтобы получить соответствующего пользователя из базы данных, и для этого мне нужно получить идентификатор от текущего пользователя. Когда я пробую current_user.get_id (), я получаю следующую ошибку:

builtins.AttributeError
AttributeError: 'NoneType' object has no attribute 'get'

Traceback (most recent call last)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/leawhitelaw/enu_group_project/src/app_f/routes.py", line 135, in account
current_user.get_id()
File "/Users/leawhitelaw/enu_group_project/src/app_f/db_classes.py", line 29, in get_id
object_id = self.user_json.get('_id')
AttributeError: 'NoneType' object has no attribute 'get'

и если я попытаюсь применить User к current_user (отмечая, что current_user является атрибутом flask-login), я получаю сообщение об ошибке:

builtins.AttributeError
AttributeError: 'User' object has no attribute 'get'

Traceback (most recent call last)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/leawhitelaw/enu_group_project/src/app_f/routes.py", line 126, in account
user.get_id()
File "/Users/leawhitelaw/enu_group_project/src/app_f/db_classes.py", line 29, in get_id
object_id = self.user_json.get('_id')
File "/usr/local/lib/python3.7/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'User' object has no attribute 'get'

Также сбивает с толку то, что в функции get_reset_token получение _id работает, потому что эта функция работает отлично, когда я ее использую. Я также пробовал:

current_user._id 
current_user['_id'] 
current_user.email
current_user['email']

в котором я получаю, что NoneType не подлежит подписке или тип пользователя не подлежит подписке.

Я понимаю, что объект User - это не то же самое, что и пользователи в моей базе данных, но мне нужно получить некоторую информацию от current_user, чтобы иметь возможность подключить его к соответствующему пользователю в базе данных.


person L.AW    schedule 17.04.2019    source источник


Ответы (1)


Класс User здесь не имеет get() метода по умолчанию, а также не реализует метод __getitem__(), необходимый для поддержки user["email"] или аналогичных шаблонов доступа, что является основной причиной ваших ошибок.

Вызов get_reset_token() работает, потому что он вызывает self.user_json.get('_id')), где user_json - это завернутый словарь, который поддерживает доступ для получения и подписки.

Возможные решения:

1. Прокси get и __getitem__ в обернутый словарь

Это частичное решение, и есть несколько других магических методов, которые можно реализовать, чтобы заставить пользователя действовать как словарь, но это отправная точка.

class User(UserMixin):
  ...
  def get(self, key):
    return self.user_json.get(key)

  def __getitem__(self, key):
    return self.user_json[key]

  def __setitem__(self, key, value):
    return self.user_json[key] = value

  def __delitem__(self, key):
    del self.user_json[key]
  ...

2. Создайте свойства для определенных шаблонов доступа.

Свойства более питоничны, чем методы получения, такие как get_email().

class User(UserMixin):
  ...
  @property
  def email(self):
    return self.user_json["email"]

  @email.setter
  def email(self, value):
    self.user_json["email"] = value
  ...
person Steve McCartney    schedule 17.04.2019
comment
Я все еще получаю сообщение об ошибке "Пользователь". Объект не может быть указан в строке: self.user_json ['email'] - person L.AW; 17.04.2019
comment
Это предполагает, что объект, который вы передаете в конструктор User, является другим объектом User, а не данными пользователя. Из исходного примера кода self.user_json должен быть dict, а не объектом User. Не видя полного кода, трудно сказать, в чем проблема. - person Steve McCartney; 18.04.2019