この回答を書いているのは、このエラーで 1 週間に 2 回噛まれたからです。この質問に来ましたが、問題を理解するのに役に立ちませんでした。このコードの問題は、request.user オブジェクトを UserDetailsForm の init 関数に渡したことです。また、 initの定義は、request.user で何が起こるかを処理しません。
userprofile = UserProfile.objects.get(user=request.user)
if request.method == 'POST':
====>form = UserDetailsForm(request.user, request.POST, request.FILES)
if form.is_valid(): # it dies here
form.save()
return HttpResponseRedirect('/members-contact/')
矢印を参照してください。それを __init__of ユーザー詳細フォームの定義と比較すると。init がその request.user を予期していないことがわかります。
class UserDetailsForm(ModelForm):
class Meta:
model = UserProfile
fields = ['mobile_phone']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(UserDetailsForm, self).__init__(*args, **kwargs)
オブジェクトを渡すために init を記述する正当な理由があることに注意してください。
def __init__(self, some_object, *args, **kwargs):
super(SomeFormClass, self).__init__(self, *args, **kwargs)
self.fields['some_field'].queryset = SomeModel.objects.filter(some_field = some_object)
また、モデルフォームの __init__ のデフォルト定義には __init__(self, *args, **kwargs) があることに注意してください
上記の動的フォームの初期化は良い例です。
この場合、django は渡された変数 request.user を some_field として扱っており、「UserModel」にはない get というメソッドを呼び出そうとしているようです。スタック トレースを確認するとわかります。以下のスタック トレースは、シミュレートされた例です。
Traceback (most recent call last):
File "/home/user/.local/lib/python3.5/site-packages/django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
return render(request, self.template_name, context)
File "/home/user/.local/lib/python3.5/site- packages/django/shortcuts.py", line 30, in render
content = loader.render_to_string(template_name, context, request, using=using)
---
---
---
packages/django/forms/forms.py", line 297, in non_field_errors
return self.errors.get(NON_FIELD_ERRORS, self.error_class(error_class='nonfield'))
File "/home/user/.local/lib/python3.5/site-packages/django/forms/forms.py", line 161, in errors
self.full_clean()
---
---
---
self._clean_fields()
File "/home/user/.local/lib/python3.5/site-packages/django/forms/forms.py", line 382, in _clean_fields
===>value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))<====
File "/home/sodara/.local/lib/python3.5/site-packages/django/forms/widgets.py", line 238, in value_from_datadict
====> return data.get(name) <====
AttributeError: 'SomeObject' object has no attribute 'get'
data.get はメソッド呼び出しの結果の戻り値 field.widget.value_from_data_dict ... 気が付くと、ここで SomeObject は get メソッドが呼び出されているデータとして扱われています。
質問に答えるには、init を定義して request.user を処理します。
def __init__(self, user, *args, **kwargs):
super(YourFormClass, self).__init__(*args, **kwargs):
self.fields["some_field"].some_attr = user
または、request.user なしでフォームを呼び出します
`form = YourFormClass(request.POST, request.FILES)`
オプション1を使用することにした場合。self.fields を呼び出す前に super を呼び出すことを忘れないでください。self.fields は super メソッドによって作成されるためです。そうしないと、fields という名前のフィールドがないという別の属性エラーが発生します。
編集
Django は、などget_form_kwargs
から継承するフォーム ビューの init に属性を追加するための便利な方法を提供します。django.views.generic.edit.ModelFormMixin
FormView
class MyFormView(FormView):
form_class = MyModelFormClass
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class MyModelFormClass(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user') # Important to do this
# If you dont, calling super will fail because the init does
# not expect, user among the fields.
super().__init__(*args, **kwargs)
self.fields['some_field'].queryset = SomeModel.objects.filter(user=user)