Метод 'save' модели Django ORM и состояние гонки / ACID Isolation

если мы рассмотрим следующий код:

class SomeModel(models.Model):
    ...
    def save(self, *args, **kwargs):
        self.validate_unique()
        super().save()

    def validate_unique(self, *args, **kwargs):
        super().validate_unique(*args, **kwargs)
        
        # Doing an ORM query on the model with *filter* on the model attributes & an associated model, 
        # and if exist - dont create a new instance, if not - create a new instance.
        is_duplicated = SomeModel.objects.filter(name=given_name_from_user, attribute_from_associated_model=some_attr)
        if is_duplicated:
             raise Exception("go wrong")
        # Else - continue to save

Теперь это будет работать с сервером разработки, но не с производственным сервером, таким как gunicorn или uvicorn, потому что метод сохранения гарантирует нам атомарность, но не изоляцию, верно?

чтобы гарантировать изоляцию, мы должны использовать 'get_or_create' на уровне представления?

Я где-то ошибаюсь? Любой комментарий поможет, спасибо!

Вы должны использовать UniqueConstraint. Это предотвратит создание экземпляра с определенными полями с одинаковым значением.

Также get_or_create не создаст экземпляр с теми же значениями, которые были предоставлены. Но между этими двумя стратегиями есть разница. Если вы используете UniqureConstraint, она предотвратит дублирование записей при любом способе создания экземпляра. Но в стратегии get_or_create она будет предотвращать дублирование экземпляров только при ее вызове.

class SomeModel(models.Model):
    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["name", "attribute_from_associated_model"], name="unique_constraint_name"
        )
    ]

Если я правильно понимаю, вы должны использовать unique_together ярлык Django:

class SomeModel(models.Model):
    name = models.CharField(max_length=45)
    foo = models.IntegerField()
    bar = models.IntegerField()

    class Meta:
        unique_together = [('name', 'foo')]

Теперь при попытке создать дубликат записи будет выброшена ошибка IntregityError:

SomeModel.objects.create(name='t1', foo=1, bar=2)
SomeModel.objects.create(name='t1', foo=1, bar=3)
# django.db.utils.IntregityError
Вернуться на верх