Как очистить и сохранить несколько экземпляров один за другим в Django, используя методы clean и save?
Я заметил, что при использовании админки Django и при выборе/изменении нескольких экземпляров и нажатии на кнопку сохранения ( например, см. картинку ниже, она не имеет прямого отношения к коду ниже), Django очищает/проверяет все экземпляры и затем сохраняет их по одному.
так ли все работает в 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
к вашей проблеме, я просто сделал неглубокий подсчет активных объектов в моей.