web-dev-qa-db-ja.com

Djangoモデルにない追加フィールドを持つModelForm

モデルにされないのフィールドを追加してModelFormを実行しました。フォームを保存するときに、これらのフィールドをいくつかの計算に使用します。

追加のフィールドがフォームに表示され、フォームのアップロード時にPOSTリクエストで送信されます。問題は、フォームを検証するときにcleaned_data辞書に追加されないことです。どうすればそれらにアクセスできますか?

40
Antonio Melé

Django ModelFormを追加のフィールドで拡張することが可能です。カスタムのユーザーモデルとこのModelFormがあると想像してください:

class ProfileForm(forms.ModelForm):

    class Meta:
        model = User
        fields = ['username', 'country', 'website', 'biography']

ここで、追加のフィールドを含めることを想像してください(ユーザーモデルには存在せず、画像のアバターとしましょう)。これを実行してフォームを拡張します。

from Django import forms

class AvatarProfileForm(ProfileForm):

    profile_avatar = forms.ImageField()

    class Meta(ProfileForm.Meta):
        fields = ProfileForm.Meta.fields + ('profile_avatar',)

最後に(フォームにImageFieldがある場合)、ビューでフォームをインスタンス化するときにrequest.FILESを含めることを忘れないでください。

# (view.py)

def edit_profile(request):
    ...
    form = AvatarProfileForm(
        request.POST or None, 
        request.FILES or None, 
        instance=request.user
    )
    ...

それが役に立てば幸い。幸運を!

編集:

AvatarProfileForm.Meta.fields属性で「タプルにタプル(「リスト」ではなく)のみ連結できる」エラーが発生しました。それをタプルに変更して動作しました。

25
Cartucho

必要なすべてのことを実行したように見えることを除いて、非常によく似た問題がありましたが、Djangoの起動時にこのエラーが発生していました。

Django.core.exceptions.FieldError: Unknown field(s) (my_new_field) specified for MyModel

これは私からのばかげた間違いでした。誤ってWidgetクラスを使用してフィールドを宣言しました。

class MyForm(forms.ModelForm):
    my_new_field = forms.HiddenInput()

Fieldクラスの代わりに:

class MyForm(forms.ModelForm):
    my_new_field = forms.CharField(widget=forms.HiddenInput())

ここで手元にある質問には回答していませんが(既によく回答されています)、他の人を助けるかもしれません。

7
Bruno A.

まず、artist_idとartistフィールドは必要ありません。それらはモデルから構築されます。アーティスト名が必要な場合は、artist_nameフィールド、つまりCharFieldを追加します。

さらに、あなたはclean_data内のclean_dataから何かを取得しようとしています。必要なデータがない可能性があります-self.dataの値を使用する必要があります。ここで、POSTからの直接のデータです。

5
gruszczy

この答えは元のポスターには遅すぎるかもしれませんが、他の人を助けるかもしれないと思いました。同じ問題があり、self.cleaned_data( 'artist_id')はclean()メソッドでアクセスできますが、clean_artist()ではアクセスできないことに気付きました。

Metaの 'fields'宣言に追加のフィールドを追加すると、うまくいきました。

    class Meta:
        model = Music
        fields=[..., 'artist_id']

Clean_artist()のself.cleaned_data( 'artist_id')にアクセスできるはずです。

4
B. Choung

はい、解決しました。 cleaned_data ['field_name']で追加のフィールドにアクセスするとKeyErrorが発生するようですが、cleaned_data.get( 'field_name')を使用すると機能します。モデルの通常のフィールドには、cleaned_data ['field_name']を介してアクセスできるため、これは奇妙です。

更新:いいえ、機能しません。 get()を使用すると、KeyErrorは発生しませんが、余分なフィールドがcleaned_data辞書にないため、値はNoneに設定されます。

これがコードです。テンプレートにはオートコンプリートがあるため、フォームには、CharFieldとしてレンダリングされた「artist」フィールドと、指定されたアーティストIDで自動入力される非表示のIntegerFieldがあります。 clean_artistメソッドで、アーティストオブジェクトを選択し、フォームのアーティストフィールドに格納します。

models.py

class Music(models.Model):
    artist = models.ForeignKey(Artist, related_name='music', blank=True, null=True)
    # other fields...

forms.py

class MusicForm(forms.ModelForm):
    artist_id = forms.IntegerField(label="", widget=forms.HiddenInput(), required=False)
    artist = forms.CharField(required=False)
    # other fields ...

    class Meta:
        model = Music

    def clean_artist(self):
        if self.cleaned_data.get('artist') == '':
            artist = None
        else:
            artist_id = self.cleaned_data.get('artist_id') # this returns always None because artist_id is not in cleaned_fields (this seemed to work with previous Django versions but not with current SVN version)
            if artist_id != None:
                artist = Artist.objects.get(id=artist_id)
            else:
                artist = None

    return artist
3
Antonio Melé

最初にフォームにフィールドを追加します

class CreateForm(forms.ModelForm):

extra_field     = forms.CharField(label = 'extra_field', required = False)

次に、データをクリーンアップするときに、self.dataから追加のフィールドを取得する必要があります[〜#〜] not [〜#〜] self.cleaned_data

正解

 self.data.get('extra_field')

間違っている

 self.cleaned_data.get('extra_field')
3
Sreeram

Django 2では、通常のフォームと同じようにフィールドを追加できます

class CreateCompanyForm(forms.ModelForm):

    password_confirmation = forms.CharField(
        label=translate('Password confirmation'),
        max_length=70,
        widget=forms.PasswordInput(),
        required=True,
    )
    company_name = forms.CharField(
        label="Nombre de la Compañía",
        max_length=90,
        widget=forms.TextInput(),
        required=True,
    )

    class Meta:
        model = AppUser
        fields = (
            "email",
            "first_name",
            "last_name",
            "password",
        )
1