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 さんは書きました:
> 露木様、返信ありがとうございます。
> また、返信が遅くなりまして、大変申し訳ありません。
> 
> 現在、私は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を定義することは可能なのでしょうか?
> 
> 質問の内容、実装したいことなど分かりにくいとは思いますが、よろしくお願いいたします。
> 
> 
> > 
> 

--~--~---------~--~----~------------~-------~--~----~
-----------------                       http://djangoproject.jp/                
         -----------------
You received this message because you are subscribed to the Google Groups 
"django-ja" group.
To post to this group, send email to django-ja@googlegroups.com
To unsubscribe from this group, send email to 
django-ja-unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/django-ja
-~----------~----~----~----~------~----~------~--~---

メールによる返信