我正在尝试从此解决方案here构建ModelForm
,但是我收到此错误:
'User' object has no attribute 'get'
我们的想法是让ModelForm
构建一个表单,当提交用户登录更新条目时。
models.py是:
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)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(UserDetailsForm, self)
if self.request:
obj.user = UserProfile.objects.get(user=self.request.user)
obj.save()
我在models.py中的模型是
class UserProfile(models.Model):
user = models.OneToOneField(User)
mobile_phone = models.CharField(max_length=30,help_text='Max 30 characters.',blank=True)
#have shortened this for simplicity
def __unicode__(self):
return self.mobile_phone
此处的请求是来自views.py:
的问题追溯 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/')
答案 0 :(得分:3)
你需要一些更简单的东西。将此作为您的模型形式:
class UserDetailsForm(ModelForm):
class Meta:
model = UserProfile
fields = ['mobile_phone']
在您看来:
from django.core.urlresolvers import reverse_lazy
from django.views.generic import UpdateView
from .models import UserDetailsForm, UserProfile
class UpdateProfile(UpdateView):
template_name = 'users/update_profile.html'
form_class = UserDetailsForm
model = UserProfile
success_url = reverse_lazy('home')
def get_object(self, queryset=None):
'''This loads the profile of the currently logged in user'''
return UserProfile.objects.get(user=self.request.user)
def form_valid(self, form):
'''Here is where you set the user for the new profile'''
instance = form.instance # This is the new object being saved
instance.user = self.request.user
instance.save()
return super(UpdateProfile, self).form_valid(form)
在urls.py
中,您需要确保使用已登录的用户调用该视图:
from django.contrib.auth.decorators import login_required
from django.views.generic TemplateView
from .views import UpdateProfile
urlpatterns = patterns('',
(r'^profile/update/$', login_required(UpdateProfile.as_view())),
(r'^$', TemplateView.as_view(template='index.html'), name='home'),
)
答案 1 :(得分:1)
form = UserDetailsForm(request.user, request.POST, request.FILES)
问题是您将用户对象作为位置参数传递,而您的表单期望第一个位置参数是表单数据。同时,您的表单需要一个包含请求对象的关键字参数request
,但您没有传递这样的参数。将上面的行更改为:
form = UserDetailsForm(request.POST, request.FILES, request=request)
我无法看到您的完整视图功能,但对于简单的表单处理,您可能需要考虑使用基于类的视图,基于Django' UpdateView
,就像Burhan建议的那样。
答案 2 :(得分:0)
__init__
而不是:
return super(UserDetailsForm, self).__init__(*args, **kwargs)
尝试:
forms.ModelForm.__init__(self, *args, **kwargs)
它对我有用..
答案 3 :(得分:0)
写这个答案,因为我在一周内被这个错误咬了两次。 来到这个问题,帮助我找出问题毫无用处。 此代码的问题在于您已将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)
另请注意,modelform的__init__默认def为__init __(self,* args,** kwargs)
上面的动态表单初始化是一个很好的例子。
似乎django在这种情况下将传入的变量视为request_user为some_field,并且正在尝试调用一个名为get的方法,即' UserModel'不具有。如果你检查堆栈跟踪,你会注意到。下面的堆栈跟踪是一个模拟的示例。
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)`
如果你决定选择一个选项。你必须记得在调用self.fields之前调用super。因为self.fields是由super方法创建的。如果你没有,你将遇到另一个属性错误,没有名为fields的字段。