2015-01-16 2 views
3

Я делаю Django как ORM для моего учебного проекта и потому, что нам не разрешено использовать существующие ORM (если вы хотите использовать его, вы должны его самим закодировать) и просто для обучения себя, я думал, что такой же ORM, как в Django, будет хорошо.Как сделать трюк метакласса, подобный Django

В ORM я не буду делать определения моделей в том же стиле, что и в Django. то есть.

class Person(models.Model): 
    first_name = models.CharField(max_length=30) 
    last_name = models.CharField(max_length=30) 

Django использует метаклассы и в моем проекте я использую тоже, но у меня есть проблема с тем, что метаклассы построить классов не экземпляры и поэтому все атрибуты являются атрибутами класса и распределяются между всеми экземплярами.

Это общий пример того, что я пробовал, но из-за того, что я сказал ранее, это не будет работать:

def getmethod(attrname): 
    def _getmethod(self): 
     return getattr(self, "__"+attrname).get() 
    return _getmethod 

def setmethod(attrname): 
    def _setmethod(self, value): 
     return getattr(self, "__"+attrname).set(value) 
    return _setmethod 

class Metaclass(type): 
    def __new__(cls, name, based, attrs): 
     ndict = {} 
     for attr in attrs: 
      if isinstance(attrs[attr], Field): 
       ndict['__'+attr] = attrs[attr] 
       ndict[attr] = property(getmethod(attr), setmethod(attr)) 
     return super(Metaclass, cls).__new__(cls, name, based, ndict) 


class Field: 
    def __init__(self): 
     self.value = 0; 

    def set(self, value): 
     self.value = value 

    def get(self): 
     return self.value 

class Mainclass: 
    __metaclass__ = Metaclass 

class Childclass(Mainclass): 
    attr1 = Field() 
    attr2 = Field() 


a = Childclass() 
print "a, should be 0:", a.attr1 
a.attr1 = "test" 
print "a, should be test:", a.attr1 

b = Childclass() 

print "b, should be 0:", b.attr1 

Я пытался для поиска от источника Djangos, но это слишком сложно для меня, чтобы понять и «Магия», кажется, где-то скрыта.

Вопрос прост, как Django делает это в очень упрощенном примере?

ответ

3

Ответ достаточно прост, если вы проверите правильный код. Метакласс, используемый Django, добавляет все поля к <model>._meta.fields (ну, любопытное), но атрибут поля удаляется из фактического класса. Единственным исключением является подкласс RelatedField, и в этом случае добавляется дескриптор объекта (аналогично свойству - по сути, свойство - это дескриптор объекта, только с собственной реализацией).

Затем в __init__ методы модели, код перебирает все поля, и либо устанавливает значение в условии *args или **kwargs, или задает значение по умолчанию на экземпляре.

В вашем примере, это означает, что класс Person никогда не будет иметь атрибуты с именем first_name и last_name, но оба поля хранятся в Person._meta.fields. Однако экземпляр Person всегда будет иметь атрибуты с именем first_name и last_name, даже если они не представлены в качестве аргументов.

 Смежные вопросы

  • Нет связанных вопросов^_^