管理员使用中间 Table 和多选的 Django M2M 关系问题
Django M2M Relationship Issue with Admin Using Intermediate Table with Multiselect
我正在处理 m2m 关系,使用 through 设置中间值 table。问题是我需要显示 multiselection 而不是正常的 dorpdown 但是当我 select 多个项目并保存时我得到一个错误。
ValueError: Cannot assign "<QuerySet [<Facility: facility1>, <Facility: facility2>]>": "Property.facility" must be a "Facility" instance.
我还在 admin.TabularInline 中展示了这个模型,它允许我 select 每行只有一个项目,因为表格内联提供了插入多个表单的能力。
我已经尝试了多种解决方案,例如自定义保存和许多其他事情,以及一些我如何能够保存它的方法,但随后出现了问题。我只需要显示一个带有 multiselect 小部件的表单来执行此 selection.
models.py
class Facility(models.Model):
name = models.CharField(max_length=200)
class Property(models.Model):
name = models.CharField(max_length=200)
area = models.CharField(max_length=200)
facility = models.ManyToManyField(Facility, through="PropertyFacility")
class PropertyFacility(models.Model):
prop = models.ForeignKey(
Property, related_name="facilities", on_delete=models.CASCADE
)
facility = models.ForeignKey(
Facility, related_name="properties", on_delete=models.CASCADE
)
admin.py
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import ugettext_lazy as _
class PropertyFacilityForm(forms.ModelForm):
facility = forms.ModelMultipleChoiceField(Facility.objects.all(), required=True, widget=FilteredSelectMultiple(_('ss'), False, attrs={'rows':'10'})
class PropertyFacilityInline(admin.TabularInline):
model = Property.facility.through
form = PropertyFacilityForm
class PropertyAdmin(TabbedModelAdmin):
model = Property
tab_facilities = (PropertyFacilityInline,)
tab_property = (
(
"Property Details",
{
"fields": (
"name",
"area",
)
},
),
)
tabs = [
("Property", tab_property),
("Facilities", tab_facilities),
]
它让我像这样在管理员上显示
在这里你可以看到我可以 select 多个 select 但这里的形式应该是一个而不是多个。
我只想显示一个带有 multiselection 小部件的单一表单,它允许我使用 multi select 并保存它,然后在 change_view 上显示 select编辑了一个,剩下的未select编辑了。
我通过添加一些用于保存 m2m 字段的自定义逻辑解决了这个问题。
admin.py
class PropertyForm(forms.ModelForm):
facility = forms.ModelMultipleChoiceField(Facility.objects.all(), required=False, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Property
fields = ["id", "name", "area", "city"]
def save(self, commit=True):
prop_facilities = self.cleaned_data.pop('facility')
instance = forms.ModelForm.save(self, commit=False)
instance.facility.clear()
for facility in prop_facilities:
PropertyFacility.objects.create(facility=facility, prop=instance)
return instance
class PropertyAdmin(TabbedModelAdmin):
model = Property
tab_facilities = (("Facilities", {"fields": ("facility", )},),)
tab_property = (
(
"Property Details",
{
"fields": (
"name",
"area",
)
},
),
)
tabs = [
("Property", tab_property),
("Facilities", tab_facilities),
]
我正在处理 m2m 关系,使用 through 设置中间值 table。问题是我需要显示 multiselection 而不是正常的 dorpdown 但是当我 select 多个项目并保存时我得到一个错误。
ValueError: Cannot assign "<QuerySet [<Facility: facility1>, <Facility: facility2>]>": "Property.facility" must be a "Facility" instance.
我还在 admin.TabularInline 中展示了这个模型,它允许我 select 每行只有一个项目,因为表格内联提供了插入多个表单的能力。
我已经尝试了多种解决方案,例如自定义保存和许多其他事情,以及一些我如何能够保存它的方法,但随后出现了问题。我只需要显示一个带有 multiselect 小部件的表单来执行此 selection.
models.py
class Facility(models.Model):
name = models.CharField(max_length=200)
class Property(models.Model):
name = models.CharField(max_length=200)
area = models.CharField(max_length=200)
facility = models.ManyToManyField(Facility, through="PropertyFacility")
class PropertyFacility(models.Model):
prop = models.ForeignKey(
Property, related_name="facilities", on_delete=models.CASCADE
)
facility = models.ForeignKey(
Facility, related_name="properties", on_delete=models.CASCADE
)
admin.py
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import ugettext_lazy as _
class PropertyFacilityForm(forms.ModelForm):
facility = forms.ModelMultipleChoiceField(Facility.objects.all(), required=True, widget=FilteredSelectMultiple(_('ss'), False, attrs={'rows':'10'})
class PropertyFacilityInline(admin.TabularInline):
model = Property.facility.through
form = PropertyFacilityForm
class PropertyAdmin(TabbedModelAdmin):
model = Property
tab_facilities = (PropertyFacilityInline,)
tab_property = (
(
"Property Details",
{
"fields": (
"name",
"area",
)
},
),
)
tabs = [
("Property", tab_property),
("Facilities", tab_facilities),
]
它让我像这样在管理员上显示 在这里你可以看到我可以 select 多个 select 但这里的形式应该是一个而不是多个。
我只想显示一个带有 multiselection 小部件的单一表单,它允许我使用 multi select 并保存它,然后在 change_view 上显示 select编辑了一个,剩下的未select编辑了。
我通过添加一些用于保存 m2m 字段的自定义逻辑解决了这个问题。
admin.py
class PropertyForm(forms.ModelForm):
facility = forms.ModelMultipleChoiceField(Facility.objects.all(), required=False, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Property
fields = ["id", "name", "area", "city"]
def save(self, commit=True):
prop_facilities = self.cleaned_data.pop('facility')
instance = forms.ModelForm.save(self, commit=False)
instance.facility.clear()
for facility in prop_facilities:
PropertyFacility.objects.create(facility=facility, prop=instance)
return instance
class PropertyAdmin(TabbedModelAdmin):
model = Property
tab_facilities = (("Facilities", {"fields": ("facility", )},),)
tab_property = (
(
"Property Details",
{
"fields": (
"name",
"area",
)
},
),
)
tabs = [
("Property", tab_property),
("Facilities", tab_facilities),
]