我有两个型号,机器和设备
class Machine(models.Model):
pass
class Device(models.Model):
machine = models.ForeignKey(Machine,related_name='devices')
现在在Django Admin,在机器更改页面中,我希望能够添加1-N设备引用,它工作得很好并且与ManyToMany关系开箱即用,这是它在管理中的外观(所需)
我正在尝试使用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中的字段仍然是空的.
谁知道为什么?
编辑:
我已经试过了
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中的一个错误?由于在我的情况下,查询集中始终会丢失初始值,因为我的查询集是未分配设备的集合.