从 Docs 请求澄清 Django 模型选择代码

Request Clarification of Django Model Choice Code from Docs

在官方文档中,https://docs.djangoproject.com/en/1.8/ref/models/fields/#choices我们给出了这个例子:

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    YEAR_IN_SCHOOL_CHOICES = (
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
    )
    year_in_school = models.CharField(max_length=2,
                                      choices=YEAR_IN_SCHOOL_CHOICES,
                                      default=FRESHMAN)

YEAR_IN_SCHOOL_CHOICES 的实际元组之前以及之外将变量设置为字符串的目的是什么? 这些字符串在哪里使用? 那么这些变量与元组中使用的变量相同吗? 如果是这样,为什么?这似乎是一个额外且不必要的步骤。

在这个例子之前的例子中,他们使用了不同的 YEAR_IN_SCHOOL_CHOICES,这无济于事。感谢您的澄清。

更新

由于我坐在这里与这段代码搏斗,感谢大家的快速回复。他们都增加了我的理解。我认为 @shang-wang 对我的问题的回答是迄今为止最简洁和最敏感的。 1+ 用于引用 get_FOO_display()。但在我的特定用例中,管理员可以选择告诉最终用户如何评估特定对象。因此,我希望评估的 'human-readable' 形式成为最终 html 模板中向网站最终用户显示的内容。鉴于这些答案,现在我想知道这是否是实现我目标的最佳方式?是否解决:

`

html display table

对象名称 |评价

FOO | foo.get_evaluation_display()

or maybe:

对于对象中的 FOO:
对象名称 |评价
FOO.name | foo.get_evaluation_display()
'

此特定模型的目的是向最终用户显示专家对 FOO 的评价。每个 FOO 都可以有很多这样的评估。虽然通常很冗长,但这些评估可以分类,因此可以选择字段。然后,用户可以根据需要单击以阅读完整的原始评估。所以 FOO 是在不同的模型上定义的,并通过外键链接到评估模型。那么 get_FOO_display() 真的会在这里工作吗,因为选择字段不在 FOO 是实例的模型上?

p.s,我意识到这现在已经变成了一个不同的问题,所以如果它需要移动或其他什么,我同意,但它确实直接来自原始问答。让我知道。谢谢。

变量YEAR_IN_SCHOOL_CHOICES作为字段year_in_school中所有可能的选择。 YEAR_IN_SCHOOL_CHOICES 中每对中的第一个值将存储在数据库中,而每对中的第二个值将显示在您的表单下拉列表中(如果您使用默认小部件)。像FRESHMAN = 'FR'这样的单独选择声明是为了确保它们被封装在class中。您可以为每个学生对象执行以下操作:

# assign the value to student's year_in_school
student.year_in_school = Student.FRESHMAN
student.save()

# this will print 'FR'
db_value = student.year_in_school
print db_value

# this will print 'Freshman'
pretty_display_value = student.get_year_in_school_display()
print pretty_display_value

get_FOO_display.

的 Django 文档

文档似乎在示例后面的段落中解释了推理

Though you can define a choices list outside of a model class and then refer to it, defining the choices and names for each choice inside the model class keeps all of that information with the class that uses it, and makes the choices easy to reference (e.g, Student.SOPHOMORE will work anywhere that the Student model has been imported).

他们似乎建议将选项设为 class 变量是个好主意,这样您就永远不必引用原始值(例如 'FR')。这也是为了确保您在导入此模型的任何地方都可以访问这些变量。

# within your models.Model class...
STUDENT_TYPE_CHOICES = (
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
)
year_in_school = models.CharField(max_length=2,
                                  choices=YEAR_IN_SCHOOL_CHOICES,
                                  default=FRESHMAN)




This means elsewhere in your code if you want to specify a choice field value, you’d have to enter the first slot of the tuple’s value, e.g.:

year_in_school = models.objects.filter(year_in_school_type='SOPHOMORE') 


**This is pretty terrible** since it’s hardcoded in our source, possibly over many files.

为了避免在下面使用 class: pip 安装 enum34 进口检验 从枚举导入枚举

class ChoiceEnum(Enum):

    @classmethod
    def choices(cls):
        # get all members of the class
        members = inspect.getmembers(cls, lambda m: not(inspect.isroutine(m)))
        # filter down to just properties
        props = [m for m in members if not(m[0][:2] == '__')]
        # format into django choice tuple
        choices = tuple([(str(p[1].value), p[0]) for p in props])
        return choices


**That’s the hard work over.**

Now  you create your choice field:

from common.utils import ChoiceEnum

class StudentTypes(ChoiceEnum):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'

# within your models.Model class...
year_in_school = models.CharField(max_length=1, choices=StudentTypes.choices())


Now if we need to access StudentTypes from elsewhere in our source code, we can simply:

# import StudentTypes
year_in_school =  models.objects.filter(year_in_school=StudentTypes.junior.value)