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

stuff = stuff.objects.all()
stuff.count()

= 7

Если я тогда пойду

extra_stuff = stuff.filter(stuff_flag=id)
extra_stuff.count()

= 6. Все хорошо, и у меня есть новый набор запросов в дополнительных материалах.

stuff = stuff.objects.all()[:3]
extra_stuff = stuff.filter(stuff_flag=id)

Я получаю сообщение об ошибке «Невозможно отфильтровать запрос после того, как был взят фрагмент».

Как я могу дальше фильтровать набор запросов, где я ограничил количество результатов?

6
purchas 14 Дек 2015 в 15:39

3 ответа

Лучший ответ

Вы не можете использовать filter() после нарезки набора запросов. Ошибка довольно явная.

Cannot filter a query once a slice has been taken.

Вы можете сделать фильтр в Python

stuff = stuff.objects.all()[:3]
extra_stuff = [s for s in stuff if s.stuff_flag=='flag']

Чтобы получить количество элементов в дополнительном материале, просто используйте len()

extra_stuff_count = len(extra_stuff)

Выполнение фильтрации в Python будет работать нормально, когда размер stuff очень мал, как в этом случае. Если бы у вас был намного больший фрагмент, вы могли бы использовать подзапрос, однако это также может иметь проблемы с производительностью, вам придется протестировать.

extra_stuff = Stuff.objects.filter(id__in=stuff, stuff_flag='flag')
7
Alasdair 14 Дек 2015 в 12:55

Просто сделайте 2 запроса.

total_stuff = StuffClass.objects.count()
extra_stuff = StuffClass.filter(stuff_flag=id)[:3]
extra_stuff_count = len(StuffClass.filter(stuff_flag=id))

Обратите внимание, что если extra_stuff_count имеет значение несколько, например 3 или 300. Потому что для большего количества требуется больше памяти (в этом случае просто сделайте еще один запрос).

-3
mrvol 14 Дек 2015 в 13:13

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

Поскольку вы получаете только три объекта, вы можете просто выполнить дополнительную фильтрацию в Django:

extra_stuff = [s for s in stuff if s.stuff_flag==id]

Но мне интересно, почему вы не делаете фильтр перед нарезкой.

7
Leistungsabfall 14 Дек 2015 в 12:46