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