Я пытаюсь использовать декораторов для управления способом, которым пользователи могут или не могут получить доступ к ресурсам в рамках веб-приложения (работающий на Google App Engine). Обратите внимание на то, что я не позволяю пользователям входить в систему с их учетными записями Google, таким образом устанавливание определенных прав доступа к определенным маршрутам в app.yaml не является опцией.
Я использовал следующие ресурсы:
- Руководство Bruce Eckel по декораторам
- ТАК: get-class-in-python-decorator2
- ТАК: python-decorators-and-inheritance
- ТАК: get-class-in-python-decorator
Однако я все еще немного смущен...
Вот мой код! В следующем примере current_user является @property методом, которые принадлежат классу RequestHandler. Это возвращает Пользователя (db.model) объект, хранивший в хранилище данных с уровнем IntProperty ().
class FoobarController(RequestHandler):
# Access decorator
def requiredLevel(required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
return f
return wrap
@requiredLevel(100)
def get(self, someparameters):
#do stuff here...
@requiredLevel(200)
def post(self):
#do something else here...
Однако мое приложение использует различные контроллеры для другого вида ресурсов. Для использования @requiredLevel декоратора во всех подклассах я должен переместить его в родительский класс (RequestHandler):
class RequestHandler(webapp.RequestHandler):
#Access decorator
def requiredLevel(required_level):
#See code above
Моя идея состоит в том, чтобы получить доступ к декоратору во всех подклассах контроллера с помощью следующего кода:
class FoobarController(RequestHandler):
@RequestHandler.requiredLevel(100)
def get(self):
#do stuff here...
Я думаю, что просто достиг предела своего знания о декораторах и наследовании классов :). Какие-либо мысли?
Покопавшись в StackOverflow и внимательно прочитав руководство Брюса Экеля по декораторам , я думаю, что нашел возможное решение.
Это включает реализацию декоратора как класса в родительском классе:
class RequestHandler(webapp.RequestHandler):
# Decorator class :
class requiredLevel(object):
def __init__(self, required_level):
self.required_level = required_level
def __call__(self, f):
def wrapped_f(*f_args):
if f_args[0].current_user.level >= self.required_level:
return f(*f_args)
else:
raise Exception('User has insufficient level to access this resource')
return wrapped_f
Это делает работу! Использование f_args [0] кажется мне немного грязным, я отредактирую этот ответ, если найду что-то более красивое.
Затем вы можете декорировать методы в подклассах следующим образом:
FooController(RequestHandler):
@RequestHandler.requiredLevel(100)
def get(self, id):
# Do something here
@RequestHandler.requiredLevel(250)
def post(self)
# Do some stuff here
BarController(RequestHandler):
@RequestHandler.requiredLevel(500)
def get(self, id):
# Do something here
Не стесняйтесь комментировать или предлагать улучшения.