2014-12-26 5 views
0

Хорошо, мне нужна небольшая помощь здесь.django - обнаружить IntegrityError без "save()"

У меня есть модель, которая имеет поле под названием slug = models.SlugField(unique=True), и я пытаюсь установить это поле на save() путем добавления 1 пули, если пробка уже существует и так далее.

Я хочу рассмотреть условия гонки.

def set_uniqslug(self, slug, i=0): 
    new_slug = u"{}{}".format(slug, str(i) if i else '') 
    try: 
     with transaction.atomic(): 
      self.slug = slugify(new_slug.lower()) 
      self.save() 
      return self 
     return self 
    except IntegrityError as e: 
     i += 1 
     return set_uniqslug(self, slug, i) 

def save(self, *args, **kwargs): 
    if not self.pk: 
     set_uniqslug(self.name.lower()) # <--- but it does "save" above. 
     # i want something like: 
     # self.slug = self.get_uniqslug(self.name.lower()) 
     super(Company, self).save(*args, **kwargs) 

моя проблема, если я называю set_uniqslug(), он должен попытаться спасти, просто знать, если есть IntegrityError. в моем коде он переходит в бесконечный цикл.

Как я могу узнать без сохранения, если есть IntegrityError, а затем просто вернуть уникальный slug обратно в метод save()?

обновление:

я попытался это:

with transaction.atomic(): 
    if Company.objects.filter(slug=new_slug).exists(): 
     i += 1 
     return self.set_uniqslug(slug, i) 
    return new_slug 

он работает, но у меня есть боли в животе, заблокировав READ -действие. я не блокирую другие запросы или делаю другие плохие вещи, делая это?

+0

Вы можете предотвратить бесконечный цикл, вызвав 'super(). Save()' внутри метода set_uniqslug() ', вам больше не нужно вызывать метод' save() '. Тем не менее, если вы не строите сайт с очень высоким объемом, добавление чтения не является огромным издержками. –

+0

Тем не менее, тот факт, что хранение пули является проблемой, которая требует поиска в Google, предполагает, что более простой слизень стоит рассмотреть. –

+1

Рассмотрите формат «name-pk» slug, более простой способ разрешить конфликты slug. – abstractpaper

ответ

1

Возможно, ваша версия с установленным номером не работает. Это будет зависеть от вашей базы данных и ее реализации уровней изоляции транзакций; но, принимая пример PostgreSQL, уровень изоляции по умолчанию READ COMMITTED не помешает другой транзакции вставить строку с тем же самым слипом между вашей проверкой и множеством.

Так что используйте оригинальную оптимистичную идею блокировки. Как указал Хьюго Роджер-Браун, вы можете избежать бесконечного цикла, вызвав save() суперкласса.

Наконец, вы можете рассмотреть альтернативный формат слизняков. Много раз пул будет включать идентификатор базы данных (как и сам StackOverflow), что исключает возможность дублирования пули.

+0

Вы правы, но я бы хотел скрыть идентификатор в URL-адресе, чтобы никто не мог узнать, сколько профилей компаний существует в db ... но я думаю, что это лучше и безопаснее. – doniyor

Смежные вопросы