“User”对象没有属性“get”

Ale*_*art 4 python django

我试图ModelForm这里构建一个解决方案,但是我收到此错误:

'User' object has no attribute 'get'
Run Code Online (Sandbox Code Playgroud)

这个想法是构建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()
Run Code Online (Sandbox Code Playgroud)

我在 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
Run Code Online (Sandbox Code Playgroud)

根据这里的请求,我们从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/')
Run Code Online (Sandbox Code Playgroud)

unl*_*kme 5

写这个答案是因为我在一周内被这个错误咬了两次。来到这个问题并没有帮助我解决问题。此代码的问题在于您已将 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/')
Run Code Online (Sandbox Code Playgroud)

参见箭头。如果将其与 __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)
Run Code Online (Sandbox Code Playgroud)

请注意,编写 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)
Run Code Online (Sandbox Code Playgroud)

另请注意,modelform 的 __init__ 的默认 def 有 __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'
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

或者在没有 request.user 的情况下调用表单

    `form = YourFormClass(request.POST, request.FILES)`
Run Code Online (Sandbox Code Playgroud)

如果您决定选择选项一。你必须记住在调用 self.fields 之前先调用 super。因为 self.fields 是由 super 方法创建的。如果不这样做,您将遇到另一个属性错误“没有名为字段的字段”。

编辑

Django 提供了一种方便的方法get_form_kwargs来将属性添加到继承django.views.generic.edit.ModelFormMixinFormView.

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)
Run Code Online (Sandbox Code Playgroud)