【问题标题】:django Initialising Choices in Form from Class Based Viewdjango 从基于类的视图中初始化表单中的选择
【发布时间】:2013-12-03 15:57:39
【问题描述】:

我已经看到很多关于在不使用基于类的视图时如何解决此问题的答案。在使用 CBV 时,我是否遗漏了一些非常明显的事情?

基本上,我希望在我的表单中有一个 MultipleChoiceField,它的选择取决于视图中发生的事情。例如我使用 URL 中的 PK 来执行一些后端请求,然后应该使用这些请求来填充选项。

# forms.py
from django.forms import Form, MultipleChoiceField, CharField

class EmailForm(Form):

    users = MultipleChoiceField(required=False)
    subject = CharField(max_length=100)
    message = CharField()

    def __init__(self, users=None, *args, **kwargs):
        super(EmailForm, self).__init__(*args, **kwargs)
        if users:
            self.fields['users'].choices = users

#urls.py
from django.conf.urls import url, patterns
from .views import EmailView

# url patterns
urlpatterns = patterns('',
    url( r'^(?P<pk>\d+)$', EmailView.as_view(), name="maindex" ),
)

#views.py
from django.views.generic import FormView, TemplateView
from .forms import EmailForm

class EmailView(FormView):
    template_name = 'myapp/email.html'
    form_class = EmailForm
    success_ulr = '/thanks/'

    def form_valid(self, form):
        # Do stuff here
        return super(EmailView, self).form_valid(form)

基本上,它归结为如何/在何处从视图中调用 init 函数。我怎么做?还是我错过了另一种方式?我想在视图中覆盖get_form_kwargs,但无法做到这一点。

谢谢

【问题讨论】:

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


    【解决方案1】:

    观点:

    from django.views.generic import FormView
    
    class EmailView(FormView):
        # ...
    
        def get_form_kwargs(self):
            kwargs = super(EmailView, self).get_form_kwargs()
    
            # get users, note: you can access request using: self.request
    
            kwargs['users'] = users
            return kwargs
    

    形式:

    from django import forms import Form
    
    class EmailForm(Form):
    
        users = MultipleChoiceField(required=False)
        # ...
    
        def __init__(self, *args, **kwargs):
            self.users = kwargs.pop('users', None)
            super(EmailForm, self).__init__(*args, **kwargs) 
            self.fields['users'].choices = self.users
    

    【讨论】:

    • 谢谢,这样就搞定了。我现在明白了。我几乎完全尝试过这个,但在 init 中有意外的关键字参数时遇到错误。所以弹出它是完全有道理的,现在我对它的理解稍微好一点,我意识到也许最简洁的方法是在 init 中有一个名为 users 的参数:def __init__(self, users=None, *args, **kwargs)
    • 是的,你也可以这样做。我已经发布了我这样做的方式,但其他选项也可以。
    【解决方案2】:

    基本上,我在类似情况下所做的如下(Python 3.5,Django 1.8):

    def get_form(self, *args, **kwargs):
        form= super().get_form(*args, **kwargs)
        form.fields['rank'].choices= <sequence of 2-tuples>
        return form
    

    显然rank 是字段名称。这种方式我使用默认形式。

    【讨论】:

      【解决方案3】:

      好的,FormMixin 调用get_form 来获取看起来像这样的表单类

      def get_form(self, form_class):
          """
          Returns an instance of the form to be used in this view.
          """
          return form_class(**self.get_form_kwargs())
      

      所以你可以覆盖get_form 来自己实例化你的表单

      def get_form(self, form_class):
          return EmailForm(files=self.request.FILES or None,
                           data=self.request.POST or None,
                           users=some_user_queryset)
      

      或者保持更通用一点,将 get_form_kwargs 覆盖为类似

      def get_form_kwargs(self):
          form_kws = super(EmailView, self).get_form_kwargs()
          form_kws["users"] = some_user_queryset
          return form_kws
      

      【讨论】:

        【解决方案4】:

        一种方法是:

        class EmailView(FormView):
            # ...
        
            def get(self, request, *args, **kwargs):
                self.users = ...
                return super(EmailView, self).get(request, *args, **kwargs)
        
            def get_form_kwargs(self):
                kwargs = super(EmailView, self).get_form_kwargs()
                kwargs['users'] = self.users
                return kwargs
        

        这允许您在视图中设置用户选择并将它们传递给表单。

        【讨论】:

          【解决方案5】:

          您可以覆盖 get_form

          我需要根据登录用户更新 ChoiceField 的选项。

          表格:

          class InteractionCreateForm(forms.Form):
              device = forms.ChoiceField(choices=[(None, '----------')])
              ...
          

          查看:

          class InteractionCreateView(FormView):
              form_class = InteractionCreateForm
              ...
          
              def get_form(self, form_class=None):
                  form_class = super().get_form(form_class=None)
          
                  form_class.fields['device'].choices = \
                      form_class.fields['device'].choices \
                      + [(device.pk, device) for device in Device.objects.filter(owner=self.request.user.id)]
          
                  return form_class
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-04
            • 2021-09-27
            • 2015-07-26
            • 1970-01-01
            • 2012-03-22
            • 1970-01-01
            相关资源
            最近更新 更多