ManyToMany в Django Admin как Muti Select CheckBox
я использую python 3.9 с django 4.1.
У меня есть список квартир и список их товаров, каждая квартира может иметь ноль или более товаров.
режимы создаются следующим образом:
class Commodities(models.Model):
name_en = models.CharField(verbose_name=_('English Name'), unique=True, blank=True, null=True, max_length=200)
name_he = models.CharField(verbose_name=_('Hebrew Name'), unique=True, blank=True, null=True, max_length=200)
name_fr = models.CharField(verbose_name=_('French Name'), unique=True, blank=True, null=True, max_length=200)
class Meta:
constraints = [
models.CheckConstraint(
check=Q(name_en__isnull=False) | Q(name_he__isnull=False) | Q(name_fr__isnull=False),
name='not_all_null_commodities'
)
]
def __str__(self):
return getattr(self, 'name_' + get_2l_lang())
class Apartment(models.Model):
address = models.ForeignKey(Address, verbose_name=_('Apartment Address'), on_delete=models.CASCADE)
floor = models.IntegerField(verbose_name=_('Floor'), null=True, blank=True)
apartment = models.CharField(verbose_name=_('Apartment'), null=True, blank=True, max_length=10)
def __str__(self):
return self.address.__str__() + \
(' ' + _('Entrance') + ' ' + self.address.entrance if self.address.entrance else '') + \
(' ' + _('Floor') + ' ' + str(self.floor) if self.floor else '') + \
(' ' + _('Apartment') + ' ' + self.apartment if self.apartment else '')
class ApartmentCommodities(models.Model):
apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE, verbose_name=_('Apartment'))
commodity = models.ForeignKey(Commodities, on_delete=models.CASCADE)
def __str__(self):
return self.apartment.__str__() + ' - ' + getattr(self.commodity, 'name_' + get_2l_lang())
Я хочу, чтобы на странице администратора, когда я добавляю или изменяю квартиру, товары отображались в виде нескольких флажков, вместо того, чтобы выбирать добавление и удаление каждого товара построчно.
Я много гуглил... и прочитал о filter_horizontal на https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_horizontal
и я попытался попробовать
поэтому я создаю forms.py
с таким кодом:
class CommoditiesModelForm(forms.ModelForm):
class Meta:
model = Commodities
fields = '__all__'
def __init__(self, *args, **kwargs):
forms.ModelForm.__init__(self, *args, **kwargs)
self.fields['commodities'].queryset = Commodities
и затем я создал admin.ModelAdmin
для квартир
class ApartmentAdmin(admin.ModelAdmin):
form = CommoditiesModelForm
list_display = ('get_country', 'get_city', 'get_street', 'get_number', 'get_entrance', 'apartment', 'floor')
#inlines = [ApartmentCommoditiesInline]
filter_horizontal = ('commodities',)
но это возвращает ошибку:
<class 'goods.admin.ApartmentAdmin'>: (admin.E019) The value of 'filter_horizontal[0]' refers to 'commodities', which is not a field of 'goods.Apartment'.
Я где-то читал, что для создания этого эффекта достаточно добавить formfiled_override
вот так:
class ApartmentAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': CheckboxSelectMultiple},
}
но это ничего не изменило.
Итак, как я могу правильно решить эту проблему?
ok так django может автоматизировать вещи за кулисами больше, чем я знал :)
сначала я создаю отношение "многие-ко-многим" из модели квартир к модулю товаров:
class Apartment(models.Model):
...
commodities = models.ManyToManyField(Commodities)
...
Я удалил CommoditiesModelForm
, с которым я пытался работать, также удалил ApartmentCommodities
модель, так как эта models.ManyToManyField
создает что-то вроде для меня за кулисами, мне также не нужен инлайн ApartmentCommoditiesInline
в модуль Admin.
Теперь, когда модель квартиры имеет отношения "многие ко многим", я могу просто использовать formfield_overrides
на ней:
class ApartmentAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': CheckboxSelectMultiple},
}
и все :)