【问题标题】:Set methods with decorators dynamically使用装饰器动态设置方法
【发布时间】:2021-01-07 16:57:38
【问题描述】:

我有这门课:

class SomeMixin:
    permissions = (SomePermission,)
    methods = ('GET',)

    @list_route(methods=methods, url_path='en', permission_classes=permissions)
    def en_list(self):
        return get_translated_objects(self, 'en')

    @list_route(methods=methods, url_path='ru', permission_classes=permissions)
    def ru_list(self):
        return get_translated_objects(self, 'ru')

    @detail_route(methods=methods, url_path='en', permission_classes=permissions)
    def en_detail(self):
        return get_translated_object(self.get_object(), 'en')

    @detail_route(methods=methods, url_path='ru', permission_classes=permissions)
    def ru_detail(self):
        return get_translated_object(self.get_object(), 'ru')

我以后可以有更多的语言,但这不是一个好的解决方案。
我想创建语言列表循环并使用 setattr(self, func_name, func) 向类添加方法,例如:

langs = ('en', 'ru')
for lang in langs:
    setattr(self, func.__name__, func)

但是我应该为每个方法添加装饰器,我该怎么做?

【问题讨论】:

  • 随着您添加更多语言,此代码会变得非常混乱。为什么不使用本地化标头或其他东西动态确定语言,并且只使用一组方法而不是每种语言的静态路由?类似get_translated_object(self.get_object(), self.request.META['HTTP_LANG'])
  • 您可能需要考虑覆盖 __getattr__

标签: python django-rest-framework python-decorators


【解决方案1】:

我相信您应该能够将此示例的内容修补到您的代码中。话虽如此,从 http 标头中检测语言并返回适当的响应似乎是一种更好的方法。 这种方法虽然实用,但并不是最干净的。

# This decorator is meant to simulate the decorator exposed by django
def route(url, language, method):
    def wrapper(func):
        def inner(*args, **kwargs):
            print('url => {0}'.format(url))
            print('language => {0}'.format(language))
            print('method => {0}'.format(method))
            func(*args, **kwargs)
        return inner
    return wrapper


# This class is analogous to your SomeMixin class
class foo(object):
    def __init__(self):
        method = 'GET'
        # fields holds the parameters that will change for each method like url
        # and language
        fields = (('en', '/en', 'en_list'), ('ru', '/ru', 'ru_list'))
        for lang, url, func_name in fields:
            setattr(self, func_name, route(url=url, language=lang, method=method)(self.func_creator(lang)))


    def func_creator(self, language):
        def inner():
            print('hello in {0}'.format(language))
        return inner


def main():
    foo_instance = foo()
    print('Calling foo.en_list()')
    foo_instance.en_list()

    print()

    print('Calling foo.ru_list()')
    foo_instance.ru_list()


if __name__ == '__main__':
    main()

【讨论】:

    猜你喜欢
    • 2015-01-03
    • 2017-06-19
    • 2020-01-11
    • 1970-01-01
    • 2014-01-14
    • 2011-07-25
    • 2012-03-15
    • 1970-01-01
    • 2011-03-04
    相关资源
    最近更新 更多