【问题标题】:How do Django model fields work?Django 模型字段如何工作?
【发布时间】:2009-02-01 11:43:27
【问题描述】:

首先,我不喜欢网络编程。我遇到了 django 并阅读了一些关于模型的信息。我对以下代码(来自 djangoproject.com)很感兴趣:


class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        # Note use of django.utils.encoding.smart_str() here because
        # first_name and last_name will be unicode strings.
        return smart_str('%s %s' % (self.first_name, self.last_name))

根据我对 python 的理解,first_name 和 last_name 是类变量,对吧?这在代码中是如何使用的(因为我猜想设置 Person.first_name 或 Person.last_name 会影响所有 Person 实例)?为什么要这样使用?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    你的问题的本质是“这些类变量(我分配 Field 对象)为什么突然变成了 Django 的 ORM 中的实例变量(我分配数据)?答案就是 Python metaclasses 的魔力。

    元类允许您挂钩和修改创建 Python 类的过程(不是创建该类的实例,而是创建类本身)。

    Django 的模型对象(以及您的模型,它们是子类)有一个ModelBase metaclass。它查看模型的所有类属性,以及任何作为 Field 子类实例的实例,它会移动到字段列表中。该列表被分配为_meta 对象的属性,这是模型的类属性。因此,您始终可以通过MyModel._meta.fieldsMyModel._meta.get_field('field_name') 访问实际的 Field 对象。

    然后Model.__init__ 方法可以使用_meta.fields 列表来确定在创建模型实例时应该初始化哪些实例属性。

    不要害怕深入研究 Django 源代码;这是一个很好的教育来源!

    【讨论】:

    • +1:这是很酷的巫术。这不是你应该深刻理解的东西。但是您确实需要看到它改变了明显的实例变量规则,为对象的创建方式添加了另一层。
    • 酷。我只是想知道:_meta 属性是官方模型 API 的一部分吗?
    • @pcv 不,从技术上讲它不是(它没有记录)。但实际上,它的一部分(当然是上面提到的部分)被广泛使用,以至于它们不太可能改变。我相信清理其中一些 API 并记录它们是在路线图上。
    • 从 Django 1.8 开始,_meta 属性现已记录在案并正式支持 API。
    【解决方案2】:

    是的,first_name 和 last_name 是类变量。它们定义将在数据库表中创建的字段。有一个包含 first_name 和 last_name 列的 Person 表,因此此时它们处于 Class 级别是有意义的。

    有关模型的更多信息,请参阅: http://docs.djangoproject.com/en/dev/topics/db/models/

    在代码中访问 Person 的实例时,通常是通过 Django 的 ORM 来完成的,此时它们基本上表现为实例变量。

    有关模型实例的更多信息,请参阅: http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs

    【讨论】:

    • 这里有一些很好的链接,但是“此时它们基本上表现为实例变量”有点挥手,并不准确(或者至少没有解释任何东西)。
    • 很公平...我会举手去接那个。 +1 你的答案。 :)
    【解决方案3】:

    不是真正的答案,而是为了丰富:

    Person.first_name 
    

    不会工作

    p = Person.objects.get(pk=x)
    p.first_name
    

    会起作用。所以 person 的对象实例有名字和姓氏,但静态上下文 Person 没有。

    另请注意:Django 有模型管理器,允许“人”执行静态查询集操作。 (https://docs.djangoproject.com/en/dev/topics/db/managers/#managers)。

    例如

    peoples = Person.objects.all()
    

    【讨论】:

      猜你喜欢
      • 2021-12-18
      • 2020-08-06
      • 2012-08-13
      • 2012-05-13
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 2016-11-04
      • 2018-01-30
      相关资源
      最近更新 更多