问题 Django:为什么Django模型字段属性属性?


在Django中,模型的字段被定义为类属性。

那么这意味着模型的所有实例都会为这些字段共享相同的值,不是吗?

说我有一个模特

class Tag(models.Model):
    name = models.CharField(max_length=30)

我有一个表单,用户可以在其中提交标签。假设用户提交了2个标签:“Python”和“Django”。如果我在视图中创建了2个Tag实例:

t1 = Tag(name="Python")
t2 = Tag(name="Django")

以来 name 是一个类属性不应该两者 t1 和 t2 具有相同的价值 name 在这种情况下应该是“Django”?

但实际上 name 行为类似于实例属性而不是类属性。你能解释一下发生了什么吗?


4367
2018-05-10 00:18


起源



答案:


不,原因与此相同:

>>> class Foo(object):
...     bar = 'Foo attribute'
...
>>> f = Foo()
>>> f.bar
'Foo attribute'
>>> Foo.bar
'Foo attribute'
>>> f.bar = 'instance attribute'
>>> f.bar
'instance attribute'
>>> Foo.bar
'Foo attribute'

为对象分配属性时,对象的“类”属性将被对象“黯然失色”。但是,在属性查找中,如果相关对象未定义所述属性,则将返回第一类。

在Django中,ORM层使用这些类属性来生成转换为SQL查询和操作的机制(深层,元类魔法在幕后进行)。

编辑:回答你的问题 -

要理解这一点,您需要了解一些关于Python的内容 数据模型。本质上,类和对象都有名称空间。如果你偷看他们的特殊情况,这是显而易见的 __dict__属性:

>>> print Foo.__dict__
{'__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute
'__weakref__' of 'Foo' objects>, '__module__': '__main__', 'bar': 'Foo attribute
', '__doc__': None}
>>> f = Foo()
>>> print f.__dict__
{}

当对象 f 首先创建它,它有一个空命名空间。当你进行查找时 f.bar,查找这个命名空间(实际上是一个字典)。既然没有 'bar' 找到属性, f上课, Foo,抬起头来。我们发现 'bar': 'Foo attribute' 那里。这就是要返回的内容:

>>> f.bar
'Foo attribute'

现在,当您为对象分配属性值,并且其名称空间中尚未存在所述属性名称时,将创建它:

>>> f.bar = 'instance attribute'
>>> print f.__dict__
{'bar': 'instance attribute'}
>>> f.bar
'instance attribute'

现在,你知道下一次会发生什么 f.bar 抬起头来! f.__dict__['bar'] 存在,将在我们看到之前返回 Foo命名空间。

当然,如果您的目的是始终访问和操作类的属性而不是实例,则需要使用类的名称。

>>> Foo.bar
'Foo attribute'
>>> Foo.__dict__['bar']
'Foo attribute'

16
2018-05-10 00:22



好的,这有效。但根据Dive Into Python(diveintopython.org/object_oriented_framework/...)class属性由类和类的所有实例共享(参见例5.18)。那么为什么Foo和f都不同意你的情况?我很困惑。 - Continuation
在编辑中回答了它。 - Santa
我懂了。谢谢! - Continuation
Django也不会使用相当多的东西 __metaclass_ 两种型号和形式的伏都教? - vicvicvic
在Django引擎盖下,自由使用元类魔法很明显,据我所知。 - Santa


答案:


不,原因与此相同:

>>> class Foo(object):
...     bar = 'Foo attribute'
...
>>> f = Foo()
>>> f.bar
'Foo attribute'
>>> Foo.bar
'Foo attribute'
>>> f.bar = 'instance attribute'
>>> f.bar
'instance attribute'
>>> Foo.bar
'Foo attribute'

为对象分配属性时,对象的“类”属性将被对象“黯然失色”。但是,在属性查找中,如果相关对象未定义所述属性,则将返回第一类。

在Django中,ORM层使用这些类属性来生成转换为SQL查询和操作的机制(深层,元类魔法在幕后进行)。

编辑:回答你的问题 -

要理解这一点,您需要了解一些关于Python的内容 数据模型。本质上,类和对象都有名称空间。如果你偷看他们的特殊情况,这是显而易见的 __dict__属性:

>>> print Foo.__dict__
{'__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute
'__weakref__' of 'Foo' objects>, '__module__': '__main__', 'bar': 'Foo attribute
', '__doc__': None}
>>> f = Foo()
>>> print f.__dict__
{}

当对象 f 首先创建它,它有一个空命名空间。当你进行查找时 f.bar,查找这个命名空间(实际上是一个字典)。既然没有 'bar' 找到属性, f上课, Foo,抬起头来。我们发现 'bar': 'Foo attribute' 那里。这就是要返回的内容:

>>> f.bar
'Foo attribute'

现在,当您为对象分配属性值,并且其名称空间中尚未存在所述属性名称时,将创建它:

>>> f.bar = 'instance attribute'
>>> print f.__dict__
{'bar': 'instance attribute'}
>>> f.bar
'instance attribute'

现在,你知道下一次会发生什么 f.bar 抬起头来! f.__dict__['bar'] 存在,将在我们看到之前返回 Foo命名空间。

当然,如果您的目的是始终访问和操作类的属性而不是实例,则需要使用类的名称。

>>> Foo.bar
'Foo attribute'
>>> Foo.__dict__['bar']
'Foo attribute'

16
2018-05-10 00:22



好的,这有效。但根据Dive Into Python(diveintopython.org/object_oriented_framework/...)class属性由类和类的所有实例共享(参见例5.18)。那么为什么Foo和f都不同意你的情况?我很困惑。 - Continuation
在编辑中回答了它。 - Santa
我懂了。谢谢! - Continuation
Django也不会使用相当多的东西 __metaclass_ 两种型号和形式的伏都教? - vicvicvic
在Django引擎盖下,自由使用元类魔法很明显,据我所知。 - Santa