Django uses a metaclass to create the model class. Just as a class's __init__()
method creates a new instance, the metaclass's __new__()
method creates the class itself. All variables, functions, properties, etc. defined in the class body are passed to the __new__()
function. Strictly speaking, just defining a variable in the class body does not create a static/class variable -- only when the __new__()
function receives the variable and sets it on the class, will it be a class/static variable.
Django overrides this behavior when it comes to fields and the special Meta
inner class, by providing a custom __new__()
method. The options in the inner Meta
class are converted to an Options
instance, and that instance is stored as Model._meta
rather than Model.Meta
. Similarly, any fields you define are stored in Model._meta.fields
rather than as class/static variables.
You will notice that in your example, the class Album
does not have a artist
attribute: Album.artist
will simply raise an AttributeError
. This is because the metaclass moves the field from the class to Album._meta.fields
. Instances of Album
do have an artists
attribute, but this is not the field. Instead, it's the database value related to the field. The __init__
method of a model uses self._meta.fields
to populate any attributes with either the value that is passed to __init__
, or with the default value, to assure that the instance variable exists.
Only class variables are passed to the __new__
method. If you were to define a field as an instance variable inside __init__
, the field would never be passed to Model._meta.fields
, and Django simply doesn't know about the field. You will be able to access Album.artist
, but this will be the actual field instance, not the related database value. Basically you would be missing the magic that makes a model into a model.