1. ホーム
  2. python

[解決済み] カスタムフォームで Django の時間/日付ウィジェットを使用する

2022-04-20 06:52:02

質問

カスタムビューで、デフォルトの管理者が使用しているJavaScriptの日付と時刻のウィジェットを使用するにはどうすればよいですか?

を調べました。 Djangoフォームのドキュメント そして、django.contrib.admin.widgets について簡単に触れていますが、どう使えばいいのかわかりません?

これは、私がそれを適用したい私のテンプレートです。

<form action="." method="POST">
    <table>
        {% for f in form %}
           <tr> <td> {{ f.name }}</td> <td>{{ f }}</td> </tr>
        {% endfor %}
    </table>
    <input type="submit" name="submit" value="Add Product">
</form>

また、このフォームのために私自身がビューを書き上げたわけではなく、一般的なビューを使用していることを指摘しておく必要があると思います。以下はurl.pyのエントリです。

(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

そして、私はDjango/MVC/MTVの全てに関連する初心者です、だから気楽に行きましょう...

どのように解決するのですか?

この回答は時間とともに複雑化し、多くのハックが必要なため、おそらくこれを行うことは避けるべきでしょう。これは管理者の文書化されていない内部実装の詳細に依存しており、Django の将来のバージョンで再び壊れる可能性が高く、他の JS カレンダーウィジェットを見つけてそれを使うよりも実装が簡単ではありません。

とはいえ、これを実現しようと思ったら、こうすればいいのです。

  1. 自分で定義する ModelForm のサブクラスを作成し(アプリのforms.pyに書くのがベスト)、そのサブクラスに対して AdminDateWidget / AdminTimeWidget / AdminSplitDateTime (「mydate」などをモデルの適切なフィールド名に置き換えてください)。

     from django import forms
     from my_app.models import Product
     from django.contrib.admin import widgets                                       
    
     class ProductForm(forms.ModelForm):
         class Meta:
             model = Product
         def __init__(self, *args, **kwargs):
             super(ProductForm, self).__init__(*args, **kwargs)
             self.fields['mydate'].widget = widgets.AdminDateWidget()
             self.fields['mytime'].widget = widgets.AdminTimeWidget()
             self.fields['mydatetime'].widget = widgets.AdminSplitDateTime()
    
    
  2. URLconfを変更し、以下を渡すようにします。 'form_class': ProductForm の代わりに 'model': Product を一般的な create_object ビュー(つまり from my_app.forms import ProductForm ではなく from my_app.models import Product もちろんです)。

  3. テンプレートのheadに {{ form.media }} を使用して、Javascriptファイルへのリンクを出力してください。

  4. 管理画面の日付/時刻ウィジェットは、国際化JSがロードされていることを前提とし、core.jsも必要としますが、どちらも自動的には提供されません。 ですから、上記のテンプレートでは {{ form.media }} が必要になります。

     <script type="text/javascript" src="/my_admin/jsi18n/"></script>
     <script type="text/javascript" src="/media/admin/js/core.js"></script>
    
    

また、以下のような管理用CSSを使用するのもよいでしょう(感謝 アレックス を参照してください)。

    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

このことは、Django の管理メディア ( ADMIN_MEDIA_PREFIX ) は /media/admin/ にあります - あなたのセットアップに合わせて変更することができます。 理想的には、この値をハードコーディングする代わりに、コンテキストプロセッサを使用してテンプレートに渡すことですが、それはこの質問の範囲外です。

また、/my_admin/jsi18n/ という URL を django.views.i18n.javascript_catalog ビュー (I18N を使っていない場合は null_javascript_catalog) に手動で配線する必要がありま す。 これは管理アプリケーションを経由するのではなく、自分で行う必要があります。 ジェレミー をご覧ください。) URLconfのサンプルコードです。

(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

最後に、Django 1.2 以降を使用している場合、ウィジェットがメディアを見つけるのを助けるために、テンプレートにいくつかのコードを追加する必要があります。

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

ありがとうございます ルペファイスコ を追加していただきました。