Форум сайта python.su
Здравствуйте!
Пока не очень разобрался с метаклассами и прочими премудростями Python и вот возник такой вопрос.
Хочется реализовать что то вроде Manager в Django ORM. Т.е. есть несколько классов, унаследованных от базового. У них есть экземпляры в некотором количестве. Хочется сделать что-то вроде этого:
class Foo(BaseClass): #Определение класса pass #Где-то в другом модуле.. from myapp.models import Foo x = Foo.objects.get_all() # Возвращается итератор for item in x: #Перебираем объекты pass
Офлайн
class classproperty(object): def __init__(self, fget): self.fget = fget def __get__(self, owner, cls): if owner is not None: raise AttributeError("objects is class only") return self.fget(cls) class Field(object): def __init__(self, **kwargs): self.null = kwargs.get("null", False) def _set_value(self, value): if value is None: if not self.null: raise ValueError("Field %s IS_NULL=FALSE" % self.__class__.__name__) self.value = None return try: self.value = self.validate(value) except: raise ValueError("Invalid value") return self def validate(self, value): pass class ModelMeta(type): def __new__(cls, name, bases, dct): fields = dict() for attr_name, value in dct.iteritems(): if isinstance(value, Field): fields[attr_name] = value dct['_fields'] = fields return type.__new__(cls, name, bases, dct) db = dict(mymodel=[ dict(id=1, a=100, b=3), dict(id=2, a=100, b=None), dict(id=3, a=3, b=None) ]) class Manager(object): def __init__(self, model_class, **kwargs): self.model_class = model_class self.where = kwargs.get("where") or dict() self.db_model_name = model_class.__name__.lower() def get(self, **kwargs): data = iter(db[self.db_model_name]) for field_name, value in kwargs.iteritems(): data = (x for x in data if x[field_name] == value) return self.model_class(**list(data)[0]) def filter(self, **kwargs): if not kwargs: raise AttributeError("Empty args") self.where.update(kwargs) return self def all(self): return Manager(self.model_class, where=self.where) def __str__(self): return str(self.execute()) def __iter__(self): return self.execute() def execute(self): data = db[self.db_model_name] for field_name, value in self.where.iteritems(): data = (x for x in data if x[field_name] == value) return (self.model_class(**item) for item in data) class Model(object): __metaclass__ = ModelMeta def __init__(self, **kwargs): setattr(self, "id", kwargs.get("id")) for field_name, field_class in self._fields.iteritems(): value = kwargs.get(field_name) setattr(self, field_name, self._fields[field_name]._set_value(value)) @classproperty def objects(cls): return Manager(cls) class IntegerField(Field): def validate(self, value): return int(value) def __str__(self): return str(self.value) class MyModel(Model): a = IntegerField() b = IntegerField(null=True) print MyModel.objects.get(a=3) for x in MyModel.objects.all(): print x.a, x.id print MyModel(a=1)
Отредактировано FishHook (Апрель 7, 2014 08:33:33)
Офлайн
Спасибо, высплюсь - буду разбираться..
Код предельно понятен, прям спасибище вам, просто слов нет.
У меня только появился глупый вопрос.. Когда я пытался осмыслить код django, то столкнулся с проблемой: я просто не смог найти определение метода objects ни для одного из базовых классов модели. Поиск по “def objects”, как и подробный просмотр кода ничего не дал. У меня так и не хватило терпения “распутать клубок” и найти определение метода. Если использован какой-то хитрый способ реализации, то хотелось бы понять - зачем?
Понимаю, что это лишь детали реализации, в таком большом проекте как Django есть куча нюансов и т.д. Просто я часто слышу, что Django - чуть ли не образец pythonic кода, но, честно говоря, там черт ногу сломит, я несколько часов подряд вчитывался в код, толку ноль. А на разбор вашего примера у меня ушло меньше минуты. Конечно, синтетический пример и реальный проект - совсем разные вещи, но все же..
Отредактировано maxfox (Апрель 8, 2014 21:49:55)
Офлайн
maxfox
У меня только появился глупый вопрос.. Когда я пытался осмыслить код django, то столкнулся с проблемой: я просто не смог найти определение метода objects ни для одного из базовых классов модели. Поиск по “def objects”, как и подробный просмотр кода ничего не дал. У меня так и не хватило терпения “распутать клубок” и найти определение метода. Если использован какой-то хитрый способ реализации, то хотелось бы понять - зачем?
Отредактировано PanovSergey (Апрель 9, 2014 00:26:51)
Офлайн
maxfoxЭто вряд ли. Джанго - довольно старый проект, с каждым релизом фреймворк наворачивают новым функционалом, но не переписывают заново сомнительные решения для сохранения обратной совместимости. То есть объективно Джанга - набор костылей.
чуть ли не образец pythonic кода
Офлайн
2PanovSergey
Спасибо!
2FishHook
Ок. Значит оо мной все в порядке. У меня тоже сложилось впечатление, что костылей в коде несколько больше чем нужно..
Еще раз спасибо за помощь!
Офлайн