ModelChoiceField 给出“选择一个有效的选择”,用 ajax 调用填充选择

Posted

技术标签:

【中文标题】ModelChoiceField 给出“选择一个有效的选择”,用 ajax 调用填充选择【英文标题】:ModelChoiceField gives “Select a valid choice” populating select with ajax call 【发布时间】:2018-04-10 03:21:23 【问题描述】:

我已经在多个线程上尝试了所有可能的解决方案,但仍然无法解决问题。我有以下代码:

models.py

class CustomerVisit(models.Model):
  start_date = models.DateField()
  end_date = models.DateField()
  customer = models.ForeignKey(Customer)
  address = models.ForeignKey(Address)

forms.py

address = forms.ModelChoiceField(label='Address',
                                 queryset=Address.objects.none(),
                             widget=forms.Select(attrs='style': 'width: 100%;'))
customer = forms.ModelChoiceField(label='Customer',
                                  queryset=Customer.objects.all(),
                          widget=forms.Select(attrs='style': 'width: 100%;'))

views.py

if request.method == "POST":
    # Cleaning fields
    post = request.POST.copy()
    post['address'] = Address.objects.get(id=post['address'])
    post['start_date'] = dateparser.parse(post['start_date'])
    post['end_date'] = dateparser.parse(post['end_date'])
    # Updating request.POST
    request.POST = post
    form = CustomerVisitForm(request.POST)
    if form.is_valid():
        form.save(commit=True)
        return redirect("customervisit:calendar")

js

$("#id_customer").select2().on("change", function () 
    var customer_id = $("#id_customer").val();
    var id_address = $("#id_address");
    id_address.select2(
        ajax: 
            url: '/get_customer_address/' + customer_id,
            dataType: "json",
            type: "GET",
            data: function (params) 

                var queryParameters = 
                    term: params.term
                
                return queryParameters;
            ,
            processResults: function (data) 
                return 
                    results: $.map(data, function (item) 
                        return 
                            text: item.text,
                            id: item.id
                        
                    )
                ;
            
        
    );
);

我的address 使用ajax call using select2 选择基于customer 选择的填充。在阅读了几个线程后,我注意到modelchoicefield 需要一个Address 对象,这就是为什么我在验证表单之前在我的视图中使用以下代码:post['address'] = Address.objects.get(id=post['address']) 但我仍然收到Select a valid choice. That choice is not one of the available choices. 错误

我正在使用queryset=Address.objects.none(),,因为我需要一个空选择

【问题讨论】:

你不应该这样做。所有这些逻辑都应该放在表单中。 @DanielRoseman 我相信你说的是清洁领域吧?如果是这样,我有一个 TODO 来改变它。谢谢 但关键是您不想对地址字段进行这种转换。我不知道你为什么认为它需要一个实例,表单字段的全部意义在于它们获取 POST 数据并将其转换为适当的类型。 我这样做是因为 django 总是显示相同的错误,Select a valid choice. That choice is not one of the available choices. 来自使用 ajax 调用生成的选择 但那是因为您使用.none() 作为该字段的查询集。 【参考方案1】:

问题解决了。

如果以后有人和我有同样的错误,检查ModelChoiceField中的to_python方法救了我的命:

def to_python(self, value):
    if value in self.empty_values:
        return None
    try:
        key = self.to_field_name or 'pk'
        value = self.queryset.get(**key: value)
    except (ValueError, TypeError, self.queryset.model.DoesNotExist):
        raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
    return value

所以我将queryset 更改为queryset=Address.objects 而不是queryset=Address.objects.none()queryset=Address.objects.all()

感谢 Daniel Roseman 的 cmets

【讨论】:

【参考方案2】:

我知道您想要实现什么,我的解决方案是使用小部件选择将字段初始化为 charfield,然后覆盖 clean 方法。示例:

class InvoiceForm(forms.ModelForm):
    customer = forms.CharField(widget=forms.Select(attrs='style': 'min-width: 150px;'))

    class Meta:
        model = Invoice
        exclude = ['id', 'created', 'is_paid']

    def clean_customer(self):
        customer_id = self.cleaned_data['customer']
        customer = Customer.objects.get(id=customer_id)
        if customer: 
            return customer 
        else:
            raise ValidationError("Customer ID invalid")

【讨论】:

以上是关于ModelChoiceField 给出“选择一个有效的选择”,用 ajax 调用填充选择的主要内容,如果未能解决你的问题,请参考以下文章

如何从两个模型填充 ModelChoiceField

对于大量选择,ModelChoiceField 都有哪些替代方法?

表单 ModelChoiceField 查询集 + 额外选择字段 django 表单

Modelchoicefield 查询集混淆

如何在 ModelChoiceField 中使用多个查询集?

ModelChoiceField 和模板