Я хочу взять последние 10 экземпляров модели и иметь этот код:
Model.objects.all().order_by('-id')[:10]
Правда ли, что сначала подберут все экземпляры, а затем возьмут только 10 последних? Есть ли более эффективный метод?
Я хочу взять последние 10 экземпляров модели и иметь этот код:
Model.objects.all().order_by('-id')[:10]
Правда ли, что сначала подберут все экземпляры, а затем возьмут только 10 последних? Есть ли более эффективный метод?
Ответы:
Наборы запросов 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>]
На самом деле, я думаю, что LIMIT 10
они будут выданы базе данных, поэтому срезы будут выполняться не в Python, а в базе данных.
См. Limiting-querysets для получения дополнительной информации.
Похоже, что решение в вопросе больше не работает с Django 1.7 и выдает ошибку: «Невозможно изменить порядок запроса после того, как был взят фрагмент»
Согласно документации https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets, принудительное использование параметра «step» синтаксиса фрагмента Python оценивает запрос. Это работает так:
Model.objects.all().order_by('-id')[:10:1]
Тем не менее, мне интересно, выполняется ли ограничение в срезах SQL или Python, весь возвращаемый массив результатов. Нет смысла извлекать огромные списки из памяти приложения.
Да. Если вы хотите получить ограниченное подмножество объектов, вы можете использовать следующий код:
Пример:
obj=emp.objects.all()[0:10]
Начало 0 необязательно, поэтому
obj=emp.objects.all()[:10]
Приведенный выше код возвращает первые 10 экземпляров.
В качестве дополнения и наблюдения к другим полезным ответам, стоит заметить, что на самом деле выполнение [:10]
срезов вернет первые 10 элементов списка , а не последние 10 ...
Чтобы получить последние 10 вы должны сделать [-10:]
вместо этого (см. Здесь ). Это поможет вам избежать использования order_by('-id')
с -
реверсом элементов.
Product.objects.filter(~Q(price=0))[-5:]
вызывает у меня ту же ошибку: «Отрицательное индексирование не поддерживается».