0

From django documents, I know if I define a model like this:

class Person(models.Model):
   SIZE = (
       ('S','Small')
       ('M','Medium')
   )
   size = models.CharField(max_length = 1, choices = SIZE)

Then I have a method for Person called get_size_display().

I wonder how django realizes this feature. How does it know I have a property of Person called size and use it in the method name? Is this a trick in python?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
atbug
  • 818
  • 6
  • 26

1 Answers1

0

Django uses python metaclasses to achieve this.

Much like a regular class is a template from which to create objects, a metaclass is is the template from which to create classes.

When you declare a regular class:

class A(object):
    pass

The default metaclass (type) is what is responsible for creating A. It does so by processing the things you have defined in A in order to create a the object that actually represents A.

In Django, the developers changed the metaclass of models.Model to their own custom metaclass. In doing so, they get to control the creation of any class that derives from models.Model, and can do the "magic" that you refer to.

Django uses similar magic to do lots of other things, too!


For example, I can do the following to replicate what you are seeing Django do:

class MetaClass(type):
    @staticmethod
    def _create_getter(attr):
        def _getter(self):
            return getattr(self, attr)
        return _getter

    def __init__(self, name, bases, attrs):
        super(MetaClass, self).__init__(name, bases, attrs)

        for attr in attrs:
            if not attr.startswith('_'):
                setattr(self, 'get_%s' % attr, MetaClass._create_getter(attr))

class Base(object):
    __metaclass__ = MetaClass

Now, any class that derives from Base will automatically acquire getter methods for each of it public attributes (those not starting with an _).

Here's is being used:

class A(Base):
    x = 2

a = A()
print a.get_x()
Jamie Cockburn
  • 7,379
  • 1
  • 24
  • 37
  • Good explaination! However, stackoverflow says I don't have enough reputation to vote for you. – atbug Jul 03 '14 at 12:36