При создании шаблонного тега часто бывает нужно что-то в него передать из контекста самого шаблона, например объект request, или какую-нибудь коллекцию с которой что-нибудь нужно сделать.
Для примера реализуем тег
pagination который будет получать какой-то список объектов и отдавать объект
Paginator. Ситнаксис тэга будет такой:
{% pagination objects as pagination_objects %}.
Итак код:
def do_pagination(parser, token):
bits = token.split_contents()
if len(bits) != 5:
raise TemplateSyntaxError('%r syntax is %s obj_list num as varname ' % (bits[0], bits[0]))
if bits[3] != 'as':
raise TemplateSyntaxError('%r required "as" beetwen arguments' % bits[0])
obj_list = parser.compile_filter(bits[1])
page_size = bits[2]
return_name = bits[-1]
return PaginationNode(obj_list, return_name, page_size)
Разберем по порядку:
- Метод do_pagination разбирает строку тэга, делает необходимые проверки и возвращает экземпляр класса PaginationNode
- bits - здесь содержится массив разобранной строки.
- if len(bits) != 5: ... тут идут проверки синтаксиса шаблона
- obj_list = parser.compile_filter(bits[1]) - вот здесь важный момент, в obj_list получаем переменную типа template.Variable при помощи метода compile_filter(), она нужна только затем чтобы потом вызвать у неё метод resolve(context) и получить саму переменную из контекста шаблона, об этом далее
Теперь реализуем класс
PaginationNode который будет создавать в контексте шаблона столь необходимый пэйджинг.
class PaginationNode(template.Node):
def __init__(self, obj_list, return_name, page_size):
self.obj_list = obj_list
self.return_name = return_name
self.page_size = page_size
def render(self, context):
actual_obj_list = self.obj_list.resolve(context)
context[self.return_name] = Paginator(actual_obj_list, int(self.page_size))
return ''
- actual_obj_list = self.obj_list.resolve(context) - вот здесь второй важный момент, actual_obj_list после вызова метода resolve(context) содержит в себе настоящий список объектов с которым мы можем творить чо хотим.
- context[self.return_name] = Paginator(actual_obj_list, int(self.page_size)) - вот тут собственно мы и творим то что хотели, т.е. создаём объект пэйджинга и записываем его в контекст шаблона