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},
    }

и все :)

Вернуться на верх