python – Django ModelMultipleChoiceField 1:N初始

前端之家收集整理的这篇文章主要介绍了python – Django ModelMultipleChoiceField 1:N初始前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我有两个型号,机器和设备

class Machine(models.Model):
    pass

class Device(models.Model):
    machine = models.ForeignKey(Machine,related_name='devices')

现在在Django Admin,在机器更改页面中,我希望能够添加1-N设备引用,它工作得很好并且与ManyToMany关系开箱即用,这是它在管理中的外观(所需)

enter image description here

我正在尝试使用forms.ModelMultipleChoiceField进行1:N选择.我已经想出了保存这种关系,但是提供初始值似乎并不起作用.

我如何尝试提供初始值:

class MachineForm(forms.ModelForm):
    class Meta:
        model = Machine
        fields = '__all__'

    devices = forms.ModelMultipleChoiceField(queryset=Device.objects.filter(machine=None).all(),required=False) 

    def __init__(self,*args,**kwargs):
        super(MachineForm,self).__init__(*args,**kwargs)
        if self.instance:
            self.fields['devices'].initial = self.instance.devices.all()

    def save(self,**kwargs):
        instance = super(MachineForm,self).save(commit=False)
        self.fields['devices'].initial.update(machine=None)
        instance.save()
        self.cleaned_data['devices'].update(machine=instance)
        return instance

在调试器中,我可以清楚地知道初始查询集是非空的:

initial< QuerySet [< Device:10126>,< Device:10127>]>
 但是django admin中的字段仍然是空的.

enter image description here

谁知道为什么?

编辑:

我已经试过了

self.fields [‘devices’].initial = self.instance.devices.all().values_list(‘id’,flat = True)

没有运气.

EDIT2:

从self.fields调试日志[‘devices’] .__ dict__

[api-857c7fc84d-rh42v api-app] empty_label -> None
[api-857c7fc84d-rh42v api-app] required -> False
[api-857c7fc84d-rh42v api-app] label -> None
[api-857c7fc84d-rh42v api-app] initial -> required': 'This field is required.','invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.','list': 'Enter a list of values.','invalid_pk_value': '"%(pk)s" is not a valid value.'}
[api-857c7fc84d-rh42v api-app] validators -> []
[api-857c7fc84d-rh42v api-app] _queryset -> 

作为词典的小部件:

[api-66c9c5d85c-qtnrq api-app] attrs -> {}
[api-66c9c5d85c-qtnrq api-app] choices -> required -> False
最佳答案
我设法解决了这个问题.在查看Django文档的几个小时后,我在ModelMultipleChoiceField源代码中找到了这个.

https://docs.djangoproject.com/en/2.1/_modules/django/forms/models/#ModelMultipleChoiceField

def _check_values(self,value):
        """
        Given a list of possible PK values,return a QuerySet of the
        corresponding objects. Raise a ValidationError if a given value is
        invalid (not a valid PK,not in the queryset,etc.) <- NOT IN THE QUERYSET?!
        """
        key = self.to_field_name or 'pk'
        # deduplicate given values to avoid creating many querysets or
        # requiring the database backend deduplicate efficiently.
        try:
            value = frozenset(value)
        except TypeError:
            # list of lists isn't hashable,for example
            raise ValidationError(
                self.error_messages['list'],code='list',)
        for pk in value:
            try:
                self.queryset.filter(**{key: pk}) # <------
            except (ValueError,TypeError):
                raise ValidationError(
                    self.error_messages['invalid_pk_value'],code='invalid_pk_value',params={'pk': pk},)
        qs = self.queryset.filter(**{'%s__in' % key: value})
        pks = {str(getattr(o,key)) for o in qs}
        for val in value:
            if str(val) not in pks:
                raise ValidationError(
                    self.error_messages['invalid_choice'],code='invalid_choice',params={'value': val},)
        return qs

问题是我的初始和我的查询集是分离的,因此它在某个地方默默地失败了.

所以chaning

devices = forms.ModelMultipleChoiceField(queryset=Device.objects.filter(machine=None).all(),required=False)

devices = forms.ModelMultipleChoiceField(queryset=Device.objects.all(),required=False)

解决了这个问题.

我想知道这是否是Django中的一个错误?由于在我的情况下,查询集中始终会丢失初始值,因为我的查询集是未分配设备的集合.

猜你在找的Python相关文章