0

マルチフォームウィジェットを使用すると、隠しフィールドを の代わりに _0 _1 などにすることができます。これは、forms.MultiValueField が clean() メソッドで ValidationError() のスローを開始する必要があるまで、すべてうまく機能します。

実際... ValidationError() はフォームエラーを _0 などの代わりに設定します...

代わりに、すべての単一ビューに「if」ラッパーを記述して、このフィールド名をキャッチして _0 に交換します... MultiWidget または MultiValueField でこれを行うことができるよりクリーンな方法はありますか?

MultiValueField clean() 関数内で ValidationError({'myfieldname_0': ['my error',]}) を投げてみましたが、より高いレベルでキャッチされると、「my_error」を self._errors に保存するだけです「myfieldname」ハッシュの下のフォーム (_0 なし)。「site-packages/django/forms/forms.py」でそのようにクリーンアップされているようです とにかく、このアプローチのもう1つの問題は、「myfieldname」をハードコーディングする必要があることです。

要するに、MultiWidget を使用してフォームをシンプルで管理しやすくしたいのですが、このフィールドのハッシュ応答 (フィールド名の末尾) に _0 を追加して、実際の入力レコードと一致させる検証が必要です。これにより、jquery.validation() ( http://jqueryvalidation.org/ ) の統合がはるかに簡単になります。私はまた、悪いデザインを受け入れることにもオープンです...おそらく、MutilWidget shrugs ではなく、MutilValueField が必要なだけです

以下は、私の問題を設定するサンプルコードです。

from django.forms import MultiWidget
from django.forms import MultiValueField
from django.forms import ModelForm
from django.forms import widgets

class MyWidget(MultiWidget):
    """

    """
    def __init__(self, attrs=None, **kwargs):

        # Populated once render() is called
        self.name = u''

        _widgets = (
            widgets.TextInput(attrs=attrs),
            widgets.HiddenInput(attrs=None),
            widgets.HiddenInput(attrs=None),
        )
        super(MyWidget, self).__init__(_widgets, attrs=None, **kwargs)

    def value_from_datadict(self, data, files, name):
        return [ widget.value_from_datadict(data, files, name + '_%s' % i)
                     for i, widget in enumerate(self.widgets)]

class MyFormField(MultiValueField):
    """
    Significantly simplified just to show my problem
    """
    widget = MyWidget

    def clean(self, value):
        # I want to some how alter how this exception is thrown so it isn't put in
        # the self._errors['<fieldname>'] hash, but instead placed in 
        # the self._errors['<fieldname>'_0] hash

        raise ValidationError(self.error_messages['required'])

class MyForm(ModelForm):
    """
   Simple form example of how I'd use the field
    """
    class Meta:
        model = <some model>

    performer = MyFormField(
        max_length=100,
        required=True,
    )
4

2 に答える 2

0

MultiWidget のデフォルト アクションを次のように変更することで問題を解決しました。

from django.forms import MultiWidget as DjangoMultiWidget
from django.utils.safestring import mark_safe

class MultiWidget(DjangoMultiWidget):
    """
    This widget djusts the extends the existing MultiWidget to not
    place an _<index> on the first widget

    Hence a list of 3 widgets would look like:

        <input name="fieldname"/>
        <input name="fieldname_0"/>
        <input name="fieldname_1"/>

    """

    def __init__(self, *attrs, **kwargs):

        # Populated once render() is called
        self.name = u''

        super(MultiWidget, self).__init__(*attrs, **kwargs)


    def render(self, name, value, attrs=None):
        """
        We over-ride this so we can correctly extract the name

        """

        # Save Name
        self.name = name

        if self.is_localized:
            for widget in self.widgets:
                widget.is_localized = self.is_localized
        # value is a list of values, each corresponding to a widget
        # in self.widgets.
        if not isinstance(value, list):
            value = self.decompress(value)
        output = []
        final_attrs = self.build_attrs(attrs)
        id_ = final_attrs.get('id', None)

        # First Entry is not prefixed with underscore (_)
        try:
            widget_value = value[0]
        except IndexError:
            widget_value = None
        output.append(self.widgets[0].render(name, widget_value, final_attrs))

        # now we process the rest
        for i, widget in enumerate(self.widgets[1:]):
            try:
                widget_value = value[i]
            except IndexError:
                widget_value = None
            if id_:
                final_attrs = dict(final_attrs, id='%s_%s' % (id_, i))
            output.append(widget.render(name + '_%s' % i, widget_value, final_attrs))
        return mark_safe(self.format_output(output))

    def format_output(self, rendered_widgets):
        """
        Place an error class
        """
        return u''.join(rendered_widgets) + \
                u'<div class="error" for="id_%s" style="display: none;"></div>' % self.name


    def value_from_datadict(self, data, files, name):
        return [ self.widgets[0].value_from_datadict(data, files, name) ] + \
                [ widget.value_from_datadict(data, files, name + '_%s' % i)
                    for i, widget in enumerate(self.widgets[1:]) ]

コードの大部分は /django/forms/fields.py から直接取得されるため、ここでは魔法は行われていません。

ただし、この方法でフィールドを使用すると、_0 なしで標準例外をスローできますが、実際にはフィールドの内容が格納されている場所を参照します。

<input name="fieldname"/>
<input name="fieldname_0"/>
<input name="fieldname_1"/>

デフォルトの MultiWidget スタイルの代わりに:

<input name="fieldname_0"/>
<input name="fieldname_1"/>
<input name="fieldname_2"/>

最終結果は Django のフレームワークであり、エラー処理は JQuery の検証プラグイン (私の質問で言及されています) と 100% 互換性があります。

うまくいけば、この答えは将来の人々に役立ちます!

于 2013-08-16T01:50:17.350 に答える
0

MultiValueField の compress メソッドで例外をキャッチすることもできます。これにより、フィールド全体の例外を追加できます。私は、 MultiValueField を拡張するフィートとインチのフォーム ウィジェットも維持しています。

初期化部分と圧縮部分は次のとおりです。

class FeetAndInchesField(MultiValueField):
    widget = FeetAndInchesWidget

    def __init__(self, *args, **kwargs):
        errors = self.default_error_messages.copy()
        if 'error_messages' in kwargs:
            errors.update(kwargs['error_messages'])
        localize = kwargs.get('localize', False)
        fields = (
            IntegerField(min_value=0, required=False, localize=localize),
            IntegerField(min_value=0, localize=localize),
            FloatField()
        )
        super(FeetAndInchesField, self).__init__(fields, *args, **kwargs)

    def compress(self, data_list):
        if data_list:
            feet = data_list[0]
            inches = data_list[1]
            fractional_inches = data_list[2]
            if feet == inches == fractional_inches == 0:
                raise ValidationError(u'Please specify a value for feet or inches')
            return sum_feet_inches_fractional_inches(feet, inches, fractional_inches)
        return None

これにより、一度に 1 つずつではなく、すべてのフィールドまたはフィールドの組み合わせに対して例外を発生させることができます。それがあなたを助けることを願っています。

于 2013-08-12T02:22:22.363 に答える