4

MultiWidgets と MultiValueFields をサブクラス化してフォームを作成する方法を理解しようとしています。シンプルな Address モデルと関連するフォームがあります。

class Address(models.Model):
    user = models.ForeignKey(User)
    city = models.CharField(max_length=255)
    state = models.CharField(choices = settings.STATES, max_length=50)
    postal = models.CharField(max_length=10)
    address = models.TextField()

    class Meta:
        verbose_name_plural = 'Addresses'

class AddressFieldWidget(forms.MultiWidget):
    def decompress(self,value):
        if value:
            return [value[0],value[1],value[2]]
        return ''

    def format_output(self, rendered_widgets):
        str = ''
        line_1 = '<td class="align_left"><label for="contact_phone">Address Line 1</label></td>'

        for field in rendered_widgets:
            str += '<tr>' + line_1
            str += '<td class="align_right">%s</td></tr>' % field
        return '<tr>' + str + '</tr>'

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

class AddressField(forms.MultiValueField):
    def __init__(self,*args,**kwargs):
        fields = (
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
        )
        super(AddressField,self).__init__(*args,**kwargs)
        self.widget = AddressFieldWidget(widgets=[fields[0].widget, fields[1].widget, fields[2].widget])

    def compress(self, data_list):
        return data_list[0] + ' ' + data_list[1] + ' ' + data_list[2]


class AddressFormNew(forms.ModelForm):
    postal = forms.CharField(widget=forms.TextInput(attrs={'class':'small'}))
    address = AddressField()
    city = forms.CharField(widget=forms.TextInput(attrs={'class':'big'}))

    class Meta:
        model = Address

私のビューでこのフォームを使用する方法がわかりません。私はやろうとしています:

@login_required
def render_addresses(request):
    address_form = AddressFormNew()
    if request.method == 'POST':
        address_form = AddressFormNew(request.POST)
        if address_form.is_valid():
            address_form.save()
            return HttpResponse('ok')
        else:
            return HttpResponse(address_form.errors['address'])

    return render_to_response('profile/addresses.html',context_instance=RequestContext(request,{'address_form':address_form}))

その結果、Django から次のエラーが返されます。

値のリストを入力します。

また、request.POST.items() を印刷しようとすると、アドレス応答が 3 つのデータで区切られて返されます。

ここでかなり迷ってしまいました。住所データを 1 行で取得する必要があります。フォームを保存するだけでそれを達成するにはどうすればよいですか?

誰かが私に明確な説明をしてくれれば、本当に感謝しています。

4

3 に答える 3

5

それを解決する必要があるコードで私が見る問題は次のとおりです。

(1)。スーパークラスのinitを呼び出すときの AddressField initメソッドでは、フィールドを引数として渡す必要があります。

class AddressField(forms.MultiValueField):
    def __init__(self,*args,**kwargs):
        fields = (
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
        )
        self.widget = AddressFieldWidget(widgets=[fields[0].widget, fields[1].widget, fields[2].widget])
        super(AddressField,self).__init__(fields=fields,*args,**kwargs)

(2)。あなたは正しいです、あなたの value_from_datadict は正しくありません。要点は、MultiValueField を使用してウィジェットによってデータが取り込まれたということです。したがって、ウィジェットは値のリストを AddressField の対応するサブフィールドに返す必要があります。

スーパークラスのvalue_from_datadictを呼び出すだけで、それが仕事をするか、これを使用することができます(私は同じだと思います):

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

根底にある概念を理解することが重要です。このウィジェットを CharField でも使用できます。その場合、value_from_datadict は文字列を返す必要があります。ただし、MultiValueField を使用しているため、戻り値の型はリストにする必要があります。それが、「値のリストを入力してください」をエラーとして取得するまさにその理由です

データベースに格納された値からフォームにアドレス行 1、2、および 3 を再作成する予定がある場合は、スペースを区切り文字として使用しないでください。そうでない場合は、すべてが良いです:)

ドキュメントやネットで MultiValueField と MultiWidget の良い例を見つけられませんでしたが、プロジェクトの 1 つでそれらを使用する必要があったため、自分で掘り下げる必要がありました。お役に立てれば :)

于 2011-09-21T01:23:18.483 に答える
0

解凍方法も必要だと思います.fields =(...)は外側にある必要があります__init__

于 2011-09-16T03:07:19.610 に答える
-1

Django のソース ファイルは、多くの場合、良いインスピレーションの源になります。django.forms.fields.SplitDateTimeField(しゃれは意図されていません)たとえば、同様のことを行う方法の例を示す をチェックアウトできます。

考えられるエラーとしては、初期化 ( ) 後に self.widget を設定しているsuper(AddressField,self).__init__()ため、フィールドは標準ウィジェットのみを使用している可能性があります。そして、あなたはどちらともfields一緒に送りませんでした。__init__これがあなたができると思う方法の簡単なドラフトですAddressField

class AddressField(forms.MultiValueField):
    widget = MultiValueWidget(widgets=(forms.TextInput, forms.TextInput, forms.TextInput)
    def __init__(self, *args, **kwargs):
        fields = (
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
            forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
        )
        super(AddressField,self).__init__(fields, *args, **kwargs)

    def compress(self, data_list):
        return "%s %s %s" % data_list[0:2]

AddressFieldWidget率直に言って、あなたが何をしようとしているのかよくわからなかったので、これはあなたが持っていたすべての巨大なジャンボを除外します:)

于 2011-09-19T18:10:18.810 に答える