Как выполнить фильтрацию запросов в шаблонах django
Мне нужно выполнить отфильтрованный запрос из шаблона django, чтобы получить набор объектов, эквивалентный коду питона в представлении:
queryset = Modelclass.objects.filter(somekey=foo)
В моем шаблоне я хотел бы сделать
{% for object in data.somekey_set.FILTER %}
но я просто не могу понять, как писать FILTER.
Ответы
Ответ 1
Вы не можете сделать это, это по дизайну. Авторы проекта Django предполагали строгое разделение кода представления от логики данных. Фильтрация моделей - логика данных, а вывод HTML - логика представления.
Итак, у вас есть несколько вариантов. Проще всего сделать фильтрацию, а затем передать результат на render_to_response
. Или вы можете написать метод в своей модели, чтобы вы могли сказать {% for object in data.filtered_set %}
. Наконец, вы можете написать свой собственный тег шаблона, хотя в этом конкретном случае я бы посоветовал это.
Ответ 2
Я просто добавляю дополнительный тег шаблона, например:
@register.filter
def in_category(things, category):
return things.filter(category=category)
Тогда я могу сделать:
{% for category in categories %}
{% for thing in things|in_category:category %}
{{ thing }}
{% endfor %}
{% endfor %}
Ответ 3
Я регулярно сталкиваюсь с этой проблемой и часто использую решение "добавить метод". Однако есть определенные случаи, когда "добавить метод" или "вычислить его в представлении" не работают (или не работают хорошо). Например. когда вы кешируете фрагменты шаблона и нуждаетесь в некотором нетривиальном вычислении БД для его создания. Вы не хотите выполнять работу с БД, если вам это не нужно, но вы не будете знать, нужно ли вам, пока вы не будете глубоко в логике шаблонов.
Некоторые другие возможные решения:
-
Используйте тег {% expr < выражение > как < var_name > %}, найденный в http://www.djangosnippets.org/snippets/9/ Выражение является любым законным выражением Python с вашим шаблоном Context как вашей локальной областью.
-
Измените шаблонный процессор. Jinja2 (http://jinja.pocoo.org/2/) имеет синтаксис, который почти идентичен языку шаблонов Django, но с полной доступностью Python. Это также быстрее. Вы можете сделать это оптом или ограничить его использование шаблонами, над которыми вы работаете, но использовать "безопасные" шаблоны Django для страниц, поддерживаемых разработчиками.
Ответ 4
Это можно решить с помощью тэга присваивания:
from django import template
register = template.Library()
@register.assignment_tag
def query(qs, **kwargs):
""" template tag which allows queryset filtering. Usage:
{% query books author=author as mybooks %}
{% for book in mybooks %}
...
{% endfor %}
"""
return qs.filter(**kwargs)
Ответ 5
Другой вариант заключается в том, что если у вас есть фильтр, который вы всегда хотите применить, добавьте пользовательский менеджер в рассматриваемую модель, которая всегда применяет фильтр к результаты возвращены.
Хорошим примером этого является модель Event
, где для 90% запросов, которые вы делаете на модели, вам нужно что-то вроде Event.objects.filter(date__gte=now)
, то есть вас обычно интересует Events
, которые предстоящий. Это будет выглядеть так:
class EventManager(models.Manager):
def get_query_set(self):
now = datetime.now()
return super(EventManager,self).get_query_set().filter(date__gte=now)
И в модели:
class Event(models.Model):
...
objects = EventManager()
Но опять же, это относится к одному и тому же фильтру против всех запросов по умолчанию, выполненных в модели Event
, и поэтому не так гибко некоторые из описанных выше методов.