カスタムウィジェットの作成方法に関するドキュメントを見つけるのに苦労しています。
私の質問は:
ありがとう。
その通りですDjangoはこの特定のトピックに関するドキュメントを提供していません。 _Django.forms.widgets
_ (I 'そのモジュールのクラスを以下で参照します)。
カスタムウィジェットを作成する場合、管理インターフェイスまたは通常のフォームに同等に使用できますか?
管理者は一部のウィジェットをオーバーライドします( _Django.contrib.admin.options.FORMFIELD_FOR_DBFIELD_DEFAULTS
_ を参照)。おそらくModelAdmin
をサブクラス化して_formfield_overrides
_属性を変更することはできますが、ModelAdmin
で何も行ったことがないので、ここでは手伝いません...
ユーザーにアイテムのリストの編集を許可する場合、どのウィジェットをサブクラス化する必要がありますか?ウィジェットのどのメソッドをオーバーライド/実装する必要がありますか?
あなたのウィジェットはおそらくデフォルトのウィジェットと共通点はありません(もしあればSelect
で?!)。 Widget
のサブクラスで、組み込みの共通パターンを見つけた場合は、後で変更できます。
次のメソッドを実装します。
render(self, name, value, attrs=None, renderer=None)
簡単な例については、_Input.render
_をご覧ください。また、HTMLに含まれているユーザー定義の属性もサポートしています。 「id」属性を追加することもできます。その方法については、_MultipleHiddenInput.render
_を参照してください。 HTMLを直接出力するときに_mark_safe
_を使用することを忘れないでください。かなり複雑なウィジェットがある場合は、テンプレートレンダリングを使用できます( example )。
_has_changed(self, initial, data)
オプション。 adminで変更内容に関するメッセージを記録するために使用されます。
ユーザーの入力からデータモデルに戻るのはどのウィジェットメソッドですか?
これはウィジェットとは何の関係もありません-Djangoは以前のリクエストでどのウィジェットが使用されたかを知ることができません。フォームから送信されたフォーム(POST)データのみを使用できます。フィールドメソッド_Field.to_python
_は、入力をPythonデータ型に変換するために使用されます(入力が無効な場合はValidationError
を発生させることがあります)。
他の回答に加えて、これはカスタムウィジェットの小さなコードサンプルです。
widgets.py
:
from Django.forms.widgets import Widget
from Django.template import loader
from Django.utils.safestring import mark_safe
class MyWidget(Widget):
template_name = 'myapp/my_widget.html'
def get_context(self, name, value, attrs=None):
return {'widget': {
'name': name,
'value': value,
}}
def render(self, name, value, attrs=None):
context = self.get_context(name, value, attrs)
template = loader.get_template(self.template_name).render(context)
return mark_safe(template)
my_widget.html
:
<textarea id="mywidget-{{ widget.name }}" name="{{ widget.name }}">
{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
ウィジェットは、 フォームレンダリングAPI を使用してレンダリングされるようになりました。
注:ここには3つの質問があります。最初の2つの質問については、AndiDogによる完全な回答を参照してください。私はここで3番目の質問に答えているだけです:
Q.ユーザーの入力からデータモデルに戻るのはどのウィジェットメソッドですか?
A. value_from_datadict
メソッド-ウィジェットのrender
メソッドの逆のようなものです。このメソッドはおそらく、ウィジェットのDjango docsが「ウィジェットがHTMLのレンダリングと、 Widget。
通常、既存のウィジェットの1つから継承することから始め、新しい目的のプロパティを追加してから、レンダリングメソッドを変更します。以下は、私が実装したフィルター可能な選択ウィジェットの例です。フィルタリングはjquery mobileを介して行われます。
class FilterableSelectWidget(forms.Select):
def __init__(self, attrs=None, choices=()):
super(FilterableSelectWidget, self).__init__(attrs, choices)
# choices can be any iterable, but we may need to render this widget
# multiple times. Thus, collapse it into a list so it can be consumed
# more than once.
self._data_filter = {}
@property
def data_filter(self):
return self._data_filter
@data_filter.setter
def data_filter(self, attr_dict):
self._data_filter.update(attr_dict)
def render_option(self, selected_choices, option_value, option_label):
option_value = force_text(option_value)
if option_value in selected_choices:
selected_html = mark_safe(' selected="selected"')
if not self.allow_multiple_selected:
# Only allow for a single selection.
selected_choices.remove(option_value)
else:
selected_html = ''
# use self.data_filter
filtertext = self.data_filter.get(option_value)
data_filtertext = 'data-filtertext="{filtertext}"'.\
format(filtertext=filtertext) if filtertext else ''
return format_html('<option value="{0}"{1} {3}>{2}</option>',
option_value,
selected_html,
force_text(option_label),
mark_safe(data_filtertext))
次に、フォームを作成するビューで、フィールドにdata_filterを設定します。
some_form.fields["some_field"] = \
forms.ChoiceField(choices=choices,
widget=FilterableSelectWidget)
some_form.fields["some_field"].widget.data_filter = \
data_filter
Djangoのサイトにあるドキュメントはこれをまったく助けません。ウィジェットのカスタマイズに関する提案 here は、form.as_p()
の使用を中断し、Djangoで提示されているフォームの値、つまりウィジェットの集合を危険にさらします。
私が一番気に入った解決策は floppyforms です。テンプレートを使用してウィジェットの定義を容易にし、Django独自のフォームモジュールの(ほぼ)透過的な置き換えです。優れたドキュメントがあり、簡単に入手できます。