Начиная с 2013 года, get_or_create является атомарным, поэтому он прекрасно обрабатывает параллелизм:
Этот метод атомарный, при условии правильного использования, правильной базы данных
конфигурация и правильное поведение базовой базы данных.
Однако, если уникальность не обеспечивается на уровне базы данных для
kwargs, используемые в вызове get_or_create (см. unique или unique_together),
этот метод склонен к состоянию гонки, которое может привести к множественным
строки с одинаковыми параметрами вставляются одновременно.
Если вы используете MySQL, обязательно используйте изоляцию READ COMMITTED
уровень, а не REPEATABLE READ (по умолчанию), в противном случае вы можете увидеть
случаи, когда get_or_create вызовет IntegrityError, но объект
не появится в последующем вызове get ().
От: https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create
Вот пример того, как вы могли бы сделать это:
Определить модель с уникальным = True:
class MyModel(models.Model):
slug = models.SlugField(max_length=255, unique=True)
name = models.CharField(max_length=255)
MyModel.objects.get_or_create(slug=<user_slug_here>, defaults={"name": <user_name_here>})
... или с помощью unique_togheter:
class MyModel(models.Model):
prefix = models.CharField(max_length=3)
slug = models.SlugField(max_length=255)
name = models.CharField(max_length=255)
class Meta:
unique_together = ("prefix", "slug")
MyModel.objects.get_or_create(prefix=<user_prefix_here>, slug=<user_slug_here>, defaults={"name": <user_name_here>})
Обратите внимание на то, как неуникальные поля находятся в dict по умолчанию, а НЕ среди уникальных полей в get_or_create. Это обеспечит атомарность ваших творений.
Вот как это реализовано в Django: https://github.com/django/django/blob/fd60e6c8878986a102f0125d9cdf61c717605cf1/django/db/models/query.py#L466 - Попробуйте создать объект, перехватите возможную ошибку IntegrityError и в этом случае верните копию. Другими словами: обрабатывать атомарность в базе данных.