Skip to content

Add docs of pagination context with context modifiers #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/recipes/forms-and-fields.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Forms and fields

We can define context for forms and fields in Python, with [context modifiers](../guides/defining-template-context.md#modifying-template-contexts-with-python).

Basic Django form definition:

```python
Expand Down
58 changes: 58 additions & 0 deletions docs/recipes/pagination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Pagination

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:

```jinja2
{% with count=search_results.paginator.count %}
{{ count }} result{{ count|pluralize }} found.
{% endwith %}

{% for result in search_results %}
<h4>{{ result.title }}</h4>
{% endfor %}

{% if search_results.paginator.num_pages > 1 %}
<nav aria-label="Pagination">
<ul>
{% if search_results.has_previous %}
<li><a href="?page={{ search_results.previous_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">previous</a></li>
{% endif %}

<li>{{ search_results.number }}/{{ search_results.paginator.num_pages }}</li>

{% if search_results.has_next %}
<li><a href="?page={{ search_results.next_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">next</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
```

We can create the needed context by using Django’s [`Paginator` API](https://docs.djangoproject.com/en/3.2/topics/pagination/).

```python
from django.core.paginator import Paginator

from pattern_library import register_context_modifier


@register_context_modifier(template='patterns/pages/search/search.html')
def replicate_pagination(context, request):
object_list = context.pop('search_results', None)
if object_list is None:
return

original_length = len(object_list)

# add dummy items to force pagination
for i in range(50):
object_list.append(None)

paginator = Paginator(object_list, original_length)
context.update(
paginator=paginator,
search_results=paginator.page(10),
is_paginated=True,
object_list=object_list
)
```
29 changes: 29 additions & 0 deletions tests/pattern_contexts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.core.paginator import Paginator

from pattern_library import register_context_modifier

from .forms import ExampleForm
Expand All @@ -12,3 +14,30 @@ def add_common_forms(context, request):
def add_field(context, request):
form = ExampleForm()
context['field'] = form['single_line_text']


@register_context_modifier(template='patterns/pages/search/search.html')
def replicate_pagination(context, request):
"""
Replace lists of items using the 'page_obj.object_list' key
with a real Paginator page, and add a few other pagination-related
things to the context (like Django's `ListView` does).
"""
object_list = context.pop('search_results', None)
if object_list is None:
return

original_length = len(object_list)

# add dummy items to force pagination
for i in range(50):
object_list.append(None)

# paginate and add ListView-like values
paginator = Paginator(object_list, original_length)
context.update(
paginator=paginator,
search_results=paginator.page(10),
is_paginated=True,
object_list=object_list
)
34 changes: 34 additions & 0 deletions tests/templates/patterns/pages/search/search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{% extends "patterns/base.html" %}

{% block content %}
<h1>{% if search_query %}Search results for “{{ search_query }}”{% else %}Search{% endif %}</h1>

{% if search_results %}
{% with count=search_results.paginator.count %}
{{ count }} result{{ count|pluralize }} found.
{% endwith %}

{% for result in search_results %}
<h4>{{ result.title }}</h4>
{% endfor %}

{% if search_results.paginator.num_pages > 1 %}
<nav aria-label="Pagination">
<ul>
{% if search_results.has_previous %}
<li><a href="#page={{ search_results.previous_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">previous</a></li>
{% endif %}

<li>{{ search_results.number }}/{{ search_results.paginator.num_pages }}</li>

{% if search_results.has_next %}
<li><a href="#page={{ search_results.next_page_number }}{% if search_query %}&amp;query={{ search_query|urlencode }}{% endif %}">next</a></li>
{% endif %}
</ul>
</nav>
{% endif %}

{% elif search_query %}
No results found.
{% endif %}
{% endblock %}
5 changes: 5 additions & 0 deletions tests/templates/patterns/pages/search/search.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
context:
search_query: test query
search_results:
- title: First result
- title: Second result