Django:附加自定义字段选项以指定外部表示

时间:2016-06-08 15:34:07

标签: python django django-models

我想在Django模型的字段中添加一些自定义字段选项,因为我正在构建一个应用程序,它将与仅遵循一般方案的模型一起使用。我们的想法是应用程序仍然可以使用新定义的模型,并且所有配置都应该直接在models.py中进行。因此,我想传递一些选项作为关键字参数,例如定义该字段是否应显示在外部表示中。问题是只传递新的关键字参数会引发意外关键字参数的错误。到目前为止,我已经使用了类似的东西,我认为这有点难看:

class CustomCharField(models.CharField):

    def __init__(self, *args, **kwargs):
        self.custom_option = kwargs['custom_option']
        del kwargs['custom_option']
        super().__init__(*args, **kwargs)

会有更清洁的解决方案吗?

此外,我想知道这种方法是否正确,或者是否有一种不同的首选方法来编码Django中模型的外部表示,类似于Flask的marshmallow

1 个答案:

答案 0 :(得分:0)

无论这种方法是否正确,我的解决方案是将自定义关键字参数附加到所有Django Field类。自定义选项可以在dict中指定,变量名称为keys,默认为values

from django.db.models import fields

# Get a dictionay of all field classes.
plain_fields = dict([(name, cls) for name, cls 
                    in fields.__dict__.items() 
                    if type(cls) == type and 
                    issubclass(cls, fields.Field) and 
                    cls != fields.Field])

def options_factory(options):
    """
    Produces a class that allows defining keyword arguments as 
    a mixin on another class.

    Args:
        options (dict): Name of the keyword arguments mapped to their 
            default value.
    """
    class OptionsMixin():

        def __init__(self, *args, **kwargs):

            for name, default in options.items():
                self.__dict__[name] = kwargs.pop(name, default)
            super().__init__(*args, **kwargs)

    return OptionsMixin

# Specify custom options with default values.
customoptions = {'supercooloption': 47,
                 'superfluous_option': None}

CustomOptions = options_factory(customoptions)

# Iterate over the field classes and mix the CustomOptions in.
optionfields = {}
for name, cls in plain_fields.items():
    optionfields[name] = type(name, (CustomOptions, cls), {})

# Update the modules __dict__ so the classes can be imported.
globals().update(optionfields)

我在optionmodels.py中的models.py这样的单独文件中指定了此内容,然后可以像import myapp.optionmodels as omodels一样导入,这样可以使用自定义字段,与标准相比只需稍微改变语法Django字段。

请注意,ManyToManyField之类的关系字段具有不同的__init__签名,因此需要使用不同的mixin来调用super().__init__(to, *args, **kwargs)