【问题标题】:Sending request.user object to ModelForm from class based generic view in Django从 Django 中基于类的通用视图将 request.user 对象发送到 ModelForm
【发布时间】:2011-08-13 22:55:50
【问题描述】:

因此,我的目标是能够在我的 ModelForm 中过滤 ModelChoiceField 查询集,以仅包含 request.user 创建的地点。

我的 ModelForm 很简单:

class PlaceEventForm(models.ModelForm):
    class Meta:
        model = Event

我希望能够添加如下内容:

def __init__(self, *args, **kwargs):
    super(PlaceEventForm, self).__init__(*args, **kwargs)
    self.fields['place'].queryset = Place.objects.filter(created_by=request.user)

但是,我似乎找不到在 ModelForm 中访问请求的方法。

我的看法是这样的:

class PlaceEventFormView(CreateView):
    form_class = PlaceEventForm
    template_name = 'events/event_create.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(PlaceEventFormView, self).dispatch(*args, **kwargs)

我不确定这是否接近我应该做的,但我试过了:

def get_form_kwargs(self):
    kwargs = super(PlaceEventFormView, self).get_form_kwargs()
    kwargs.update({'place_user': self.request.user})
    return kwargs

但我得到了错误:init() 得到了一个意外的关键字参数 'place_user'

关于这个有什么想法吗?或者任何人都可以想出一种方法来过滤视图中的 ModelChoiceField 而无需将我的请求传递给 ModelForm?

【问题讨论】:

    标签: django django-forms django-class-based-views


    【解决方案1】:

    要更新 Yuji 对 Django 1.10+(包括 Django 2.0+)的回答,请参见下面的示例(注意更新的方法签名)。 Yuji 建议的方法将查询集与其他业务逻辑一起保留在视图中,并有助于保持任何扩展 models.ModelForm 的表单类简洁明了。

    def get_form(self, form_class=None):
        if form_class is None:
            form_class = self.get_form_class()
        form = super(MyView, self).get_form()
        form.fields['place'].queryset = Place.objects.filter(created_by=self.request.user)
        return form
    

    短:

    def get_form(self, form_class=None):
        form = super(MyView, self).get_form(form_class)
        form.fields['place'].queryset = Place.objects.filter(created_by=self.request.user)
        return form
    

    【讨论】:

      【解决方案2】:

      您需要在PlaceEventForm.__init__()方法中从kwargs中弹出键user,以防止它进入ModelForm.__init__()方法:

      views.py:

      class PlaceEventFormView(CreateView):
          form_class = PlaceEventForm
          template_name = 'events/event_create.html'
      
          @method_decorator(login_required)
          def dispatch(self, *args, **kwargs):
              return super(PlaceEventFormView, self).dispatch(*args, **kwargs)
      
          def get_form_kwargs(self):
              kwargs = super(PlaceEventFormView, self).get_form_kwargs()
              kwargs.update({'place_user': self.request.user})
              return kwargs
      

      forms.py:

      class PlaceEventForm(models.ModelForm):
          class Meta:
              model = Event
      
          def __init__(self, *args, **kwargs):
              user = kwargs.pop('place_user')
              # now kwargs doesn't contain 'place_user', so we can safely pass it to the base class method
              super(PlaceEventForm, self).__init__(*args, **kwargs)
              self.fields['place'].queryset = Place.objects.filter(created_by=user)
      

      【讨论】:

      • 非常感谢!完美运行。
      • 无法理解您是如何做到这一点的。
      • 我把例子写完了,如果还不清楚请告诉我
      • # now kwargs doesn't ... 后面的 # now kwargs doesn't ... 评论是我第一次看到无数 Django Python SO 答案中的解释!谢谢!超级有帮助!
      • 我花了很长时间才把这个答案和this answer 放在一起来弄清楚如何使用经过身份验证的用户选择外键。使用 .initial 声音现在如此基本(手/脸)
      【解决方案3】:

      我使用的是 iPhone,但请执行以下操作:

      def get_form(self, form_class):
           form = super(MyView, self).get_form(form_class)
           form.fields['place'].querset = Place....
           return form
      

      哇,太难了!不支持缩进!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-07
        • 2014-09-18
        • 1970-01-01
        • 1970-01-01
        • 2018-07-18
        • 1970-01-01
        相关资源
        最近更新 更多