Как уменьшить количество запросов в Django ORM?
Доброго времени суток.
Задача такая.
Нужно получить QuerySet, который состоит из вопросов разных категорий. Вопросы должны быть разной сложности, а для каждой сложности своё количество. Все вопросы нужно вытащить из бд в случайном порядке.
Есть вот такой код.
- # models.py
- class Question(models.Model):
- EASY = 1
- MEDIUM = 2
- HARD = 3
- DIFFICULTY_CHOICES = (
- (EASY, 'Легкий'),
- (MEDIUM, 'Средний'),
- (HARD, 'Сложный')
- )
- text = models.TextField(max_length=300, null=True, verbose_name='текст вопроса')
- categories = models.ManyToManyField(Category, related_name="questions", verbose_name='категории')
- difficulty = models.PositiveSmallIntegerField(choices=DIFFICULTY_CHOICES, default=MEDIUM, verbose_name='сложность')
- questions = None
- for category in categories:
- category_id = category['id']
- easy_question_count = category['easy_question_count']
- medium_question_count = category['medium_question_count']
- hard_question_count = category['hard_question_count']
- easy_questions = Question.objects.filter(categories__id=category_id, difficulty=1)
- medium_questions = Question.objects.filter(categories__id=category_id, difficulty=2)
- hard_questions = Question.objects.filter(categories__id=category_id, difficulty=3)
- q1 = easy_questions.objects.random(easy_question_count)
- q2 = medium_questions.objects.random(medium_question_count)
- q3 = hard_questions.objects.random(hard_question_count)
- if questions:
- questions = questions.union(q1).union(q2).union(q3)
- else:
- questions = q1.union(q2).union(q3)
Метод random взят из библиотеки https://github.com/rremizov/django-random-queryset.git
Это библиотека позволяет получить QuerySet определенной длины, состоящий из элементов в случайном порядке.
Это для одной категории, а если категорий, к примеру 10, то получится 60 запросов.
Как это дело оптимизировать? Ломаю голову 3 дня.
Может кто-нибудь подсказать, как мне решить задачу?
3
100
Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!
Пікірлер
- Соңғы өткен сынақтар
- ISНаурыз 31, 2025, 2:03 Т.Ж.
- ААНаурыз 14, 2025, 1:48 Т.Қ.
- ААНаурыз 14, 2025, 1:43 Т.Қ.
- Соңғы пікірлер
- AKСәуір 1, 2025, 11:41 Т.Ж.Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
- VPНаурыз 9, 2025, 4:14 Т.Қ.Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
- ИМҚар. 22, 2024, 9:51 Т.Қ.Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
- Енді форумда талқылаңыз
- МАСәуір 1, 2025, 4:21 Т.Қ.0ff763fe-4e50-455d-a3a6-5699c243b1a5_17_44_22_1.xml
- fАқп. 15, 2025, 1:46 Т.Қ.Подскажите, пожалуйста! Как данный класс можно дополнить, чтобы созданные объекты можно было перемещать мышкой по сцене?
- Не запускается компьютер (точнее работает блок , но сам монитор вообще жесть)В общем я ничего с интернета не скачивала в последнее время. На компе никаких левых пр…
- Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
Добрый день,
Я правильно понимаю, что вы в итоге сваливаете в кучу все вопросы в объект questions?
Возможно, что стоит это переписать иначе, например так
Ну а если вам нужно просто срандомизировать всё в одной куче, то я бы так попробовал написать
-"Я правильно понимаю, что вы в итоге сваливаете в кучу все вопросы в объект questions?"
-Да. Это для дальнейших манипуляций) Возможно, переделаю.
Проблема в том, что для каждой категории нужно разное кол-во вопросов.
Например:
Категория биология, 1 легкий вопрос, 2 средних и 3 сложных;
Категория математика, 2 легких, 2 средних и 2 сложных....и т.д.
Кстати, сделать случайный порядок можно крайне просто:
Документация
Вообще, я слабо понял задачу. Если чуть более понятно сможете описать ее, возможно, смогу помочь
На stackoverflow пишут, что это дорогая операция и лучше по-другому.
В доках пишут:
Note: order_by('?') queries may be expensive and slow, depending on the database backend you’re using.
Я конечно не спец(всего лишь любитель), но я попробую таким способ тоже, может в моем случае будет всё норм.
На счёт задачи.
Есть, к примеру, категории: биология, математика, физика...и т.д.
В каждой категории есть вопросы. У всех вопросов есть сложность от 1 до 3.
Нужно вот что.
Из категории физика нужно достать в случайном порядке 3 легких вопроса, 2 средних и 1 сложный;
Из категории математика 1 легкий, 3 средних, 2 сложных. Тоже в случайном порядке .
Моя проблема в том, что чем больше категорий, тем больше запросов.
Если нужно сделать поиск вопросов только по 1-ой категории, то 6 запросов, по 2-ум категориям 12 запросов и т.д.
Хотелось бы, чтобы при увеличении количества категорий, количество запросов не увеличивалось.
Руслан, посмотрите исходники той библиотеки, которую вы использовали. Там как раз и используется order_by('?') в конечном итоге, а ещё перед этим используется агрегация id всех объектов в queryset. Метод aggregate , кстати, тоже достаточно дорогой, я стараюсь избегать его или кешировать.
Так что в методе random , который выполняет данная библиотека используется сразу два дорогостоящих запроса, хорошо хоть там нет distinct , иначе совсем вилы были бы.
Я вашу задачу понял, но вопрос действительно сложный, пока мыслей нет.
К слову говоря, этот метод order_by('?') мне кажется относительно рандомным, поскольку он выполняет сортировку по случайному столбцу и в случайном направлении (по алфавиту/ против алфавита), если я правильно понял его суть. В общем он настолько рандомный, сколько у вас полей в модели.
Да, я посмотрел, вы абсолютно правы. Единственное, если я правильно понял, если срабатывает условие
то он возвращает QuerySet минуя order_by('?').
В общем, пока что я решил отказаться от этой затеи, и сделал выбор количества легких, средних и сложных вопросов не для каждой категории отдельно, а для всех.
И да, после использования union, нельзя юзать filter, а так как мне нужно потом отфильтровать ещё раз, то я сделал так
А для получения рандомных вопросов нужного мне количества написал вот такую функцию.
Получилось всего 5 запросов.
Готов выслушать критику, если есть)