django-model-utilsをいろいろ試してみる その3 InheritanceManager


django-model-utilsのInheritanceManagerを試してみます。

InheritanceってことはModelの継承に関係ある機能ですね。

サンプルを書いてみます。

class Place(models.Model):
    name = models.CharField(max_length=100)
    location = models.CharField(max_length=100)
    objects = InheritanceManager()

    def __unicode__(self):
        return self.name


class Restaurant(Place):
    pass


class Bar(Place):
    pass


適当にRestaurantとBarを登録

>>> Restaurant.objects.create(name='sakura', location='london')
<Restaurant: sakura>
>>> Restaurant.objects.create(name='Narisawa', location='tokyo')
<Restaurant: Narisawa>
>>> Bar.objects.create(name='Mine Bar', location='london')
<Bar: Mine Bar>
>>> Bar.objects.create(name='Agave', location='tokyo')
<Bar: Agave>


Place.objects.filterで、RestaurantとBarがまとめて取れます。でも取得できるのはPlaceモデルのインスタンスです

>>> Place.objects.filter(location='london')
[<Place: sakura>, <Place: Mine Bar>]


select_subclassesを使うと、それぞれのモデルのインスタンスを取得できます。

>>> Place.objects.filter(location='london').select_subclasses()
[<Restaurant: sakura>, <Bar: Mine Bar>]

sqlを見るとこんな感じになります。

>> print Place.objects.filter(location='london').query
SELECT "apps_place"."id", "apps_place"."name", "apps_place"."location" FROM "apps_place" WHERE "apps_place"."location" = london 

>>> print Place.objects.filter(location='london').select_subclasses().query
SELECT "apps_place"."id", "apps_place"."name", "apps_place"."location", "apps_restaurant"."place_ptr_id", "apps_bar"."place_ptr_id" FROM "apps_place" LEFT OUTER JOIN "apps_restaurant" ON ("apps_place"."id" = "apps_restaurant"."place_ptr_id") LEFT OUTER JOIN "apps_bar" ON ("apps_place"."id" = "apps_bar"."place_ptr_id") WHERE "apps_place"."location" = london 

サブクラスの種類ごとにJOINをしてますね。


Restaurantのインスタンスは欲しいけど、BarはPlaceのインスタンスでいいなんてときはこう書けるようです。

>>> Place.objects.filter(location='london').select_subclasses('restaurant')
[<Restaurant: sakura>, <Place: Mine Bar>]

>>> print Place.objects.filter(location='london').select_subclasses('restaurant').query
SELECT "apps_place"."id", "apps_place"."name", "apps_place"."location", "apps_restaurant"."place_ptr_id" FROM "apps_place" LEFT OUTER JOIN "apps_restaurant" ON ("apps_place"."id" = "apps_restaurant"."place_ptr_id") WHERE "apps_place"."location" = london 

ちょっとjoinが減ります。


get_subclassを使うとidを指定して、サブクラスのインスタンスを取得できます。

>>> Place.objects.get_subclass(id=1)
<Restaurant: sakura>
>>> Place.objects.get_subclass(id=2)
<Restaurant: Narisawa>
>>> Place.objects.get_subclass(id=3)
<Bar: Mine Bar>
>>> Place.objects.get_subclass(id=4)
<Bar: Agave>

関連 : django-model-utilsをいろいろ試してみる その1 StatusModel - brainstorm
関連 : django-model-utilsをいろいろ試してみる その2 TimeFramedModel - brainstorm
参考 : carljm / django-model-utils / source / ― Bitbucket