Существует ли метод ModelAdmin, который запускается после Model.clean()?

У меня возникает ошибка ValidationError в методе clean() моей модели

from django.core.exceptions import ValidationError

class PosDetail(models.Model, PosDetailChecksMixin):
    self._errors = set()
    ...
    def clean(self, *args, **kwargs):
        if PosDetail.objects.filter(username=self.username).exists(): # example ValidationError
            self._errors.add('check_duplicates')
            raise ValidationError("This username is already in use.", code="invalid")
        return super().clean(*args, **kwargs)

После этого в форме просмотра изменений администратора после POST-запроса отображается ошибка ValidationError.

я хочу показать кнопку в админке для изменения вида после отправки формы

я попробовал метод save_model, но он не выполняется, если возникает ошибка ValidationError. Я также пытался переопределить метод change_view в ModelAdmin, но он выполняется до метода Model clean, поэтому пропускает валидацию.

@admin.register(PosDetail)
class BddDetailAdmin(admin.ModelAdmin):
    ...
    def change_view(self, request, object_id, form_url="", extra_context=None):
        extra_context = extra_context or {}
        pos_detail = self.get_object(request, object_id)
        
        if request.POST:
            if pos_detail and 'check_duplicates' in pos_detail._errors:
                extra_context['show_save_anyway'] = True
            else:
                extra_context['show_save_anyway'] = False
        return super().change_view(request, object_id, form_url, extra_context)

Существует ли метод ModelAdmin, который запускается после Model.clean(), чтобы я мог перехватить ошибку ValidationError, которая возникает в методе Model.clean.

Для этого следует использовать типовые формы.

К ошибкам формы будут добавлены все ошибки валидации, возникающие при проверке формы. Для форм моделей это включает ошибки, возникающие при проверке модели. Смотрите:


Чтобы связать ошибку с полем, оберните "оригинальную" ValidationError в другую ValidationError:

class PosDetail(models.Model, PosDetailChecksMixin):
    def clean(self, *args, **kwargs):
        if PosDetail.objects.filter(username=self.username).exists():
            raise ValidationError(
                {"username": ValidationError("This username is already in use.", code="duplicate")}
            )
        return super().clean(*args, **kwargs)

Форма с "дублирующимися" данными будет помечена как недействительная:

PosDetail.objects.create(username="foo")
PosDetailForm = modelform_factory(PosDetail, fields=["username"])
form = PosDetailForm(data={"username": "foo"})
print(f"{form.is_valid()=}, {repr(form.errors)}")
>>> form.is_valid()=False, {"username": "This username is already in use."}

В админке вы можете сделать примерно следующее:

class BddDetailAdmin(admin.ModelAdmin): 
    def change_view(self, request, object_id, form_url="", extra_context=None):
        response = super().change_view(request, object_id, form_url, extra_context)
        if response.context_data["adminform"].form.has_error("username", code="duplicate"):
            response.context_data["show_save_anyway"] = True
        return response
Вернуться на верх