Как очистить и сохранить несколько экземпляров один за другим в Django, используя методы clean и save?

Я заметил, что при использовании админки Django и при выборе/изменении нескольких экземпляров и нажатии на кнопку сохранения ( например, см. картинку ниже, она не имеет прямого отношения к коду ниже), Django очищает/проверяет все экземпляры и затем сохраняет их по одному.

enter image description here

так ли все работает в Django или процесс должен быть чистым, а затем сохранить экземпляр перед повторением того же процесса со следующим экземпляром? потому что при попытке установить значение is_active как true для нескольких экземпляров, он проходит условие метода clean без сообщения об ошибке, которое говорит, что только один экземпляр должен быть выбран как true и это правильно, потому что ни один из экземпляров не имеет is_active как true в базе данных еще Но если я нажму кнопку сохранения снова, то появится сообщение об ошибке .

models.py:


class SupplierAddress(models.Model):
    """Model to create supplier's address instances"""

    class Meta:
        """Customize django default way to plural the class name"""

        verbose_name = 'Supplier Address'
        verbose_name_plural = 'Supplier Addresses'
        constraints = [
            models.UniqueConstraint(
                fields=['supplier', 'address'],
                name='supplier_address_unique_appversion'
            )
        ]

    # Define model fields.
    supplier = models.ForeignKey(
        'Supplier',
        on_delete=models.CASCADE,
        related_name='supplier_addresses_supplier'
    )
    address = models.ForeignKey(
        'Address',
        on_delete=models.CASCADE,
        related_name='supplier_addresses_address'
    )
    is_active = models.BooleanField(default=False)

    def clean(self):
       """Restrict the add/change to model fields"""

       if self.is_active is True:

          if SupplierAddress.objects.filter(
                  supplier=self.supplier,
                  is_active=True
          ).exclude(id=self.id).count() >= 1:
              raise forms.ValidationError(
                  {
                     "is_active": "You can't set more than one active address"
                  }
              )

Итак, я смог воспроизвести вашу проблему. Дело в том, что страница администратора Django использует набор форм для сохранения данных в этом виде редактируемого списка. Что вам нужно, так это переопределить этот набор форм (благодаря этому answer) и добавить к нему валидацию, что-то вроде:

from django.forms import BaseModelFormSet

class MyAdminFormSet(BaseModelFormSet):
    def clean(self):
        active_count = 0
        form_set = self.cleaned_data
        for form_data in form_set:
            if form_data['is_active']:
                active_count += 1
                if active_count > 1:
                    raise forms.ValidationError('Cannot have more than one active object')
        return form_set 

class MyModelAdmin(admin.ModelAdmin):
    list_display = (..., 'is_active')
    list_editable = ('is_active',)

    def get_changelist_formset(self, request, **kwargs):
        kwargs['formset'] = MyAdminFormSet
        return super().get_changelist_formset(request, **kwargs)

Обратите внимание, что вам нужно адаптировать MyAdminFormSet к вашей проблеме, я просто сделал неглубокий подсчет активных объектов в моей.

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