@paginate
Материал из PythonWiki.
Содержание |
@paginate()
Декоратор @paginate()прозрачно для програмиста разбивает результаты запроса на подмножества для более удобного просмотра. Шаблон изпользуемый из метода декорированного paginate получает нужный кусок набора данных и переменные определяющие показываемую страницу, без необходимости методу делать что-либо кроме определения запроса SQLObject. Также существует основанный на DataGrid контрол (PaginateDataGrid) что расширяет функциональность базового DataGrid, отображая результат по страницам.
Основное использоваение
Следующий пример (и все примеры на этой странице) используют таблицу Person(Лица) с колонками name(имя) и age(возраст). Пример кода.
Ниже пример использования разбиения без контрола DataGrid:
@expose(template=".templates.paginate1") @paginate('persons') def paginate1(self): persons = Person.select() return dict(persons=persons)
SQLObject
откладывает выполнение запроса к базе данных до тех пор, пока нет обращений к результатам выборки. Вышеописанный код контролера определяет резултирующий набор (persons) но никак его не использует. Это позволяет декоратору управлять выбором строк из базы. Декоратор @paginate() просматривает возвращаемый методом словарьи находит результирующий набор persons. Декоратор изменяет объект persons так, чтобы тот выбирал ограниченное число сторок, добавляет некотрое количество дополнительных переменных в словарь и передает это все
шаблону.Ниже показан вариант шаблона для использования с этим декоратором:
<span py:for="page in tg.paginate.pages">
<a py:if="page != tg.paginate.current_page"
href="${tg.paginate.get_href(page)}">${page}</a>
<b py:if="page == tg.paginate.current_page">${page}</b>
</span>
<table border="1">
<tr>
<td>
Name
</td>
<td>
Age
</td>
</tr>
<tr py:for="person in persons">
<td>
${person.name}
</td>
<td>
${person.age}
</td>
</tr>
</table>Заметим что код использующий tg.paginate , ожидает что вы работаете с результатом SQLObject запроса. Объект tg.paginate
автоматически создан декоратором и заполнен данными для страницы. Если кликнуть на ссылках, созданных этим шаблоном вы передете на соответствующую страницу данных. Рассмотрим как выглядит URL на вашей
странице при использовании разбиения. Пример из paginate1:http://localhost:8080/paginate1?tg_paginate_limit=10&tg_paginate_no=2&tg_paginate_order=
- tg_paginate_limit говорит декоратору как много элементов отображать на странице. По умолчанию показывается 10, и вы можете позволить пользователям управлять их количеством.(По умолчанию изменение запрещено)
- tg_paginate_no номер текущей страницы. Сейчас мы смотрим вторую страницу данных.
- tg_paginate_order
используется когда декоратор сортирует результирующий набор. Мы можем использовать этот параметр, чтобы сортировать данные по различным
колонкам.
tg.paginate в деталях
Перед тем, как рассматривать декоратор @paginate() дальше, разберем подробно назначение объекте tg.paginate. Он используется для передачи информации о разбиении на страницы в шаблон. Имеет несколько аттрибутов и метод get_href, который используется для построения ссылок при разбиении на страницы. Ниже следует список его аттрибутов:
- tg.paginate.pages - список номеров страниц окружающих текущую.
- tg.paginate.current_page - хранит номер текущей страницы.
- tg.paginate.href_next - url на следующую страницу в последоватльности.
- tg.paginate.href_prev - аттрибут парный к href_next. url на предыдущую страницу в последовательности.
- tg.paginate.href_last - url на последнюю страницу.
- tg.paginate.href_first - парный к href_last url на первую страницу последовательности.
- tg.paginate.page_count - общее число страниц.
- tg.paginate.limit - количество элементов результирующего набора, показываемых на одной странице.
- tg.paginate.order - колонка по которой отсортирован результат, если используется сортировка.
- tg.paginate.reversed - булево значение установлено в False если набор отсортирован в прямом, и в True если в обратном порядке.
- tg.paginate.input_values - испульзуется системой разбиения, в основном для построения url`ов. Скорее всего, вам не придется обращатся к этому аттрибуту.
tg.paginate.get_href()
Метод tg.paginate.get_href строит url указывающий на страницу с заданным номером. Для этого он использует tg.paginate.input_values, порядок и направление сортировки поддерживаются автоматически, если вы не задаете им новое значение при вызове метода. Параметры метода:
- page (обязательный) - номер страницы, url на которую создается.
- order (опциональный, по умолчанию None) - колонка, по которой сортируется результирующий набор.
- reverse_order (опциональный, по умолчанию False) - если установлен в True, результат сортируется в обратном порядке.
@paginate() в подробностях
Декоратор @paginate просматривает результат, возвращаемый методом контролера, который он декорирует, производит некотрые изменения в SelectResult(результирующий набор, который возвращает запрос в SQLObject) или списке которые разбиваются на страницы, добавляет вспомогательную переменную (tg.paginate) и отдает измененный результат в шаблон. Используя @paginate, имейте в виду - он работает только со списками и объектом SelectResults SQLObject`а. Параметры декоратора:
- var_name (обязательный) - имя переменной в возвращаемом словаре, содержимое которой @paginate будет разбивать на страницы.
- default_order
(опциональный, по умолчанию пустая строка) - имя колонки для сортировки. Заметим, что любая сортировка результата сделанная в
декорируемом методе, будет перекрыта указанной в default_order. - limit (опциональный, по умолчанию 10) - количество элементов отображаемых на странице.
- allow_limit_override
(опциональный, по умолчанию False) - если установлен в True, то запрос с указанием отличного от значения по умолчанию количества элементов на
страницу, получит запрошенное количество. - max_pages (опциональный, по умолчанию 5, минимальное значение 3) - используется для генерации содержимого переменной tg.paginate.pages Если общее количество страниц в результате больше чем max_pages, то tg.paginate.pages будет содержать только номера страниц, окружающих текущую на 1/2 max_pages. Например, для результата в 15 страниц и текущей седьмой при max_pages установленом в 5, tg.pageinate.pages будет содержать [5,6,7,8,9]
Часть параметров в URL http-запроса влияют на поведение декоратора @paginate. Перечислим эти параметы и их эфекты:
- tg_paginate_reversed - если установлен в True, декоратор поменяет порядок сортировки по колонке указанной в параметре default_order, или в tg.paginate.order на обратный. Это не действует если default_order не указан.
c версии TurboGears 1.0.1 называется "default_reversed" - tg_paginate_order - если default_order был указан, этот параметр перекрывает значение колонки для сортировки указанной в default_order.
- tg_paginate_limit - если allow_limit_override установлено в True, это значение будет использовано вместо limit заданного в @paginate.
PaginateDataGrid
Декоратор paginate полезен сам по себе. Однако, наиболее частый случай его использования это ограничения количества показываемых данных в таблице. Мы уже имеем контрол что делает большую часть работы для этого: DataGrid. Система разбиения по страницам предоставляет расширение этого контрола, которое умеет работать с кусками данными: PaginateDataGrid. PaginateDataGrid не изменяет функциональность DataGrid, он только добавляет обработку разбиения в шаблон. Чтобы использовать PaginateDataGrid вместо обычного DataGrid вам не нужно делать изменений в вашем шаблоне или аргументах передаваемых в контрол. Просто декорируйте метод контролера.
Использование данных, не являющихся результатом SQL-запроса
Разбиение так-же может работает со списком словарей( и кортежем):
@turbogears.expose(template='.templates.paginate5') @turbogears.paginate('persons') def paginate5(self): return dict(persons=self.persons(), list=data_grid) def persons(self): data = [] for i in range(100): data.append(dict(id=i, name='name%d'%i, age=100-i)) return data
Не забудте изменить шаблон, поскольку person.name и person['name'] разные вещи(для системы шаблонов Kid)
Вот часть шаблона paginate5.kid:
<tr py:for="person in persons"><td py:content="person['name']"> person.name </td> <td py:content="person['age']"> person.age </td>
</tr>
http://docs.turbogears.org/1.0/PaginateDecorator?action=AttachFile&do=get&target=pagetest-asx.tar.gz
Включение ссылки в ячейку datagrid
Чтобы включить ссылку в ячейку datagrid, просто замените данные в виде строки на объект TreeElement.
Ниже пример использование не SQL данных и вставки ссылки:
from elementtree import ElementTree as ET # вставляет ссылку в datagrid class MakeLink: def __init__(self, baseurl, id, title, action): self.baseurl=baseurl self.id=id self.title=title self.action=action def __call__(self, obj): url=controllers.url(self.baseurl, dict(id=obj[self.id],action=self.action)) link = ET.Element('a', href=url, style='text-decoration: underline' ) link.text = obj[self.title] return link # чтобы получить ссылку вида : http://centos41-srv:8080/person?action=edit&id=6 mylink=MakeLink('person', 'id', 'name', 'edit') # просто получим элемент из словаря def get(fieldname): return lambda x: x.get(fieldname) data_grid = PaginateDataGrid( fields = [ PaginateDataGrid.Column(name='name', getter=mylink, title='Name', options=dict(sortable=True)), PaginateDataGrid.Column(name='age', getter=get('age'), title='Age', options=dict(sortable=True, reverse_order=True)), ])
контролен очень прост и использует тот-же код, что и выше:
# this is like paginate2 except it has sorting support @turbogears.expose(template='.templates.paginate2') @turbogears.paginate('persons', default_order='name') def paginate4(self): return dict(persons=self.persons(), list=data_grid)
This code can be found in .. http://docs.turbogears.org/1.0/PaginateDecorator?action=AttachFile&do=get&target=pagetest-asx.tar.gz
ЧАВО
- Почему разбиение не работает когда мой контролер возвращает строку?</dt>
- Разбиение в принципе может работать только с методом контролера возвращающим словарь.</dd>
- Могу я разбивать что-либо кроме результатов запросов SQLObject?</dt>
- В данный момент (14.09.2006) мы рассматриваем возможность изменить
декоратор, чтобы сделать возможным работу с SQLAlchemy. Смотрите за
продвижением задачи: http://trac.turbogears.org/turbogears/ticket/1115 По умолчанию можно работать и со списками, хотя сортировка будете не доступна.</dd> - Могу я переименовать параметры разбиения передаваемые через URL?</dt>
- В текущей реализации не получится.</dd>
размещено с разрешения автора перевода Олега Комкова

