![](/img/trans.png)
[英]Django: ModelMultipleChoiceField doesn't select initial choices
[英]Django ModelMultipleChoiceField 1:N initial
我有兩個型號,機器和設備
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, *args, **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__
調試日志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 -> <QuerySet [<Device: 10126>, <Device: 10127>]>
[api-857c7fc84d-rh42v api-app] show_hidden_initial -> False
[api-857c7fc84d-rh42v api-app] help_text ->
[api-857c7fc84d-rh42v api-app] disabled -> False
[api-857c7fc84d-rh42v api-app] label_suffix -> None
[api-857c7fc84d-rh42v api-app] localize -> False
[api-857c7fc84d-rh42v api-app] widget -> <django.forms.widgets.SelectMultiple object at 0x7f7d749597f0>
[api-857c7fc84d-rh42v api-app] error_messages -> {'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 -> <QuerySet [<Device: 10036>, <Device: 10135>, <Device: 10062>, <Device: 10069>, <Device: 10101>, <Device: 10139>, <Device: 10022>, <Device: 10149>, <Device: 10103>, <Device: 10146>, <Device: 10020>, <Device: 10040>, <Device: 10075>, <Device: 10123>, <Device: 10059>, <Device: 10001>, <Device: 10142>, <Device: 10148>, <Device: 10097>, <Device: 10118>, '...(remaining elements truncated)...']>
作為詞典的小部件:
[api-66c9c5d85c-qtnrq api-app] attrs -> {}
[api-66c9c5d85c-qtnrq api-app] choices -> <django.forms.models.ModelChoiceIterator object at 0x7f6c73ad4ac8>
[api-66c9c5d85c-qtnrq api-app] is_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
一個錯誤? 由於在我的情況下,查詢集中始終會丟失初始值,因為我的查詢集是未分配設備的集合。
請嘗試設置queryset
屬性:
if self.instance:
self.fields['devices'].queryset = self.instance.devices.all()
你需要將選擇作為元組傳遞,為了將結果查詢轉換為元組,你必須做類似下面的事情,它將工作:
CHOICES = tuple((x.id, x.devices) for x in Device.objects.all())
class MachineForm(forms.ModelForm):
devices = forms.MultipleChoiceField(choices=CHOICES)
class Meta:
model = Machine
fields = '__all__'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.