简体   繁体   English

在基于类的视图中为动态创建的ModelChoiceField设置初始值

[英]Set initial value for dynamically created ModelChoiceField in Class Based View

I'm creating a Form which has a ModelChoiceField . 我正在创建一个具有ModelChoiceFieldForm I'm able to set the values for this field as follows: 我可以如下设置该字段的值:

class DeviceForm(Form):
    devices = ModelChoiceField(queryset=None, widget=RadioSelect, empty_label=None)

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        user_id = kwargs['initial']['user_id']
        devices = Device.objects.filter(user_id=user_id, is_validated=True)
        self.fields['devices'].queryset = devices

This works perfectly, but I can't seem to be able to set an initial value. 这可以完美地工作,但是我似乎无法设置初始值。 I've tried multiple things such as adding an initial value to get_initial() : 我已经尝试了多种方法,例如将初始值添加到get_initial()

def get_initial(self):
    initial = super(DeviceView, self).get_initial()
    initial['user_id'] = self.kwargs['user_id']
    default_device = Device.objects.get(user_id=self.kwargs['user_id'], is_validated=True, is_default=True)
    initial['devices'] = default_device.id
    return initial

But that doesn't work. 但这是行不通的。 I've come across multiple questions on StackOverflow which instantiate the form and pass in an initial value like so: 我在StackOverflow上遇到了多个问题,这些问题实例化了表单并传递了一个初始值,如下所示:

#Get default device
form = DeviceForm(initial={'devices': default_device.id})

But ideally I would like to avoid it, since I'm trying to stick to the Django generic base views (which look like this, and don't allow for an initial kwarg as far as I'm aware): 但理想情况下,我想避免这种情况,因为我试图坚持使用Django通用基础视图(看起来像这样,并且就我所知,不允许initial变形):

def get(self, request, user_id, **kwargs):
    # Do stuff

    form = self.get_form()
    return self.render_to_response(self.get_context_data(form=form))

Setting devices in get_initial() should work, since the self.get_form_kwargs() returns: 因为self.get_form_kwargs()返回:在get_initial()设置设备应该可以工作。

{'prefix': None, 'initial': {'user_id': u'1', 'devices': 42}}

or, depending on what I'm supposed to choose: 或者,取决于我应该选择什么:

{'prefix': None, 'initial': {'user_id': u'1', 'devices': <Device: Device object>}}

Doing the following still doesn't get it to work (basically the the same thing as get_form() manually). 仍然无法执行以下操作(基本上与手动执行get_form()相同)。

def get(self, request, user_id, **kwargs):
    #Do stuff
    form_class = self.get_form_class()
    form = form_class(**self.get_form_kwargs())
    return self.render_to_response(self.get_context_data(form=form))

Setting the initial value in the constructor of the Form also doesn't work: 在Form的构造函数中设置初始值也不起作用:

class DeviceForm(Form):
    devices = ModelChoiceField(queryset=None, widget=RadioSelect, empty_label=None)

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        user_id = kwargs['initial']['user_id']
        devices = Device.objects.filter(user_id=user_id, is_validated=True)
        self.fields['devices'].queryset = devices
        default_device = devices.filter(is_default=True)
        self.fields['devices'].initial = default_device  # or default_device.id

Does anyone know of a way to accomplish this? 有人知道实现此目标的方法吗?

You need to use the suggested way to assign initial , but it's still available in class based views. 您需要使用建议的方式来分配initial ,但是在基于类的视图中仍然可用。 Quoting from django doc : 引用django doc

class MyFormView(View):
    form_class = MyForm
    initial = {'key': 'value'}
    template_name = 'form_template.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

Since you have already overridden your form's __init__ method, it might be easiest to set the initial value there. 由于您已经覆盖了表单的__init__方法,因此在此处设置初始值可能是最简单的。

class DeviceForm(Form):
    devices = ModelChoiceField(queryset=None, widget=RadioSelect, empty_label=None)

    def __init__(self, *args, **kwargs):
        super(DeviceForm, self).__init__(*args, **kwargs)
        user_id = kwargs['initial']['user_id']
        devices = Device.objects.filter(user_id=user_id, is_validated=True)
        self.fields['devices'].queryset = devices
        default_device = Device.objects.get(user_id=user_id, is_validated=True, is_default=True)
        self.fields['devices'].initial = default_device

In the end it was a dumb mistake on my part in the template. 最后,在模板方面,这是我的愚蠢错误。 The value actually got set correctly in the view, but I forgot to set the checked value in the template. 该值实际上已在视图中正确设置,但是我忘记在模板中设置checked值。 I thought it was just using {{form}} , but I wasn't. 我以为它只是使用{{form}} ,但不是。 Just for people who are wondering how you can set it manually: 只适合那些想知道如何手动设置的人:

{% for device in form.devices.field.choices.queryset %}
    <input type="radio" name="devices" value="{{ device.pk }}" class="radio-device"
        {% ifequal form.devices.value device.pk %}checked{% endifequal %}
    />
{% endfor %}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM