42

一連の典型的なモデルが与えられた場合:

# Application A
from django.db import models
class TypicalModelA(models.Model):
    the_date = models.DateField()

 # Application B
from django.db import models
class TypicalModelB(models.Model):
    another_date = models.DateField()

...

すべてのDateFieldのデフォルト ウィジェットをカスタム MyDateWidget に変更するにはどうすればよいでしょうか?

アプリケーションに日付を入力するための jQueryUI 日付ピッカーが必要なため、質問しています。

カスタム ウィジェットで django.db.models.DateField を拡張するカスタム フィールドを検討しました。これは、この種の全面的な変更を実装するための最良の方法ですか? このような変更には、特別な MyDateField をすべてのモデルに具体的にインポートする必要があります。これは、労力がかかり、開発者のエラーが発生しやすく (つまり、いくつかのモデルの DateField が通過します)、私の考えでは、労力の不必要な重複のように思えます。一方、models.DateField の標準バージョンと見なされるものを変更するのは好きではありません。

考えや意見をお待ちしております。

4

6 に答える 6

59

ModelFormクラスで と呼ばれる属性を宣言できますformfield_callback。これは、Django モデルFieldインスタンスを引数として受け取り、フォームFieldインスタンスをフォームで表現する関数である必要があります。

あとは、渡されたモデル フィールドが のインスタンスであるかどうかをDateField確認し、そうであれば、カスタム フィールド/ウィジェットを返すだけです。そうでない場合、モデル フィールドには、formfieldデフォルトのフォーム フィールドを返すために呼び出すことができるという名前のメソッドがあります。

したがって、次のようなものです:

def make_custom_datefield(f):
    if isinstance(f, models.DateField):
        # return form field with your custom widget here...
    else:
        return f.formfield(**kwargs)

class SomeForm(forms.ModelForm)
    formfield_callback = make_custom_datefield

    class Meta:
        # normal modelform stuff here...
于 2009-03-19T05:41:25.710 に答える
8

この記事には何度も助けられました。

その要点は、ModelForm の__init__メソッドをオーバーライドしてから、スーパー クラスのメソッドを呼び出し、__init__フィールドを個別に調整することです。

class PollForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PollForm, self).__init__(*args, **kwargs)
        self.fields['question'].widget = forms.Textarea()

    class Meta:
        model = Poll

このメソッドは Vasil のメソッドよりも複雑に見えるかもしれませんが、再宣言して他の属性をリセットすることなく、フィールドの任意の属性を正確にオーバーライドできるという追加の利点があります。

更新:提案されたアプローチは、各名前を厳密に入力せずにすべての日付フィールドを変更するように一般化できます。

from django.forms import fields as formfields
from django.contrib.admin import widgets

class PollForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PollForm, self).__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields[field_name]
            if isinstance(field, formfields.DateField):
                field.widget = widgets.AdminDateWidget()

    class Meta:
        model = Poll

それは私のために働いpython3django 1.11

于 2009-03-19T03:12:43.790 に答える
6

まあ、デフォルトのフォームウィジェットを変更するためだけにカスタムモデルフィールドを作成することは、実際には明らかな出発点ではありません.

独自のフォーム ウィジェットを作成し、フォーム内のフィールドをオーバーライドして、Soviut の回答のように独自のウィジェットを指定できます。

より短い方法もあります:

class ArticleForm(ModelForm):
     pub_date = DateField(widget=MyDateWidget())

     class Meta:
         model = Article

フォームウィジェットの書き方の例があります.Djangoのフォームパッケージのどこかにあります. これは、3 つのドロップダウンを持つ日付ピッカーです。

標準の HTML 入力要素に JavaScript を追加したいだけの場合、私が通常行うことは、そのままにしておき、後で JavaScript でその id を参照して変更することです。Django が生成する入力フィールドの ID の命名規則は簡単に理解できます。

フォームでウィジェットをオーバーライドするときに、ウィジェットのクラスを提供することもできます。次に、クラス名でjQueryを使用してそれらをすべてキャッチします。

于 2009-03-19T03:21:02.320 に答える
3

私はJQueryを使用しています。日付ピッカーに関連付けたいフィールドの 'id' を探して、それらを JQuery と適切な表示形式にバインドするだけです。

models.py

class ObjectForm(ModelForm):
    class Meta:
        model = Object        
        fields = ['FieldName1','FieldName2']

ビューでレンダリングするページの上部に:

<head>
    <link type="text/css" href="/media/css/ui-darkness/jquery-ui-1.8.2.custom.css" rel="Stylesheet" /> 
    <script type="text/javascript" src="/media/js/jquery-1.4.2.min.js"></script>
    <script type="text/javascript" src="/media/js/jquery-ui-1.8.2.custom.min.js"></script>
</head>
<script type="text/javascript">
 $(function() {
        $("#id_FieldName1").datepicker({ dateFormat: 'yy-mm-dd' });
        $("#id_FieldName2").datepicker({ dateFormat: 'yy-mm-dd' });
 });
</script>
...
{{form}}
于 2010-07-23T20:52:33.423 に答える
1

カスタム ウィジェットを定義し、ウィジェットの内部 Media クラスを使用して、ウィジェットが機能するためにページに含める必要がある JS (および CSS?) ファイルを定義します。これを正しく行うと、ウィジェットを完全に自己完結型で再利用可能にすることができます。これを行う1 つの例については、 django-markitupを参照してください( MarkItUp! ユニバーサル マークアップ エディター用の再利用可能なウィジェットがあります)。

次に、formfield_callback (James Bennett の回答を参照) を使用して、そのウィジェットをフォーム内のすべての DateField に簡単に適用します。

于 2009-03-19T09:31:31.930 に答える