在Django模型的Meta类中添加属性

46 投票
3 回答
17826 浏览
提问于 2025-04-15 12:43

我正在写一个混合类,这样我的模型就可以轻松地转换成一个深层的字典(有点像 .values(),但可以遍历关系)。在模型内部定义这些内容似乎是最干净的做法,像这样:

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

(完整的错误信息可以在 这里 查看)

现在,我想我可以在我的混合类中详细地重写这个,但有没有更优雅的方法来存储这些信息呢?

3 个回答

3

这个方法对我来说可以在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)

希望这个能解决你的问题。

4

这不是直接的答案,但我不太喜欢在每个需要的模型里都添加选项,所以我做了以下的事情:

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

    class MyPrefixMeta:
        my_value = "Abc"

你甚至可以把这个放到一个抽象模型里,然后在 __init__ 函数中验证设置的类属性,或者可以像给模型添加一个 _myprefix_meta 属性那样做。这样你就有了自己的元类。

64

我不知道这算不算优雅,但有一种实用的方法是:

import django.db.models.options as options

options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('schema',)

显然,如果Django以后自己添加了一个叫'schema'的属性,这个方法就会失效。不过,想法总是好的……你可以选择一个不太可能冲突的属性名称。

撰写回答