Django:为什么Django模型字段是类属性?
在Django中,一个模型的字段是作为类的属性来定义的。
这是不是意味着模型的所有实例都会共享这些字段的相同值呢?
假设我有一个模型
class Tag(models.Model):
name = models.CharField(max_length=30)
而且我有一个表单,用户可以在里面提交标签。比如说,一个用户提交了两个标签:“Python”和“Django”。如果我在我的视图中创建两个Tag的实例:
t1 = Tag(name="Python")
t2 = Tag(name="Django")
因为name
是一个类属性,所以t1
和t2
的name
值不应该都是“Django”吗?
但实际上,name
的表现更像是实例属性,而不是类属性。你能解释一下这是怎么回事吗?
1 个回答
21
不,这里有个原因:
>>> 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属性'
。所以这就是将要返回的内容:
>>> 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'