来自常量的Django模型字段?

Avi*_*Avi 5 python architecture django python-3.x

如何在常量中定义 Django 模型字段并随处使用。例如,如果我有一个模型,如:-

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()
Run Code Online (Sandbox Code Playgroud)

我想要做的是为 Author 模型中的字段定义常量,并在模型中提供常量而不是字段名称,例如:-

KEY_FIRST_NAME = 'first_name'
KEY_LAST_NAME = 'last_name'
KEY_EMAIL = 'email'
Run Code Online (Sandbox Code Playgroud)

并且作者模型应该使用常量而不是确切的键,例如:-

class Author(models.Model):
        KEY_FIRST_NAME = models.CharField(max_length=30)
        KEY_LAST_NAME = models.CharField(max_length=40)
        KEY_EMAIL = models.EmailField()
Run Code Online (Sandbox Code Playgroud)

如何做这样的事情,直接分配给常量在这里不起作用。

我想将所有字段名称存储在常量中,并且在需要的任何地方我都想使用常量而不是字符串字段名称。

这样做的目的是如果在以后的版本中文件名称有任何更改,那么我只想在一个地方更改,并且应该反映所有地方。

如果这是不可能的,或者它会使代码过于复杂,正如@dirkgroten 的一种方法所建议的那样,那么最好的做法是将模型字段定义为常量并在其他地方使用它们(除了内部模型,就像我们所指的那样)管理门户或任何其他地方的那些字段)。

bru*_*ers 3

简短的回答:你不能在 Python 中做到这一点,期间(实际上我不认为你可以在任何语言中做到这一点,但有人肯定会证明我错了 xD)。

现在,如果我们回到您真正的“问题” - 如果模型的字段名称发生更改,则不必更改客户端代码 - 您首先需要判断您的意思是“python 属性名称”还是“底层数据库字段”姓名”。

对于第二种情况,数据库字段名称不必与 Python 属性名称匹配,Django 模型字段采用db_column参数来处理这种情况。

对于第一种情况,我不得不说这是一个非常通用的(并且无论如何都不是新的)API 设计问题,通常的答案是“一旦公共 API 中包含了名称,您就不应该更改它”。已被释放”。现在事情发生了,有时你必须这样做。这里最好的解决方案是使用计算属性,在弃用期间将旧名称重定向到新名称,并在所有客户端代码移植后将其删除。

以您的模型为例,将 'first_name' 更改为 'firstname':

class Author(models.Model):
    # assuming the database column name didn't change
    # so we can also show how to us `db_column` ;)

    firstname = models.CharField(
        max_length=30, 
        db_column='first_name'
        )

    @property
    def first_name(self): 
        # shoud issue a deprecation warning here
        return self.firstname

    @first_name.setter
    def first_name(self, value):
        # shoud issue a deprecation warning here
        self.firstname = value
Run Code Online (Sandbox Code Playgroud)

如果您有十几个字段需要重命名,您肯定会想要编写一个自定义描述符(=> 计算属性),而不是保持干燥:

class Renamed(object):
    def __init__(self, new_name):
        self.new_name = new_name

    def __get__(self, instance, cls):
        if instance is None:
            return self

        # should issue a deprecation warning here
        return getattr(instance, self.new_name)

    def __set__(self, instance, value):
        # should issue a deprecation warning here
        setattr(instance, self.new_name, value)


class Author(models.Model):
    firstname = models.CharField(
        max_length=30, 
        db_column='first_name'
        )
    first_name = Renamed("firstname")
Run Code Online (Sandbox Code Playgroud)