Как обрабатывать django.db.utils.IntegrityError для асинхронных POST? (Можете ли вы исключить IntegrityError?)

У меня есть модель с сигнальным хуком @BEFORE_CREATE следующим образом:

from django.lifecycle.hooks import BEFORE_CREATE

class Item(models.Model):
    title = models.CharField()
    slug = models.JSONField(unique=True)

    @hook(BEFORE_CREATE)
    def populate_slug(self):
        # Create a slug from the title
        # If the slug already exists, append "-{n}"
        # to make sure it is unique
        slug[0] = slugify(self.title)
        n = 2
        while List.objects.filter(slug=slug).exists():
            slug[0] = f"{slug[0]-{n}"
            n += 1
        self.slug = slug

Это отлично работает в моих тестах, когда элементы создаются синхронно один за другим:

i1 = Item.objects.create(title="Hello")
i2 = Item.objects.create(title="Hello")

self.assertEqual(i1.slug, ["hello"])
self.assertEqual(i2.slug, ["hello-2"])

Однако на моем реальном фронтенде я создаю эти объекты асинхронно и в одно и то же время:

const item1 = axios.post(POST_ITEMS_URL, {title: "Hello"})
const item2 = axios.post(POST_ITEMS_URL, {title: "Hello"})
Promise.all([item1, item2]);

Что дает мне эту ошибку:

web_1  | django.db.utils.IntegrityError: duplicate key value violates unique constraint "app_item_slug_key"
web_1  | DETAIL:  Key (slug)=(["hello"]) already exists.

Простым исправлением (я думаю) будет изменение моего @hook на AFTER_CREATE, но я хотел бы избежать дополнительной записи для всех объектов, если это возможно.

Можно ли куда-нибудь поместить except IntegrityError? Если да, то куда?

Или как еще я могу решить эту проблему?

Я использую PostGRE, если это имеет значение.

Выяснили, куда поместить IntegrityError - путем перезаписи метода create представления Item:

# To retry 3 times
    def create(self, request, *args, **kwargs):
        n = 0
        while n < 4:
            try:
                serializer = self.get_serializer(data=request.data)
                serializer.is_valid(raise_exception=True)
                self.perform_create(serializer)
                headers = self.get_success_headers(serializer.data)
                return Response(
                    serializer.data, status=status.HTTP_201_CREATED, headers=headers
                )
            except IntegrityError:
                n += 1
                continue
            break

Async POSTs на фронтенде теперь работают :)

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