Django のModel
の設計に関して質問があるのですが、管理画面において"editor"のid
が自動的に入るような設定はできないでしょうか?
class Hoge(models.Model):
title = models.CharField(maxlength=200)
editor = models.ForeignKey(User)
edit_date = models.DateTimeField(auto_now=True)
class Admin:
pass
のようなモデルがあった場合に、管理画面でユーザを選択しなくても、ログインしているユーザのidが自動的に入るようにしたいのです。
Model のdefault で対応できないか、session
の値を取れないか、save()
をオーバーライドして対応できないか、など調べてみたのですが分からない状況です。
モデル定義が、ログインの有無と独立であることを考えると、ログインユーザのログインIDを取れないのは自然ですが、何か良い方法はないかと模索しています。
お知恵を貸していただけると幸いです。
よろしくお願いいたします。
まず, myapp/models.py に Hoge が定義されていたとして,
myapp/templates/admin/myapp/hoge/change_form.htmlを作成します.
change_form.html は admin/change_form.html を継承します.admin/change_form には
form_top というブロックがある(これはたぶん django の内部利用ではなく,アプリケーション
開発時用のカスタマイズポイントだと思います)ので,このブロックにデフォルト値のタグを
貼り込みます.
{% extends "admin/change_form.html" %}
{% block form_top %}
<input type="hidden" id="userid_embedded" name="editor" value="{{ user.id }}">
{% endblock %}
自動生成される方の Editor フィールドが目障りなら, class Admin の fields オプションで
抑制できます.
また,Editor フィールドのデフォルト値として自動的に値を入れたいのなら,
userid_embedded から id_editor (Editor フィールドのフォームコントロール) に値を設定
するような JavaScript を作成して, class Admin の js オプションで取り込めばよいと
思います.
--
Yasushi Masuda
http://ymasuda.jp/
06/10/31 に jun<ledmo...@gmail.com> さんは書きました:
>
> モデル定義が、ログインの有無と独立であることを考えると、ログインユーザのログインIDを取れないのは自然ですが、何か良い方法はないかと模索しています。
django.contrib.auth.models.User.id で現在のログインユーザの id
は取れると思います
ログインしているユーザの id と、class Hoge(models.Model) の id
との関係が分からないので、管理画面でユーザの id 云々という意味
がよく分かりません
ログインユーザの id と Hoge の id が等しいと考えて良いなら、
フォームを呼び出す URL に django.contrib.auth.models.User.id の
値を組み込んでやれば良いような気もします (←動作未確認)
--
Nakane Ryuji living at Nagoya
// mailto:ryu...@gmail.com
// business http://www.compnet.jp/
// private http://www.bernese.jp/lux/
訂正
s/django.contrib.auth.models.User/request.user"/
以下訂正後の全文を再掲
> 06/10/31 に jun<ledmo...@gmail.com> さんは書きました:
> >
> > モデル定義が、ログインの有無と独立であることを考えると、ログインユーザのログインIDを取れないのは自然ですが、何か良い方法はないかと模索しています。
>
> request.user.id で現在のログインユーザの id は取れると思います
>
> ログインしているユーザの id と、class Hoge(models.Model) の id
> との関係が分からないので、管理画面でユーザの id 云々という意味
> がよく分かりません
> ログインユーザの id と Hoge の id が等しいと考えて良いなら、
> フォームを呼び出す URL に request.user.id の値を組み込んでや
> {% extends "admin/change_form.html" %}
> {% block form_top %}
> <input type="hidden" name="editor" value="{{ user.id }}" id="embedded_editor">
> {{ request.POST }}
> {% endblock %}
{% block form_top %} を使うと,その後にある自動生成の
Editor フィールドの値が未設定なために POST データが更新され,バリデーション
エラーになってしまいます.
というわけで,フォームの先頭でなく,末尾の方にあるブロックを探してみたところ,
after_related_objects というブロックがありました.
{% extends "admin/change_form.html" %}
{% block after_related_objects %}
<input type="hidden" name="editor" value="{{ user.id }}" id="embedded_editor">
{% endblock %}
手元ではこれでうまくいきました...が,これでは自動生成のフィールドに何を
設定しても無視されるのでユーザに優しくありません.
class Admin:
fields = (
(None, {
'fields': ('title',), }),)
のようにしてフィールドを非表示にする方がよいようです.
ちなみに, JavaScript を使うやり方を試していたら,もっと奇麗にできました.
{% extends "admin/change_form.html" %}
{% block after_related_objects %}
<script type="text/javascript">
document.getElementById("id_editor").selectedIndex={{ user.id }};
</script>
{% endblock %}
です.いかがでしょう.
Yasushi Masuda wrote:
> admin のテンプレートには必ずユーザオブジェクトが渡りますから,テンプレートを
> カスタマイズして,ユーザ id の入った隠しタグを挿入するというのはどうでしょう.
>
> まず, myapp/models.py に Hoge が定義されていたとして,
> myapp/templates/admin/myapp/hoge/change_form.htmlを作成します.
>
> change_form.html は admin/change_form.html を継承します.admin/change_form には
> form_top というブロックがある(これはたぶん django の内部利用ではなく,アプリケーション
> 開発時用のカスタマイズポイントだと思います)ので,このブロックにデフォルト値のタグを
> 貼り込みます.
>
> {% extends "admin/change_form.html" %}
> {% block form_top %}
> <input type="hidden" id="userid_embedded" name="editor" value="{{ user.id }}">
> {% endblock %}
>
> 自動生成される方の Editor フィールドが目障りなら, class Admin の fields オプションで
> 抑制できます.
>
> また,Editor フィールドのデフォルト値として自動的に値を入れたいのなら,
> userid_embedded から id_editor (Editor フィールドのフォームコントロール) に値を設定
> するような JavaScript を作成して, class Admin の js オプションで取り込めばよいと
> 思います.
>
Yasushi Masuda wrote:
> ちなみに, JavaScript を使うやり方を試していたら,もっと奇麗にできました.
>
> {% extends "admin/change_form.html" %}
> {% block after_related_objects %}
> <script type="text/javascript">
> document.getElementById("id_editor").selectedIndex={{ user.id }};
> </script>
> {% endblock %}
>
> です.いかがでしょう.
SELECT の option の並び順とユーザ id は一致していませんから,これでは正しい
ユーザをピックアップできません.スクリプトを手直ししてみました.
{% extends "admin/change_form.html" %}
{% block after_related_objects %}
<script type="text/javascript">
var i;
var sel = document.getElementById("id_editor");
for (i=0; i<sel.options.length; i++){
if (sel.options[i].value=="{{ user.id }}"){
sel.selectedIndex = i;
}
}
</script>
{% endblock %}
ここまで書いて気づいたんですが,これだと,システムに登録されているユーザの
リストを間接的に取得できてしまいます.うーん.
早速のお返事ありがとうございます。林です。
Model
内で解決することを考えていたので、テンプレートのオーバーライドは目から鱗でした。しかし考えてみれば、当然のやり方ですね。
hidden タグを埋め込む方法、javascript
を用いる方法、両方試してみます。
# Masuda様の回答を読んでいて、「Admin
オプションのjs」が使えそうだと思いましたが、
#
よくよく考えてみると、js内ではテンプレートを記述できないので、
# Admin オプションのjs は静的なもの限定ですね。
> ここまで書いて気づいたんですが,これだと,システムに登録されているユーザの
> リストを間接的に取得できてしまいます.うーん.
こちらの方、よく分かりませんでした。
「User
テーブルを外部キーとして用いた場合に管理画面のリストボックスでユーザ一覧が表示されてしまう」という問題でしょうか。
不特定多数を対象としたようなシステムの場合には、hidden
タグ方式がよさそうですね。
お返事ありがとうございます。林です。
質問の方が説明不足だったのですが、
・ Django で自動生成する管理画面を使いたい
・ editor
というフィールドがあり、データを編集したユーザのuser.id
を自動挿入したい
→ Model
定義をうまく書けば自動挿入される?と模索したが、うまくいかない!
という思考回路でした。
管理者ページのテンプレートを上書きする発想がなかったのですね・・・
ありがとうございます、勉強になりました。
> よくよく考えてみると、js内ではテンプレートを記述できないので、
> # Admin オプションのjs は静的なもの限定ですね。
js でもいけると思いますよ.ただし,
- JavaScript の置き場所に注意する. JavaScript はページの相対か絶対パスで指定
するので,実行環境に合わせてファイルを正しい場所に配置せねばならない.
- JavaScript の実行タイミングに注意する.js で指定したスクリプトが差し込まれる
場所はページの冒頭 (change_form.html の {% include_admin_script_js %}) なので,
フォームコントロールを読み込んだ後で実行されるように onLoad ハンドラにバインド
しておく.
のような注意が必要だと思います.
頂いた情報、まだ試せていないのですが、そのまんまの回答がDjango
FAQにありました。
正規の方法はまだないのですね。
http://ymasuda.jp/python/django/docs/faq.html#id46
取り急ぎ、ご報告まで。