複数のmodelを結合する 1
異なったmodelを結合して結果を出力しなければならない場合があります。
SQLで可能ですが、Model APIを使って実行してみましょう。
サンプルmodel作成
結合させるBlogEntryとTweetクラスを作成します。
models.py
from django.db import models
class BlogEntry(models.Model):
title = models.CharField(max_length = 255)
content = models.TextField()
created = models.DateTimeField()
def __unicode__(self):
return self.title
class Tweet(models.Model):
tweet_text = models.CharField(max_length = 140)
created = models.DateTimeField()
def __unicode__(self):
return self.tweet_text
サンプルデータ作成
>>>from appname.models import BlogEntry, Tweet
>>>from datetime import datetime
>>>BlogEntry(title = 'Entry #1', content = 'Test', created = datetime.now()).save()
>>>Tweet(tweet_text = 'Test Tweet', created = datetime.now()).save()
>>>BlogEntry(title = 'Entry #2', content = 'Test', created = datetime.now()).save()
結合
まずは、単純にBlogEntry, Tweet modelを結合を試してみましょう。
>>>BlogEntry.objects.all() | Tweet.objects.all()
AssertionError: Cannot combine queries on two different base models.
となり結合できません。
結合できないことには、先に進めません。
そこで、Pythonモジュールのchainを使って結合します。
>>>from itertools import chain
>>>entry_list = chain(BlogEntry.objects.all(), Tweet.objects.all())
>>>for e in entry_list:
... print(e, e.created.strftime("%X"))
...
(<BlogEntry: Entry #1>, '17:48:34')
(<BlogEntry: Entry #2>, '17:50:18')
(<Tweet: Test Tweet...>, '17:49:54')
結合することできました。が、出来ると欲が出てきます。
ソートしたくなるものです。
created fieldを対象にソートしてみましょう。
>>>from itertools import chain
>>>entry_list = chain(BlogEntry.objects.all(), Tweet.objects.all())
>>>entry_list = sorted(entry_list, key = lambda x: x.created)
>>>for e in entry_list:
... print(e, e.created.strftime("%X"))
...
(<BlogEntry: Entry #1>, '17:48:34')
(<Tweet: Test Tweet...>, '17:49:54')
(<BlogEntry: Entry #2>, '17:50:18')
ついでに逆順にしてみましょう。
>>>from itertools import chain
>>>entry_list = chain(BlogEntry.objects.all(), Tweet.objects.all())
>>>entry_list = sorted(entry_list, key = lambda x: x.created, reverse = True)
>>>for e in entry_list:
... print(e, e.created.strftime("%X"))
...
(<BlogEntry: Entry #2>, '17:50:18')
(<Tweet: Test Tweet...>, '17:49:54')
(<BlogEntry: Entry #1>, '17:48:34')
このようにすれば、結合・ソートすることができます。
ただし、この方法はソート対象のfield名が同一のものであることが条件となります。