Skip to content

Commit 03b8b42

Browse files
authored
Add docs of pagination context with context modifiers (#148)
1 parent 03b62cc commit 03b8b42

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

docs/recipes/forms-and-fields.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Forms and fields
22

3+
We can define context for forms and fields in Python, with [context modifiers](../guides/defining-template-context.md#modifying-template-contexts-with-python).
4+
35
Basic Django form definition:
46

57
```python

docs/recipes/pagination.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Pagination
2+
3+
The Django paginator API is impossible to fully recreate in YAML. Instead, we can define context in Python, with [context modifiers](../guides/defining-template-context.md#modifying-template-contexts-with-python). Take a template like:
4+
5+
```jinja2
6+
{% with count=search_results.paginator.count %}
7+
{{ count }} result{{ count|pluralize }} found.
8+
{% endwith %}
9+
10+
{% for result in search_results %}
11+
<h4>{{ result.title }}</h4>
12+
{% endfor %}
13+
14+
{% if search_results.paginator.num_pages > 1 %}
15+
<nav aria-label="Pagination">
16+
<ul>
17+
{% if search_results.has_previous %}
18+
<li><a href="?page={{ search_results.previous_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">previous</a></li>
19+
{% endif %}
20+
21+
<li>{{ search_results.number }}/{{ search_results.paginator.num_pages }}</li>
22+
23+
{% if search_results.has_next %}
24+
<li><a href="?page={{ search_results.next_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">next</a></li>
25+
{% endif %}
26+
</ul>
27+
</nav>
28+
{% endif %}
29+
```
30+
31+
We can create the needed context by using Django’s [`Paginator` API](https://docs.djangoproject.com/en/3.2/topics/pagination/).
32+
33+
```python
34+
from django.core.paginator import Paginator
35+
36+
from pattern_library import register_context_modifier
37+
38+
39+
@register_context_modifier(template='patterns/pages/search/search.html')
40+
def replicate_pagination(context, request):
41+
object_list = context.pop('search_results', None)
42+
if object_list is None:
43+
return
44+
45+
original_length = len(object_list)
46+
47+
# add dummy items to force pagination
48+
for i in range(50):
49+
object_list.append(None)
50+
51+
paginator = Paginator(object_list, original_length)
52+
context.update(
53+
paginator=paginator,
54+
search_results=paginator.page(10),
55+
is_paginated=True,
56+
object_list=object_list
57+
)
58+
```

tests/pattern_contexts.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from django.core.paginator import Paginator
2+
13
from pattern_library import register_context_modifier
24

35
from .forms import ExampleForm
@@ -12,3 +14,30 @@ def add_common_forms(context, request):
1214
def add_field(context, request):
1315
form = ExampleForm()
1416
context['field'] = form['single_line_text']
17+
18+
19+
@register_context_modifier(template='patterns/pages/search/search.html')
20+
def replicate_pagination(context, request):
21+
"""
22+
Replace lists of items using the 'page_obj.object_list' key
23+
with a real Paginator page, and add a few other pagination-related
24+
things to the context (like Django's `ListView` does).
25+
"""
26+
object_list = context.pop('search_results', None)
27+
if object_list is None:
28+
return
29+
30+
original_length = len(object_list)
31+
32+
# add dummy items to force pagination
33+
for i in range(50):
34+
object_list.append(None)
35+
36+
# paginate and add ListView-like values
37+
paginator = Paginator(object_list, original_length)
38+
context.update(
39+
paginator=paginator,
40+
search_results=paginator.page(10),
41+
is_paginated=True,
42+
object_list=object_list
43+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{% extends "patterns/base.html" %}
2+
3+
{% block content %}
4+
<h1>{% if search_query %}Search results for “{{ search_query }}”{% else %}Search{% endif %}</h1>
5+
6+
{% if search_results %}
7+
{% with count=search_results.paginator.count %}
8+
{{ count }} result{{ count|pluralize }} found.
9+
{% endwith %}
10+
11+
{% for result in search_results %}
12+
<h4>{{ result.title }}</h4>
13+
{% endfor %}
14+
15+
{% if search_results.paginator.num_pages > 1 %}
16+
<nav aria-label="Pagination">
17+
<ul>
18+
{% if search_results.has_previous %}
19+
<li><a href="#page={{ search_results.previous_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">previous</a></li>
20+
{% endif %}
21+
22+
<li>{{ search_results.number }}/{{ search_results.paginator.num_pages }}</li>
23+
24+
{% if search_results.has_next %}
25+
<li><a href="#page={{ search_results.next_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">next</a></li>
26+
{% endif %}
27+
</ul>
28+
</nav>
29+
{% endif %}
30+
31+
{% elif search_query %}
32+
No results found.
33+
{% endif %}
34+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
context:
2+
search_query: test query
3+
search_results:
4+
- title: First result
5+
- title: Second result

0 commit comments

Comments
 (0)