试图找出如何为Django管理命令编写一些mixins来封装
BaseCommand.option_list
而不会丢失当前类或任何继承的类/ mixins的值。目标是避免在我的命令中执行BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + ( local command options )
。
示例:
class BaseCommmand(object):
option_list = (
# Default options here.
)
# Rest of BaseCommand code.
我使用一些常见选项定义了一个mixin:
class MyCommonOptionMixin(object):
option_list = (
# Some common option/options I wish to have available in many commands
)
def __getattribute__(self, name):
values = super(MyCommonOptionMixin, self).__getattribute__(name)
if name == 'option_list':
for option in self.option_list:
if option not in values:
values += option,
return values
也许我还有一个,只是为了涵盖我有多个的情况。 mixin都覆盖__getattribute__
class MyOtherCommonOptionMixin(object):
option_list = (
# Maybe I have another mixin I want to define separately
)
# Tried this, does not work with more than one mixin.
def __getattribute__(self, name):
values = super(MyOtherCommonOptionMixin, self).__getattribute__(name)
if name == 'option_list':
for option in self.option_list:
if option not in values:
values += option,
return values
# Works if the mixin defines the option_list under a different name, e.g. "_mymixin_options"
# Then access at self._mymixin_options instead of self.option_list
class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand):
option_list = BaseCommand.option_list + (
# Local defined options.
)
如果mixins对option_list属性使用相同的名称,我就会遇到冲突。是否有更简洁的方法来实现这一目标,而不是在mixins中唯一地命名option_list并覆盖__getattribute__
?
答案 0 :(得分:5)
documentation中的建议是明确连接各种选项列表。也就是说,如果你想走这条路线,我认为自定义元类是正确的方法。类似的东西:
class CommandMetaclass(type):
def __new__(mcl, name, bases, dct):
# start with the option_list in the class we're creating
# use set() to avoid duplicates
option_list = set(dct.get('option_list', tuple()))
# add the options from each base class
for base in bases:
option_list.update(base.__dict__.get('option_list', tuple()))
# replace the original option_list with our combined version
dct['option_list'] = tuple(option_list)
return type.__new__(mcl, name, bases, dct)
class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand):
__metaclass__ = CommandMetaclass
option_list = (
# Local defined options.
)