Django - ограничение результатов запроса

146

Я хочу взять последние 10 экземпляров модели и иметь этот код:

 Model.objects.all().order_by('-id')[:10]

Правда ли, что сначала забрать все экземпляры, а затем взять только 10 последних? Есть ли более эффективный метод?

Теги:

8 ответов

244
Лучший ответ

Запросы Django являются ленивыми. Это означает, что запрос попадет в базу данных только тогда, когда вы специально спросите результат.

Итак, пока вы не распечатываете или не используете результат запроса, вы можете фильтровать дальше без доступа к базе данных.

Как вы можете видеть ниже, ваш код выполняет только один SQL-запрос для извлечения только последних 10 элементов.

In [19]: import logging                                 
In [20]: l = logging.getLogger('django.db.backends')    
In [21]: l.setLevel(logging.DEBUG)                      
In [22]: l.addHandler(logging.StreamHandler())      
In [23]: User.objects.all().order_by('-id')[:10]          
(0.000) SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" ORDER BY "auth_user"."id" DESC LIMIT 10; args=()
Out[23]: [<User: hamdi>]
  • 0
    Я попробовал это на mongoDB, и он говорит, что SELECT не поддерживается. Как это сделать на mongoDB?
  • 0
    @winux Поскольку это специфично для Django, может показаться, что вам может понадобиться настроить Django для работы именно с базами данных Mongo / NoSQL. По моему опыту, это не типичная настройка для стандартной установки Django ORM.
27

На самом деле, я думаю, что LIMIT 10 будет выдан базе данных, поэтому нарезание не произойдет в Python, а в базе данных.

Подробнее см. limiting-querysets.

  • 0
    Обратите внимание, что это не будет работать для наборов запросов, которые также нуждаются в фильтрации, так как вы не можете фильтровать после нарезки.
10

Похоже, что решение в вопросе больше не работает с Django 1.7 и вызывает ошибку: "Невозможно изменить порядок запроса после того, как был сделан срез"

В соответствии с документацией https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets, заставляющей параметр "шаг" синтаксиса среза Python оценивает запрос. Он работает следующим образом:

Model.objects.all().order_by('-id')[:10:1]

Тем не менее мне интересно, выполняется ли предел в средах SQL или Python весь массив результатов. Нет никакой пользы для извлечения огромных списков в память приложения.

  • 0
    Даже это решение не работает с django> = 1.8.
2

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

Пример:

obj=emp.objects.all()[0:10]

Начало 0 не является обязательным, поэтому

obj=emp.objects.all()[:10]

Приведенный выше код возвращает первые 10 экземпляров.

1

В качестве дополнения и наблюдения к другим полезным ответам, стоит заметить, что на самом деле выполнение [:10] качестве среза вернет первые 10 элементов списка, а не последние 10...

Чтобы получить последние 10, вы должны вместо этого сделать [-10:] (см. Здесь). Это поможет вам избежать использования order_by('-id') с - для order_by('-id') элементов.

  • 0
    Я попробовал это и получил «Отрицательное индексирование не поддерживается».
  • 0
    Это странно ... Не хочешь показать, как ты это написал?
0

Для меня параметр Python Steps делает свою работу, как ответил Николай Грищенко:

Model.objects.all().order_by('-id')[:10:1]

Обратите внимание, что это специфично для noSQL/mongodb

-4

Нет, это не так, как это четко объяснено в документации.

-10

Это не то, что на самом деле происходит. Django НЕ извлекает только нужные результаты. Django будет загружать полную таблицу базы данных (которая является stup [id thing to do) и возвращает вам только последние 10 записей.

Я подтвердил это, запустив SHOW FULL PROCESSLIST на сервере MySQL, и у запроса нет предложения LIMIT.

Django НЕ является хорошим вариантом, если вы собираетесь разработать большое приложение, которое требует высокой масштабируемости.

  • 5
    Пожалуйста, предоставьте дополнительную информацию, чтобы доказать это. Ответ с наибольшим рейтингом показывает, что то, что Django регистрирует как работающее, содержит ограничение. Я только что подтвердил, что это все еще верно для Django 1.10. Мне не удалось показать полный список процессов, потому что запрос был настолько коротким, что не отображался. Включение журналов запросов в соответствии с предложением stackoverflow.com/questions/650238/… MySql (или, точнее, MariaDB) показывает, что запрос содержит предложение limit. Вы случайно не делаете свой запрос таким образом, чтобы он мог быть загружен лениво?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню