Desde 2013 más o menos, get_or_create es atómica, por lo que se encarga de concurrencia bien:
Este método es atómica Suponiendo un uso correcto, la configuración de base de datos correcta , y corregir el comportamiento de la base de datos subyacente. Sin embargo, si la exclusividad no se aplica en el nivel de base de datos para los kwargs utilizados en una llamada get_or_create (vea unique or unique_together), este método es propenso a una condición de carrera que puede dar lugar a múltiples filas con los mismos parámetros insertado simultáneamente.
Si está utilizando MySQL, asegúrese de utilizar el nivel de aislamiento READ COMMITTED en lugar de REPETIBLE LEER (por defecto), de lo contrario puede ver casos en get_or_create lanzará una IntegrityError pero el objeto no aparecerá en una llamada get() posterior.
Desde: https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create
Aquí hay un ejemplo de cómo podría hacerlo:
definir un modelo único, ya sea con = 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>})
... o utilizando 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>})
Observe cómo los campos que no son únicos están en la definición predeterminada, NO entre los campos únicos en get_or_create. Esto asegurará que tus creaciones sean atómicas.
Así es como se implementó en Django: https://github.com/django/django/blob/fd60e6c8878986a102f0125d9cdf61c717605cf1/django/db/models/query.py#L466 - Intente crear un objeto, capture un eventual IntegrityError y devuelva la copia en ese caso. En otras palabras: manejar la atomicidad en la base de datos.
Uno de los dos subprocesos recibirá un error de registro duplicado y una excepción. No habrá datos duplicados. –