Django 管理画面逆引きメモ


## リスト画面 (Change List View)

### 表示させる項目を指定
```python
ModelAdmin.list_display = ('hoge',)
```

Boolを返すModelのカスタムメソッドは直接指定可能。
ついでに `__unicode__` or `__str__` も指定できるよ。

```python
ModelAdmin.list_display = ('__str__', 'model_custom_method')
```

### 詳細画面へのリンクを貼る項目を指定
デフォルトでは一番左側に表示される奴にリンクが付く

```python
ModelAdmin.list_display = ('hoge', 'fuga')
ModelAdmin.list_display_links = ('fuga',)
```

### カスタムした値を表示
```python
ModelAdmin.list_display = ('custom_hoge',)

def custom_hoge(self, obj):
    return u'Hoge'
custom_hoge.short_description = u'表示名'
custom_hoge.allow_tags = True  # htmlタグ許可
```

ユーザー入力の場合は `format_html('hoge')` 関数をつかってエスケープしておくとよい。


### デフォルトのソート順
```python
ModelAdmin.ordering = ('created_at',)  # 作成時間でソート
```

### カスタムアクション (リストビュー上部のセレクト部分のやつ)
```python
ModelAdmin.actions = ['hoge']  # 定義した関数などをリストアップ
ModelAdmin.actions_on_top = True  # ページ上部に表示
ModelAdmin.actions_on_bottom = True  # ページ下部に表示
```

### カスタムフィールドのソート
Django のソートは全て DB のクエリレベルで行うので、実際にDBにカラムが存在しないフィールドはソートできない。
ただ、カスタムフィールドが、あるフィールドの代理になっているときは、そのフィールド名を指定するとソートできる。

```python
ModelAdmin.list_display = ('number_str',)

# number が数字(int)を返すとする
def number_str(self, obj):
    return str(obj.number)
number_str.admin_order_field = 'number'
```

### `list_display` でDBにカラムのないカスタムフィールドをソート可能にする方法
StackOverflow [Django admin: how to sort by one of the custom list_display fields that has no database field](http://stackoverflow.com/questions/2168475/django-admin-how-to-sort-by-one-of-the-custom-list-display-fields-that-has-no-d)



## 追加・変更画面

### 特定のフィールドを更新の対象にしたい
２つの指定方法がある

#### fields

1. fields は `ModelAdmin.readonly_fields` の値も指定できるが、編集はできない
1. `list_display` などと違い、Model の field か `ModelAdmin.form` しか指定できない

```python
ModelAdmin.fields = ('hoge', 'fuga')  # hoge, fuga フィールドのみ追加、更新時の編集対象
ModelAdmin.fields = (('hoge', 'fuga'), 'piyo')  # hoge, fuga が同じ行で表示される
```

#### exclude
```python
ModelAdmin.exclude = ('hoge',)  # hoge は編集対象とならない
```

### 外部キーの値も、同じ画面で追加/編集できるようにする

```python
# Inline モデルを定義
class SomeForeignKeyModelInline(admin.TabularInline):
    model = SomeForeignKeyModel

# Inline モデルを表示させたいモデルの管理画面に追加
class HogeAdmin(admin.ModelAdmin):
    list_display = ('hoge', 'fuga')
    inlines = [SomeForeignKeyModelInline]
```

### fieldsets オプションでリッチな画面

```python
ModelAdmin.fieldsets = (
    ( '名前', {'オプション名': ('オプション値',)} ),
    (None, {
        'fields': ('hoge', 'fuga')
    }),
)
```

### カスタムフォーム
デフォルトでは `ModelForm` がよしなに管理画面用のフォームを生成するが、自分でカスタムしたフォームも指定可能

```python
ModelAdmin.form = HogeForm
```

#### モデルに定義されていないカスタムのフォームフィールドを管理画面に表示させたい
stackOverflow: [django admin - add custom form fields that are not part of the model](http://stackoverflow.com/questions/17948018/django-admin-add-custom-form-fields-that-are-not-part-of-the-model)

#### 既存の自動生成されるフォームをカスタマイズしたい
`get_form` メソッドでフックする

```python
ModelAdmin.get_form(request, obj=None, **kwargs)
```


## 管理画面テンプレートの上書き

### 設定
管理画面の元テンプレートは `contrib/admin/template/admin` に格納されている。
上書きする場合は、 `TEMPLATE_DIR` で設定されているディレクトリに `admin/` を追加する。

上書きしたい管理対象を、上記ディレクトリ配下に、 `app_name/modelname/` で追加する。
アプリ名以下のテンプレートはアプリ配下の全てのモデルに適応される。
モデル名以下のテンプレートは、そのモデルの管理画面のみ適応される。
ディレクトリ名は全て小文字。

### テンプレート作成方針
基本的に必要な部分だけを上書きするほうが効率的。

例:
hoge アプリの fuga モデルの一覧画面を上書きしたいときは
`admin/hoge/fuga/change_list.html` を作成。

あとは以下のように変更したい `{% block %}` 上書きしていく。

```html
{% extend 'admin/change_list.html' %}
{% block 'content' %}
<!--
なにか追加したいフォームや変数など
-->
{{ block.super }}
{% endblock 'content' %}
```


## 独自機能追加
管理画面に独自機能を追加したい場合、必要になりそうな作業のメモ

### URL の追加
独自機能を提供するURLを追加する。
Django管理画面がデフォルトで生成するURLをカスタマイズする必要がある。

`get_urls` を使う.

```python
from django.conf.urls import url
from django.http import HttpResponse
class HogeAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(HogeAdmin, self).get_urls()
        my_urls = [
            url(r'^hoge/$', self.admin_site.admin_view(self.hoge), name='hoge'),
        ]
        return my_urls + urls

    def hoge(self, request):
        return HttpResponse('OK')
```

`self.admin_site.admin_view` は追加したいビューに、パーミッションのチェックと `never_cache` を付与するもの。
基本的には、これでラップしておくほうが良い。

`return my_url + urls` の順番に注意。 `my_urls` を先にしないと、管理画面標準の URL が優先されて
独自定義した URL のビューまで辿りつけない。


## 既存管理画面の動作を上書きする

各 View関数の動作をオーバーライドすればよい

```python
class HogeAdmin(admin.ModelAdmin):
    # 一覧画面の動作を上書きする例
    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context['hoge'] = 'hoge'
        return super(HogeAdmin, self).changelist_view(request, extra_context=extra_context)
```

## その他

### 同一の Model を複数の ModelAdmin で管理する
StackOverflow [Multiple ModelAdmins/views for same model in Django admin](http://stackoverflow.com/questions/2223375/multiple-modeladmins-views-for-same-model-in-django-admin)