Subscribe

Categories

Checkio.ORG

Subscribe to Posts

Email:

  • 17Jun

    Когда делая выборку из объекта родителя и хочется получать объекты наследники, то я использую такой финт

    1. from django.db import models
    2.  
    3. class MBase(models.Model):
    4.     field1 = models.CharField(max_length=10)
    5.     field2 = models.CharField(max_length=10)
    6.     classname = models.CharField(max_length=10)
    7.     def save(self,*args,**kwargs):
    8.         self.classname = self.__class__.__name__.lower()
    9.         super(MBase,self).save(*args,**kwargs)
    10.     @property
    11.     def rel_obj(self):
    12.         return getattr(self, self.classname)
    13.    
    14. class MFirst(MBase):
    15.     myf1 = models.CharField(max_length=10)
    16.    
    17. class MSecond(MBase):
    18.     myf2 = models.CharField(max_length=10)

    А в коде выходит примерно следующее

    1. In [11]: M.MBase.objects.get(id=3)
    2. Out[11]: <MBase: MBase object>
    3.  
    4. In [12]: M.MBase.objects.get(id=3).rel_obj
    5. Out[12]: <MFirst: MFirst object>
    6.  
    7. In [13]: M.MBase.objects.get(id=3).rel_obj.myf1
    8. Out[13]: u'Hi1'

    PS: Чтоб не мучаться, можно вынести функционал в абстрактную модель.

    1. class RelatedBase(models.Model):
    2.     childclassname = models.CharField(max_length=20,editable=False)
    3.     def save(self,*args,**kwargs):
    4.         if not self.childclassname:
    5.             self.childclassname = self.__class__.__name__.lower()
    6.         super(RelatedBase,self).save(*args,**kwargs)
    7.     @property
    8.     def rel_obj(self):
    9.         return getattr(self, self.childclassname)
    10.     class Meta:
    11.         abstract=True

    а все базовые классы уже будут от нее наследоваться

    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Posted by Oduvan @ 6:55 pm

    Tags: , ,

Facebook comments:

  • Ну. в местах, где раньше были просто выборки через filter(), и дальше просто работа с объектами, то нужно будет везде вставлять вызов rel_obj.

    Например, был у меня код, который пробегался по разделам сайта, и спрашивал у них, где какие виджеты рисуются. Никакой иерархии классов для них не предполагалось, все просто и тупо:

    for sect in Section.objects.filter(...):
    res = sect.what_to_draw()
    draw_results(res)

    Как-то так.

    Потом у меня появился новый тип разделов, для которых эта логика совершенно иная. Я наследую класс Section, создаю FullSection, при этом применяю предложенный тобой метод. Теперь мне придется переписать этот код так:

    for sect in Section.objects.filter(...):
    res = sect.rel_obj.what_to_draw()
    draw_results(res)

    И так везде, где я выбирал эти объекты и работал с ними.

    Конечно, проблема не такая уж и большая, и предложенное решение намного лучше, чем остаться совсем без полиморфизма, но вот после SqlAlchemy это все как-то грустно...
  • Хороший выход. Только вот все равно остается торчать костылик в виде "rel_obj" :( Т.е. когда класс наследник внедряется в систему позже -- нужно будет горы кода перелопатить.

    Просто беда в django с динамическим полиморфизмом. Самый глубоко доставший меня глюк...
blog comments powered by Disqus