検索ボックスを複数設置したい

612 views
Skip to first unread message

maru

unread,
Apr 26, 2009, 3:03:16 AM4/26/09
to django-ja
はじめまして、この度初めて投稿させていただきます。

Djangoを始めたばかりなのですが、
Home › Sites › Sitesの検索ボックスを複数にしたいと考えております。

検索ボックスを複数にする場合、
django\contrib\admin\templates\adminないのsearch_form.htmlファイルに
<input type="text" size="400" name="{{ search_var }}"
value="{{ cl.query }}" id="searchbar" />を
増やす方法で考えていますが、フレームワークのTemplateに手を入れる方法は良いのでしょうか?
良い方法があればご教示お願いします。

また、そもそも検索ボックスは増やせるのでしょうか?


説明等不足している部分があると思いますがよろしくお願いします。

tsuyuki makoto

unread,
Apr 27, 2009, 9:38:40 AM4/27/09
to djan...@googlegroups.com
はじめまして、露木です。

検索ボックスはなんのために増やすのでしょう?
単にUI上の理由でしょうか?

---
adminのテンプレートを修正する場合は、Djangoのコードベース
内で修正するのではなく、settings.TEMPLATE_DIRSにテンプレー
ト探索ディレクトリを追加して、admin/search_form.htmlをコピー
して修正します。
adminのテンプレートについては、下記のドキュメントを見ると
すこし解説があります。
http://djangoproject.jp/doc/ja/1.0/ref/contrib/admin.html

2009/04/26 16:03 maru <s.marukawa...@nifmail.jp>:

maru

unread,
Apr 30, 2009, 1:09:11 PM4/30/09
to django-ja
露木様、返信ありがとうございます。
また、返信が遅くなりまして、大変申し訳ありません。

現在、私はPython x Djangoで構築されたあるシステムの
追加機能開発のプロジェクトに参画しております。
その追加機能の要件にて、検索ボックスを増やしてほしいとの要望がありました。
以下のような検索ボックスを作りたいです。
例>
ID:(ID用の検索ボックス)
NAME:(NAME用の検索ボックス)
TEL:(TEL用の検索ボックス)

上記3つの検索ボックスを一つの画面に作成したいです。

その検索機能がついているモデルは動的に生成されたモデルです。
前任者の方が残されたソースには、以下のURLが記載されておりました。
http://bitbucket.org/MiCHiLU/my/src/tip/python/django/dynami_model/dynamic/models.py
http://code.djangoproject.com/wiki/DynamicModels

ソースを見る限りでは、データベースからデータを取得し、動的に検索画面のモデルを生成していると思っております。

一つのモデル内に複数のsearch_fieldsを定義することは可能なのでしょうか?

質問の内容、実装したいことなど分かりにくいとは思いますが、よろしくお願いいたします。

Takanao Endoh

unread,
Apr 30, 2009, 7:21:46 PM4/30/09
to djan...@googlegroups.com
遠藤です

2009/5/1 maru <s.marukawa...@nifmail.jp>:
> その検索機能がついているモデルは動的に生成されたモデルです。
> 前任者の方が残されたソースには、以下のURLが記載されておりました。
> http://bitbucket.org/MiCHiLU/my/src/tip/python/django/dynami_model/dy...

(URLは正しくは↓ですね)
http://bitbucket.org/MiCHiLU/my/src/tip/python/django/dynamic_model/dynamic/models.py

Django Adminに付属している検索ボックスを利用して、dynamic_modelで生成されたモデルに対応するデータベースに対して、カラム毎に検索条件を指定したい。ということでしょうか。

dynamic_modelに限ったことではないのですが、Django
Adminに付属している簡易検索機能をカスタマイズして拡張するのではなく、自前のviewを新たに作成して要件に添った本格的な検索機能を実装することをお勧めします。

Django Adminの見た目を活用したい、ということであれば、AJAXを使う方法もあります。
検索結果を返すRESTfulなAPIだけを自前のviewで作成し、Django
Adminに埋め込んだJavaScriptから呼び出して、検索結果をレンダリングする。という方法もとれます。

Django Admin - ModelAdmin のメディア定義
http://djangoproject.jp/doc/ja/1.0/ref/contrib/admin.html#modeladmin-media-definitions

ただ、Django Adminテンプレートに手を入れることは最小限に済ませられるのですが、IE6などでも動作を保証するとなると苦労するかもしれません。Django
Adminを利用するのは"スタッフだけ"の場合がほとんどでしょうから、使用するブラウザをFirefoxだけに限定するなども検討した方がいいでしょう。


Takanao Endoh
http://www.MiCHiLU.com

Yasushi Masuda

unread,
May 1, 2009, 1:56:43 AM5/1/09
to djan...@googlegroups.com
maru さん

将来のバージョンで期待通りに動作する保証はないのですが、
1.0 で近いことを実現するハックが、あることにはあります。

テンプレートの編集
=====================

バージョン 1.0 以前から、 Django には管理画面のテンプレートをカスタマイズ
する方法がありました。たとえば、 adressbook というアプリケーションの
Entry というモデルの管理画面のレコード一覧(「チェンジリスト」といいます)
の表示をいじりたければ、 "admin/addressbook/entry/change_list.html" という
テンプレートを、アプリケーションのテンプレートディレクトリ下
(addressbook/templates/admin/addressbook/entry/change_list.html) に
作成します。デフォルトの change_list.html の内容は、 django のインストール
ディレクトリの django/contrib/admin/templates/admin/change_list.html
です。継承を使えば、全部をコピーして書き換えなくても、ツールバーの
検索部分だけをオーバライドできます。

オーバライドするべきブロックは、search です。
元のテンプレートでは、以下のようになっているでしょう::

...
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
{% block search %}{% search_form cl %}{% endblock %} ←ここです。
{% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %}
...

search ブロックの中に入っている {% search_form cl %} は
django.contrib.admin.templatetags.admin_list で定義されているインクルージョン
タグです。この機能をちょっといじりたいので、 change_list.html テンプレートには
以下のように記述します::

{# -*- coding: utf-8 -*- #}
{% extends "admin/change_list.html" %}
{% load my_tags %}
{% block search %}{% my_search_form cl %}{% endblock %}

こうしておくと、search_form テンプレートタグが呼出される代りに、
(あとで説明する)自作の my_search_form テンプレートタグが呼び出されて、
複数のフィールドを出力するようカスタマイズしたテンプレートでレンダリング
されるようになります。 {% load my_tags %} では、自作のテンプレートタグ
ライブラリをロードしていますが、このライブラリは後で作ります。

さて、search_form タグは、
django/contrib/admin/templates/admin/search_form.html
というテンプレートを使ってレンダリングを行うので、このファイルを
addressbook/templates/admin/addressbook/entry/my_search_form.html
にコピーして、以下のように書き換えておきます::

********************** ここから ***************************
{# -*- coding: utf-8 -*- #}
{% load adminmedia %}
{% load i18n %}
{% if cl.search_fields %}
<div id="toolbar">
<form id="changelist-search" action="" method="get">
<div><!-- DIV needed for valid HTML -->
{# 元のテンプレートでは、ここに検索フィールドが入っている #}
<label for="searchbar">ID:</label>{# 変更箇所 #}
<input type="text" size="20" name="id"
value="{{ cl.params.id }}" id="searchbar" />{# ID #}{# 変更箇所 #}
<label for="searchbar">NAME:</label>{# 変更箇所 #}
<input type="text" size="20" name="name"
value="{{ cl.params.name }}" id="searchbar" />{# NAME #}{# 変更箇所 #}
<input type="submit" value="{% trans 'Go' %}" />{# 変更箇所 #}
<label for="searchbar">TEL:</label>{# 変更箇所 #}
<input type="text" size="20" name="tel"
value="{{ cl.params.tel }}" id="searchbar" />{# TEL #}{# 変更箇所 #}
<input type="submit" value="{% trans 'Go' %}" />
{% if show_result_count %}
<span class="small quiet">
{% blocktrans count cl.result_count as counter %}
1 result{% plural %}{{ counter }} results
{% endblocktrans %}
(<a href="?{% if cl.is_popup %}pop=1{% endif %}">
{% blocktrans with cl.full_result_count as full_result_count %}
{{ full_result_count }}
total{% endblocktrans %}</a>)
</span>
{% endif %}
{% for pair in cl.params.items %}
{% ifnotequal pair.0 "id" %}{# 変更箇所 #}
{% ifnotequal pair.0 "name" %}{# 変更箇所 #}
{% ifnotequal pair.0 "tel" %}{# 変更箇所 #}
<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>
{% endifnotequal %}{# 変更箇所 #}
{% endifnotequal %}{# 変更箇所 #}
{% endifnotequal %}{# 変更箇所 #}
{% endfor %}
</div>
</form>
</div>
<script type="text/javascript">
document.getElementById("searchbar").focus();
</script>
{% endif %}
********************** ここまで ***************************

ポイントは、検索フィールドを増やすときに、<input> の name 属性を
検索したいフィールド名にすることと、 対応する value 属性を、
{{ cl.params.(フィールド名) }} にすること、そして、後半の
{% for pair in cl.params.items %} の中で、 pair.0 と検索フィールド
名が一致するときに
<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>
が実行されないよう ifnotequal をかぶせておくことです。


テンプレートタグを定義する
============================

ここまできたら、今度は
次に、 {% my_search_form cl %} を実行するテンプレートタグを定義します。
テンプレートタグのライブラリを作るには、 addressbook/templatetags/
ディレクトリを作り、その下に __init__.py , my_tags.py という名前の
二つのファイルを作成します。 __init__.py の内容は空で、 my_tags.py
は以下のように記述します::

from django.template import Library
from django.contrib.admin.templatetags.admin_list import search_form

register = Library()

@register.inclusion_tag('admin/log/log/my_search_form.html')
def my_search_form(cl):
return search_form(cl)

これで、 search_form の機能はそのままに、テンプレートだけ
my_search_form.html を使うようなインクルージョンタグ my_sarch_form
が my_tags テンプレートライブラリに登録されます。


ModelAdmin をカスタマイズする
===============================

最後に、 ModelAdmin をカスタマイズします。 ModelAdmin は、
addressbook/admin.py で編集します::

from django.contrib import admin
from django.http import QueryDict
from models import Entry

class EntryAdmin(admin.ModelAdmin):
search_fields = ['id', 'name', 'tel']
def __call__(self, request, url):
get_dict = request.GET.copy()
for sf in self.search_fields:
if sf in get_dict and bool(get_dict.get(sf))==False:
get_dict.pop(sf)
request.GET = get_dict; request.GET._mutable = False
return super(EntryAdmin, self).__call__(request, url)

admin.site.register(Entry, EntryAdmin)

ModelAdmin は、管理画面の中で、ビューのように使われます。すなわち、
管理画面を表示するときに、 request, url を引数にして呼び出されます。
上のコードでは、 __call__ を拡張して、 search_fields と同じキーで、
値が空文字列のパラメタが request.GET に入っていたら、 pop して取り
出しています。これは、検索フィールドに値が入っていないときに、
検索条件が「name__exact=''」のようにになってしまうのを防ぐためです。

これで完成です。

補足
=======
同じようなことを実現するのに色々試していて、 name だけでなく、
name__contains のような表現もできるようだと分かりましたが、正しく
動作する保証はありません。もちろん、上の内容も、将来のバージョン
にわたって正しく動作する保証はありません。

---------------
Yasushi Masuda
http://ymasuda.jp/

maru さんは書きました:

maru

unread,
May 3, 2009, 9:38:00 AM5/3/09
to django-ja
遠藤様、返信ありがとうございます。返信が遅くなりまして申し訳ありません。すみません・・URL間違っていました。。。> Django Admin
に付属している検索ボックスを利用して、dynamic_modelで生成されたモデルに対応するデータベースに対して、カラム毎に検索条件を指定し-
たい。ということ>でしょうか。遠藤さんがおっしゃられているように、dynamic_modelで生成されたモデルに対応するデータベースに対して、
カラム毎に検索条件を指定したいです。しかし、dynamic_modelで生成されるモデルが複数あり、それぞれの画面で異なった検索条件にしたいの
です。例> dynamic_modelで生成されたモデルAの場合の検索条件:ID、NAME、TEL dynamic_modelで生成されたモデ
ルBの場合の検索条件:ADDRESS、POST上記のは例ですが、このような機能にしたいです。> Django Adminの見た目を活用したい、
ということであれば、AJAXを使う方法もあります。> 検索結果を返すRESTfulなAPIだけを自前のviewで作成し、Django>
Adminに埋め込んだJavaScriptから呼び出して、検索結果をレンダリングする。という方法もとれます。見た目等は特に指定はされていないの
で、機能が実現できれば大丈夫です。(見た目は統一されていたほうがよろしいとは思いますが。)しかし、それ以前に私のPythonとDjangoのス
キルが低く、またスケジュール的に余裕がないので今回は検索機能の追加修正は行わない方向になっています。スケジュールに余裕ができたときにアドバイス
いただきました方法を試してみます。アドバイスありがとうございます。

maru

unread,
May 3, 2009, 9:44:09 AM5/3/09
to django-ja
増田様、返信ありがとうございます。返信が遅くなりまして申し訳ございません。詳細なアドバイス、ソースサンプル本当にありがとうございます。しかし、
現プロジェクトでは今回の検索機能の修正追加は行わない方向で動いております(私のPythonとDjangoのスキルが低いので実現が難しく、スケ
ジュール的にも厳しいため)ので、アドバイスいただきましたことは勉強のために活用させていただきます。ご丁寧なアドバイス、ありがとうございました。
Reply all
Reply to author
Forward
0 new messages