Django: почему атрибуты класса полей Django?

В Django поля модели определяются как атрибуты класса.

Таким образом, это означает, что все экземпляры модели будут иметь одинаковые значения для этих полей, не?

Скажем, у меня есть модель

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

И у меня есть форма, в которой пользователи могут отправлять теги. Скажем, пользователь представил 2 тега: "Python" и "Django". Если я создам 2 экземпляра тега в моем представлении:

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

Так как name является атрибутом класса, то оба t1 и t2 имеют одинаковое значение для name, которое в этом случае должно быть "Django"?

Но на самом деле name ведет себя как атрибут экземпляра вместо атрибута класса. Можете ли вы объяснить, что происходит?

Ответ 1

Нет, по той же причине, что и:

>>> 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'

Когда вы назначаете атрибут объекту, атрибут класса с тем же именем будет "затмеваться" объектом. Однако при поиске атрибутов, если объект, о котором идет речь, не определяет указанный атрибут, вместо него будет возвращен класс 1.

В Django эти атрибуты класса используются слоем ORM для генерации механизма, который преобразуется в SQL-запросы и операции (глубокая, метаклассическая магия происходит за кадром).

edit: Чтобы ответить на ваш вопрос -

Чтобы понять это, вам нужно немного разобраться в модели данных 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 class, 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'