Trying to figure out how to write some mixins for Django management command that will wrap the
BaseCommand.option_list
without losing the value of the current class or any inherited classes/mixins. The goal is to avoid doing BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + ( local command options )
in my commands.
Example:
class BaseCommmand(object):
option_list = (
# Default options here.
)
# Rest of BaseCommand code.
I define a mixin with some common options:
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
Maybe I have one more, just to cover that case where I have multiple. The mixins both override __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.
)
I've run into collision if the mixins use the same name for the option_list property. Is there a cleaner way to achieve this goal than naming the option_list uniquely inside the mixins and overriding __getattribute__
?
The advice in the documentation is to explicitly concatenate the various option lists. That said, if you want to go this route I think a custom metaclass is the right approach. Something like:
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.
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With