Reputation: 107
Sorry for nerd question, but I spent 2 days but cannot find any solution.
This is my route.py configuration
app = WSGIApplication(
routes=[
Route("/account", handler="app.account.Settings")
]
)
I created a Handler like that (which required login)
@HealthPortRequestHandler.login_required
class Settings(HealthPortRequestHandler):
def get(self):
self.render("account/settings.html")
And create login_required validation method
@cached_property
def check_user_logged_in(self):
if self.request.cookies.get("User"):
user_id = self.read_cookie("User")
if user_id:
from models.users import Users
return Users.get_by_id(int(user_id))
else:
return None
return None
@staticmethod
def login_required(handler):
def check_login(self, *args, **kwargs):
if self.check_user_logged_in:
return handler(self, *args, **kwargs)
else:
return self.redirect("/login")
return check_login
But error found when debugging at this line
if self.check_user_logged_in:
with error raise AttributeError(attr)
AttributeError: check_user_logged_in
How can i know exactly happened ? any ideas ?
Upvotes: 0
Views: 127
Reputation: 55724
You are applying the decorator login_required
to the class Settings
, so the decorator will be executed when a Settings
instance is created.
When you try to create an instance of Settings
, the check_login
function inside login_required
is called. The arguments it receives are the values that are passed to Setting
's __init__
method. check_login
then takes the first value that it has received as an argument and tries to access its check_user_logged_in
attribute. This value, whatever it is (probably a webapp2.Request object), doesn't have a check_user_logged_in
attribute so the exception is raised.
This can be demonstrated without using the webapp2 framework:
class HealthPortRequestHandler(object):
def __init__(self, *args, **kwargs):
pass
@property
def check_user_logged_in(self):
pass
@staticmethod
def login_required(handler):
def check_login(self, *args, **kwargs):
if self.check_user_logged_in:
return handler(self, *args, **kwargs)
else:
raise RuntimeError('Not expecting to execute this')
return check_login
@HealthPortRequestHandler.login_required
class Settings(HealthPortRequestHandler):
pass
>>> s = Settings('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "demo.py", line 14, in check_login
if self.check_user_logged_in:
AttributeError: 'str' object has no attribute 'check_user_logged_in'
>>> s = Settings(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "demo.py", line 14, in check_login
if self.check_user_logged_in:
AttributeError: 'int' object has no attribute 'check_user_logged_in'
>>> s = Settings('Hello', 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "deco.py", line 14, in check_login
if self.check_user_logged_in:
AttributeError: 'str' object has no attribute 'check_user_logged_in'
So that's why you get the AttributeError.
To fix it, I'd suggest decorating the request handler's dispatch method instead of the class definition. This way you can still make your checks before the request is handled, but with access to the fully initialised Settings
instance.
Upvotes: 1