Избегайте расы при создании объекта с увеличенным полем - PullRequest
1 голос
/ 26 марта 2020

Я пытаюсь создать объект MyModel, но я хочу установить в поле bar увеличенное значение уже существующего наибольшего значения bar в дБ для указанного foo. Проблема здесь в условиях гонки. Я хотел выполнить все логи c на стороне БД за один шаг без успеха. Я нашел решение, но это не самый элегантный способ. Бесконечные циклы всегда плохая идея.

from django.db import models, IntegrityError
from django.db.models import Max


class MyModel(models.Model):
    foo = models.UUIDField(default=uuid4)
    bar = models.PositiveIntegerField()

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['id', 'other_id'],
                name='unique_id_other_id'
            )
        ]

    @classmethod
    def create_my_model(cls, data):
        while True:
            bar = (cls.objects.filter(foo=data['foo']).aggregate(Max('bar')).get('bar_max')
                   or 0) + 1
            try:
                cls.objects.create(bar=bar, **data)
            except IntegrityError:
                continue

Я буду рад, если кто-нибудь может указать мне любое направление, как справиться с этим. BR

1 Ответ

0 голосов
/ 26 марта 2020

Решение

Использование django.db.models.AutoField

class MyModel(models.Model):
    foo = models.UUIDField(primary_key=True, default=uuid4)
    bar = models.AutoField()

IntegerField, который автоматически увеличивается в соответствии с доступными идентификаторами. Вам обычно не нужно использовать это напрямую; поле первичного ключа будет автоматически добавлено в вашу модель, если вы не укажете иное. См. Поля первичного ключа Automati c.

https://docs.djangoproject.com/en/3.0/ref/models/fields/#autofield

Комментарий

Хотя лично я просто сделаю следующее и оставьте первичный ключ в покое (это де-факто способ сделать что-то в Django)

class MyModel(models.Model):
    foo = models.UUIDField(unique=True, default=uuid4)

, что даст MyModel автоматическое c поле первичного ключа

id = models.AutoField(primary_key=True)

https://docs.djangoproject.com/en/3.0/topics/db/models/#automatic -primary-key-fields

или если вы хотите переименовать поле первичного ключа automati c:

class MyModel(models.Model):
    bar = models.AutoField(primary_key=True)
    foo = models.UUIDField(unique=True, default=uuid4)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...