複数の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名が同一のものであることが条件となります。

twitter 2010-01-15 03:08:28.234091

関連ページ

参照サイト

Recent Updates

URLConf Tip 01 - キャプチャの有無にかかわらず同一のviewで処理する
Markdownの入力補助"wmd"をAdmin siteで使う
ModelFormでfieldのwidgetを変更する
動的なformを作る 6 - Dynamic Inline Admin site編
Formsetsを使う3 - inlineformset_factory編
動的なformを作る 5 - django-dynamic-formset編
Formクラスからメディアを定義する
複数のmodelを結合する 2 - Proxy model編
複数のmodelを結合する 1
ModelFormでfieldの表示順番を変える
Admin siteのwidgetを個別に変更する
formfield_overridesを使ってAdmin siteのwidgetを変更する
Admin siteのlist_displayをカスタマイズする - リンク編
Admin siteのlist_displayをカスタマイズする - 基本編
Admin siteのTextareaの高さを自在に変更する - admin.py編