Django: почему атрибуты класса полей модели Django? - PullRequest
13 голосов
/ 10 мая 2011

В 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 ведет себя как атрибут экземпляра, а не атрибут класса.Можете ли вы объяснить, что происходит?

1 Ответ

18 голосов
/ 10 мая 2011

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

>>> 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-запросам и операциям (глубокая магия метаклассов происходит за кулисами).

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