【问题标题】:Adding attributes into Django Model's Meta class将属性添加到 Django 模型的 Meta 类中
【发布时间】:2023-04-08 03:50:02
【问题描述】:

我正在编写一个 mixin,它可以让我的模型很容易地转换成一个深层的值 dict(有点像 .values(),但是遍历关系)。定义这些的最干净的地方似乎是在模型本身中,a la:

class Person(models.Model, DeepValues):
    name = models.CharField(blank=True, max_length=100)
    tribe = models.ForeignKey('Tribes')

    class Meta:
        schema = {
            'name' : str,
            'tribe' : {
                'name' : str
            }
        }

Person.objects.all().deep_values() => {
    'name' : 'Andrey Fedorov',
    'tribe' : {
        'name' : 'Mohicans'
    }
}

然而,Django 抱怨我在class Meta 中包含了这个:

TypeError: 'class Meta' got invalid attribute(s): schema

(整个堆栈跟踪here

现在,我想我可以在我的 mixin 中精心覆盖它,但是有没有更优雅的方式来存储这些信息?

【问题讨论】:

    标签: python django django-models metadata


    【解决方案1】:

    这适用于我在元数据中为 Django 模型设置额外字段。

    class Vendor(CustomModel):
    
        def __init__(self, *args, **kwargs):
            cls = self.__class__
            meta = getattr(cls, '_meta', None)
            setattr(meta, 'exclude_logging', ["otp", "is_otp_verified"])
            super().__init__(*args, **kwargs)
    

    exclude_logging 字段可以通过如下方式访问。

    class CustomModel(models.Model):
    
        objects = UpdateManager()
    
        class Meta:
            abstract = True
    
        def save(self, *args, **kwargs):
            print(self._meta.exclude_logging)
    

    我希望这能解决问题。

    【讨论】:

      【解决方案2】:

      不是一个直接的答案,但我不喜欢在需要它的每个模型中将它添加到选项中的想法,所以我做了:

      class MyModel(models.Model):
          
          class Meta:
              ordering = ["myfield"]
      
          class MyPrefixMeta:
              my_value = "Abc"
      

      您甚至可以将它放到一个抽象模型中,并在__init__ 函数中验证设置的类属性,或者执行诸如向模型添加_myprefix_meta 属性之类的操作。所以你有自己的元类。

      【讨论】:

        【解决方案3】:

        我不知道优雅,但一种务实的方式是:

        import django.db.models.options as options
        
        options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('schema',)
        

        显然,如果 Django 添加了它自己的“模式”属性,这将中断。但是,嘿,这是一个想法……您总是可以选择一个不太可能发生冲突的属性名称。

        【讨论】:

        • 为了后代,这行不通,但这样做了:options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('default_values',)
        • 哦...大概是因为我的解决方案将 DEFAULT_NAMES 转换为列表,而您的改进将其保留为元组。
        猜你喜欢
        • 2018-09-13
        • 2015-08-28
        • 1970-01-01
        • 2018-08-29
        • 1970-01-01
        • 2018-06-27
        • 2016-01-24
        • 2018-08-22
        • 1970-01-01
        相关资源
        最近更新 更多