django从基于类的视图初始化表单中的选项

django从基于类的视图初始化表单中的选项,django,forms,django-class-based-views,Django,Forms,Django Class Based Views,我已经看到了很多关于在不使用基于类的视图时如何解决这个问题的答案。在CBV上做这件事有没有什么明显的不足之处 基本上,我希望在我的表单中有一个multipleechoicefield,它的选择取决于视图中发生的事情。e、 我使用URL中的PK来执行一些后端请求,然后这些请求应该用于填充选择 # forms.py from django.forms import Form, MultipleChoiceField, CharField class EmailForm(Form): us

我已经看到了很多关于在不使用基于类的视图时如何解决这个问题的答案。在CBV上做这件事有没有什么明显的不足之处

基本上,我希望在我的表单中有一个multipleechoicefield,它的选择取决于视图中发生的事情。e、 我使用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)
#forms.py
从django.forms导入表单、MultipleChoiceField、CharField
班级电邮表格(表格):
用户=MultipleChoiceField(必需=False)
主题=CharField(最大长度=100)
message=CharField()
定义初始化(self,用户=None,*args,**kwargs):
super(EmailForm,self)。\uuuuuu init\uuuuuu(*args,**kwargs)
如果用户:
self.fields['users'].choices=用户
#url.py
从django.conf.url导入url、模式
从。视图导入电子邮件视图
#url模式
urlpatterns=模式(“”,
url(r'^(?P\d+$),EmailView.as_view(),name=“maindex”),
)
#views.py
从django.views.generic导入FormView,TemplateView
从.forms导入电子邮件表单
类EmailView(FormView):
模板名称='myapp/email.html'
form_class=EmailForm
成功_ulr='/谢谢/'
def表单_有效(自身、表单):
#在这里做事
返回super(EmailView,self)。表单_有效(表单)
基本上,它归结为如何/在何处从视图调用init函数。我该怎么做?还是我错过了另一条路?我想在视图中重写
get\u form\u kwargs
,但没能让它做任何事情


谢谢

好的,FormMixin调用
get\u 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\u 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\u form\u kwargs
到类似

def get_form_kwargs(self):
    form_kws = super(EmailView, self).get_form_kwargs()
    form_kws["users"] = some_user_queryset
    return form_kws
一种方法是:

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
这允许您在视图中设置用户选项并将其传递给表单。

视图:

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

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

def get_表单(self、*args、**kwargs):
form=super().get_form(*args,**kwargs)
表单.字段['rank'].选项=
报税表

其中,
rank
是字段名。这样我就使用默认表单。

您可以覆盖get\u表单

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

表格:

视图:


谢谢,这就清楚了。我现在明白了。我几乎完全尝试了这一点,但在init中遇到了一个意外的关键字参数。因此,弹出它是完全有意义的,现在我对它的理解稍微好了一点,我意识到可能最整洁的方法是在init中有一个命名的
users
参数:
def\uuu init\uuuuu(self,users=None,*args,**kwargs)
Ye,你也可以这样做。我已经发布了我的方式,但另一个选择是好的。
def get_form(self, *args, **kwargs):
    form= super().get_form(*args, **kwargs)
    form.fields['rank'].choices= <sequence of 2-tuples>
    return form
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