Django: получить случайный объект из базы данных по id, но если id не существует, попробовать еще раз

Попытка получить случайный объект из базы данных с идентификатором. Некоторые идентификаторы в таблице базы данных отсутствуют, например, 1, 2, 4, 5, 6, 19, 20... поэтому мне нужно убедиться, что я не получу ошибку при попытке получить объект.

Это, кажется, работает. Есть ли лучший способ.

def get_random_title():
  title_count = OriginalTitle.objects.count()
  random_id = random.randrange(1, title_count)
  random_title_obj = None

  while random_title_obj is None:
    try:
      random_title_obj = OriginalTitle.objects.get(id=random_id)
    except ObjectDoesNotExist:
      continue
  return random_title_obj.title

def play(request):
  random_title = get_random_title()
  context = {
    'original_title': random_title
  }
  return render(request, 'game/game.html', context)
     

Вы можете использовать random.sample() на объекте QuerySet. или изменить порядок следования строк.

OriginalTitle.objects.order_by('?')[:1]


# edit your get_random_title
def get_random_title():
  random_title_obj = OriginalTitle.objects.order_by('?')[0]
  return random_title_obj.title

пожалуйста, прочитайте более подробную информацию в этом ответе

Ок. Спасибо за ответы. Я избавился от функции get_random_title() и просто поместил одну строку в представление play()

def play(request):
  random_title = OriginalTitle.objects.order_by("?").first().title
  context = {
    'original_title': random_title
  }
  return render(request, 'game/game.html', context)

Одно замечание всем, кто использует этот ответ: Теперь я вижу в docs. говорится: "Обратите внимание: запросы order_by('?') могут быть дорогими и медленными, в зависимости от используемой вами базы данных."

Использование .order_by('?') является дорогостоящим . Действительно, как говорится в документации :

Примечание: order_by('?') запросы могут быть дорогими и медленными, в зависимости от используемого бэкенда базы данных.

Для большинства баз данных он присвоит каждой записи случайное число, а затем упорядочит ее по этому числу, что делает его линейным по размеру таблицы.

Вы можете вернуть образец базы данных с помощью:

def get_random_title():
  title_count = OriginalTitle.objects.count()
  idx = random.randrange(0, title_count)
  random_title_obj = OriginalTitle.objects.all()[idx].title

Это сделает два запроса, но для больших таблиц может превзойти .order_by('?').

Вернуться на верх