Djangoのジェネリックビューで検索結果を表示してみる
最近社内で使うアプリをDjangoで作ってみてるわけなんだけど、Djangoすごすぎ。
C#とかJavaで作ったら結構工数かかるよなー、っていう管理系画面がコマンド一発で作れる。
しかもWebアプリでありがちな画面のための仕組みが用意されてて、ページングまでしてくれる。
だからやってることといえば、これくらいしかない。
PythonのレベルをあげるためにDjangoでやってみてるのに、Pythonコードをほとんど書いていない・・・
そんな素敵なDjangoなんだけど、ちょっとした検索結果を表示したい時にジェネリックビューが使えない。
(もしかしたらあるのかもしれないけど、見つけられなかった。)
それを何とかしてみようと、いろいろやってたら動いたのでメモしておく。
メインのコードはこんな感じ。
list_detail.object_list の代わりにこれを指すようにして、patternsの第3引数にfiltersとqueryをセットした辞書オブジェクトを渡してやればいい。複数条件の場合はANDで結合する。
- filters
- {キー=検索キー(URLからキャプチャする値の名前)、値=検索条件}の辞書オブジェクト
- query
- クエリセットを取得する関数
def lookup(*args, **kwargs): filters = kwargs.pop('filters') query = kwargs.pop('query') qs = [] for key in filters: id = kwargs.pop(key, None) if not id: continue qs.append(Q(**{ filters[key] : id })) q = reduce(lambda x, y:x & y, qs) kwargs['queryset'] = query(q) return object_list(*args, **kwargs)
たとえばこんなモデルがあったとして、Book一覧を表示するだけなら list_detail.object_list で構わない。
# -*- encoding: utf-8 -*- from django.db import models class Author(models.Model): name = models.CharField(maxlength=200) class Book(models.Model): name = models.CharField(maxlength=200) authors = models.ManyToManyField(Author)
でもAuthorで絞り込みたい、ってのはよくあるはず。
で、こういう風にURLを書いてみても、
urlpatterns = patterns('', (r'^book/author/(?P<author_id>\d+)/$', 'django.views.generic.list_detail.object_list', {'queryset':Book.objects.filter(**{'authors__id' : 'author_id'})}), )
object_list() got an unexpected keyword argument 'author_id'
というエラーが発生して意図した結果は得られない。
コンテキストに余計なキーがあるとエラーが発生するようだ。
そこで上記のラッパーを指すようにすると、意図した結果を得られる。
urlpatterns = patterns('', (r'^book/$', 'django.views.generic.list_detail.object_list', {'queryset':Book.objects.all()}), (r'^book/author/(?P<author_id>\d+)/$', 'djangotest.book.urls.lookup', { 'filters' : { 'author_id' : 'authors__id' }, 'query' : lambda x: Book.objects.filter(x) }) )