6

I have been reading and working with Django for a bit now. One of the things that I am still confused with is why the model classes that we create in Django are made up of static variables and not member variables. For instance

class Album(models.Model):
    artist = models.CharField(max_length=128, unique=True)
    title = models.CharField(max_length=128, unique=True)
    genre = models.CharField(max_length=128, unique=True)

    def __unicode__(self):
        return self.name 

I read this page here which explains static and instance variables in python however i am still confused as to why Django wants the field variables in models be static ?

Community
  • 1
  • 1
James Franco
  • 4,516
  • 10
  • 38
  • 80

1 Answers1

10

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.

knbk
  • 52,111
  • 9
  • 124
  • 122