Django Включить ManyToManyField для «другой» модели в ModelForm - PullRequest
1 голос
/ 23 марта 2020

Я хотел бы иметь форму с предварительно установленными флажками ManyToManyField.

models.py

class Store(models.Model):
    ...

class Brand(models.Model):
   stores = models.ManyToManyField(Store, blank=True, related_name="brands")

forms.py

class StoreForm(ModelForm):

    class Meta:
        model = Store
        fields = ('brands',)

Я получаю это исключение:

django.core.exceptions.FieldError: Unknown field(s) (brands) specified for Store

Я знаю, что могу добавить поле в класс вручную:

brands = forms.ModelMultipleChoiceField(
         queryset=Brand.objects.all(),
         widget=forms.CheckboxSelectMultiple,
    )

Если я сделаю это, флажки не будут предварительно установлены.

Как можно включить поле ManyToMany с «другой стороны» модели (из магазина)?

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Одной из возможностей является определение поля на «другой» модели. Поэтому вместо того, чтобы писать это:

class Store(models.Model):
    ...

class Brand(models.Model):
   stores = models.ManyToManyField(Store, blank=True, related_name="brands")

Вы можете написать это:

class Brand(models.Model):
...

class Store(models.Model):
    brands = models.ManyToManyField(Brand, blank=True, related_name="stores")

Или, если вы вручную добавили поле в форму, вы можете заполнить его начальное значение в метод __init__() формы.

0 голосов
/ 23 марта 2020

@ hedg ie Изменение поля в другой модели не очень хороший вариант для меня, потому что я его уже использую.

Но __init__() был хорошим намеком. Я придумала это решение, и оно, кажется, работает.

class StoreForm(ModelForm):
    def __init__(self, *args, **kwargs):
        if kwargs.get('instance'):
            brand_ids = [t.pk for t in kwargs['instance'].brands.all()]

            kwargs['initial'] = {
                'brands': brand_ids,
            }
        super().__init__(*args, **kwargs)

    # https://stackoverflow.com/questions/49932426/save-many-to-many-field-django-forms
    def save(self, commit=True):
        # Get the unsaved Pizza instance
        instance = forms.ModelForm.save(self, False)

        # Prepare a 'save_m2m' method for the form,
        old_save_m2m = self.save_m2m

        def save_m2m():
            old_save_m2m()
            # This is where we actually link the pizza with toppings
            instance.brands.clear()
            for brand in self.cleaned_data['brands']:
                instance.brands.add(brand)

        self.save_m2m = save_m2m

        # Do we need to save all changes now?
        # Just like this
        # if commit:
        instance.save()
        self.save_m2m()

        return instance

    brands = forms.ModelMultipleChoiceField(
         queryset=Brand.objects.all(),
         widget=forms.CheckboxSelectMultiple,
    )

Хотя, кажется, оно не очень элегантно. Интересно, почему django не поддерживает лучший способ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...