From 4e1a63e42d562b450d3f5c9fb4169defb6b51274 Mon Sep 17 00:00:00 2001 From: antoliny0919 Date: Mon, 2 Jun 2025 17:23:51 +0900 Subject: [PATCH] Updated new pagination feature. --- .../tests/migrations => base}/__init__.py | 0 base/exceptions.py | 6 ++ base/migrations/__init__.py | 0 base/pagination.py | 58 ++++++++++ base/templatetags/__init__.py | 0 base/templatetags/base_templatetags.py | 69 ++++++++++++ base/templatetags/components.py | 40 +++++++ base/tests/__init__.py | 0 .../tests/fixtures/ratings_testdata.json | 0 .../tests/migrations/0001_initial.py | 0 base/tests/migrations/0002_fish.py | 21 ++++ base/tests/migrations/__init__.py | 0 {ratings => base}/tests/models.py | 7 +- base/tests/tests.py | 60 +++++++++++ cab/utils.py | 100 ++++-------------- djangosnippets/settings/base.py | 1 + djangosnippets/settings/testing.py | 3 +- djangosnippets/static/scss/main.scss | 61 ++++++++++- djangosnippets/templates/base.html | 10 +- .../templates/base/components/pagination.html | 21 ++++ .../templates/cab/language_list.html | 4 +- .../templates/cab/partials/language_list.html | 5 +- .../cab/partials/most_bookmarked.html | 12 +-- .../templates/cab/partials/tag_list.html | 4 +- .../templates/cab/partials/top_rated.html | 12 +-- .../templates/cab/snippet_list.html | 12 +-- djangosnippets/templates/cab/tag_list.html | 4 +- .../templates/cab/user_bookmarks.html | 4 +- djangosnippets/templates/cab/user_detail.html | 12 +-- djangosnippets/templates/search/search.html | 4 +- ratings/tests/tests.py | 3 +- 31 files changed, 392 insertions(+), 141 deletions(-) rename {ratings/tests/migrations => base}/__init__.py (100%) create mode 100644 base/exceptions.py create mode 100644 base/migrations/__init__.py create mode 100644 base/pagination.py create mode 100644 base/templatetags/__init__.py create mode 100644 base/templatetags/base_templatetags.py create mode 100644 base/templatetags/components.py create mode 100644 base/tests/__init__.py rename {ratings => base}/tests/fixtures/ratings_testdata.json (100%) rename {ratings => base}/tests/migrations/0001_initial.py (100%) create mode 100644 base/tests/migrations/0002_fish.py create mode 100644 base/tests/migrations/__init__.py rename {ratings => base}/tests/models.py (74%) create mode 100644 base/tests/tests.py create mode 100644 djangosnippets/templates/base/components/pagination.html diff --git a/ratings/tests/migrations/__init__.py b/base/__init__.py similarity index 100% rename from ratings/tests/migrations/__init__.py rename to base/__init__.py diff --git a/base/exceptions.py b/base/exceptions.py new file mode 100644 index 00000000..e13df8f9 --- /dev/null +++ b/base/exceptions.py @@ -0,0 +1,6 @@ +class IncorectLookupParameter(Exception): + """ + Raised when a query parameter contains an incorrect value. + """ + + pass diff --git a/base/migrations/__init__.py b/base/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/base/pagination.py b/base/pagination.py new file mode 100644 index 00000000..d85e83af --- /dev/null +++ b/base/pagination.py @@ -0,0 +1,58 @@ +from django.core.paginator import InvalidPage, Paginator + +from .exceptions import IncorectLookupParameter + +PAGE_VAR = "page" + + +class Pagination: + def __init__( + self, + request, + model, + queryset, + list_per_page, + ): + self.model = model + self.opts = model._meta + self.queryset = queryset + self.list_per_page = list_per_page + try: + # Get the current page from the query string. + self.page_num = int(request.GET.get(PAGE_VAR, 1)) + except ValueError: + self.page_num = 1 + self.params = dict(request.GET.lists()) + self.setup() + + @property + def page_range(self): + """ + Returns the full range of pages. + """ + return ( + self.paginator.get_elided_page_range(self.page_num) + if self.multi_page + else [] + ) + + def setup(self): + paginator = Paginator(self.queryset, self.list_per_page) + result_count = paginator.count + # Determine use pagination. + multi_page = result_count > self.list_per_page + + self.result_count = result_count + self.multi_page = multi_page + self.paginator = paginator + self.page = paginator.get_page(self.page_num) + + def get_objects(self): + if not self.multi_page: + result_list = self.queryset._clone() + else: + try: + result_list = self.paginator.page(self.page_num).object_list + except InvalidPage: + raise IncorectLookupParameter + return result_list diff --git a/base/templatetags/__init__.py b/base/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/base/templatetags/base_templatetags.py b/base/templatetags/base_templatetags.py new file mode 100644 index 00000000..8cfb0c84 --- /dev/null +++ b/base/templatetags/base_templatetags.py @@ -0,0 +1,69 @@ +from collections.abc import Iterable, Mapping + +from django import template +from django.http import QueryDict +from django.template.exceptions import TemplateSyntaxError + +register = template.Library() + + +# This template tag is scheduled to be added in Django 6.0. +# Imported for use before the release of Django 6.0. +@register.simple_tag(name="querystring", takes_context=True) +def querystring(context, *args, **kwargs): + """ + Build a query string using `args` and `kwargs` arguments. + + This tag constructs a new query string by adding, removing, or modifying + parameters from the given positional and keyword arguments. Positional + arguments must be mappings (such as `QueryDict` or `dict`), and + `request.GET` is used as the starting point if `args` is empty. + + Keyword arguments are treated as an extra, final mapping. These mappings + are processed sequentially, with later arguments taking precedence. + + A query string prefixed with `?` is returned. + + Raise TemplateSyntaxError if a positional argument is not a mapping or if + keys are not strings. + + For example:: + + {# Set a parameter on top of `request.GET` #} + {% querystring foo=3 %} + + {# Remove a key from `request.GET` #} + {% querystring foo=None %} + + {# Use with pagination #} + {% querystring page=page_obj.next_page_number %} + + {# Use a custom ``QueryDict`` #} + {% querystring my_query_dict foo=3 %} + + {# Use multiple positional and keyword arguments #} + {% querystring my_query_dict my_dict foo=3 bar=None %} + """ + if not args: + args = [context.request.GET] + params = QueryDict(mutable=True) + for d in [*args, kwargs]: + if not isinstance(d, Mapping): + raise TemplateSyntaxError( + "querystring requires mappings for positional arguments (got " + "%r instead)." % d + ) + for key, value in d.items(): + if not isinstance(key, str): + raise TemplateSyntaxError( + "querystring requires strings for mapping keys (got %r " + "instead)." % key + ) + if value is None: + params.pop(key, None) + elif isinstance(value, Iterable) and not isinstance(value, str): + params.setlist(key, value) + else: + params[key] = value + query_string = params.urlencode() if params else "" + return f"?{query_string}" diff --git a/base/templatetags/components.py b/base/templatetags/components.py new file mode 100644 index 00000000..a271b7d0 --- /dev/null +++ b/base/templatetags/components.py @@ -0,0 +1,40 @@ +from django import template +from django.utils.html import format_html +from django.utils.safestring import mark_safe + +from base.pagination import PAGE_VAR + +from .base_templatetags import querystring + +register = template.Library() + + +@register.simple_tag +def pagination_number(pagination, i): + """ + Generate an individual page index link in a paginated list. + """ + if i == pagination.paginator.ELLIPSIS: + return format_html("{} ", pagination.paginator.ELLIPSIS) + elif i == pagination.page_num: + return format_html('{} ', i) + else: + link = querystring(None, pagination.params, {PAGE_VAR: i}) + return format_html( + '{} ', + link, + i, + mark_safe(' class="end"' if i == pagination.paginator.num_pages else ""), + i, + ) + + +@register.inclusion_tag("base/components/pagination.html", name="pagination") +def pagination_tag(pagination): + previous_page_link = f"?{PAGE_VAR}={pagination.page_num - 1}" + next_page_link = f"?{PAGE_VAR}={pagination.page_num + 1}" + return { + "pagination": pagination, + "previous_page_link": previous_page_link, + "next_page_link": next_page_link, + } diff --git a/base/tests/__init__.py b/base/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ratings/tests/fixtures/ratings_testdata.json b/base/tests/fixtures/ratings_testdata.json similarity index 100% rename from ratings/tests/fixtures/ratings_testdata.json rename to base/tests/fixtures/ratings_testdata.json diff --git a/ratings/tests/migrations/0001_initial.py b/base/tests/migrations/0001_initial.py similarity index 100% rename from ratings/tests/migrations/0001_initial.py rename to base/tests/migrations/0001_initial.py diff --git a/base/tests/migrations/0002_fish.py b/base/tests/migrations/0002_fish.py new file mode 100644 index 00000000..b312f3d2 --- /dev/null +++ b/base/tests/migrations/0002_fish.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.15 on 2025-06-04 05:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tests', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Fish', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('price', models.IntegerField()), + ], + ), + ] diff --git a/base/tests/migrations/__init__.py b/base/tests/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ratings/tests/models.py b/base/tests/models.py similarity index 74% rename from ratings/tests/models.py rename to base/tests/models.py index 45b56d22..00d5dc0d 100644 --- a/ratings/tests/models.py +++ b/base/tests/models.py @@ -1,6 +1,11 @@ from django.db import models -from ..models import RatedItemBase, Ratings +from ratings.models import RatedItemBase, Ratings + + +class Fish(models.Model): + name = models.CharField(max_length=255) + price = models.IntegerField() class Food(models.Model): diff --git a/base/tests/tests.py b/base/tests/tests.py new file mode 100644 index 00000000..6df8b699 --- /dev/null +++ b/base/tests/tests.py @@ -0,0 +1,60 @@ +from django.test import RequestFactory, TestCase + +from base.pagination import Pagination + +from .models import Fish + + +class PaginationTestCase(TestCase): + @classmethod + def setUpTestData(cls): + fishs = [Fish(name=f"fish-{i}", price=i * 100) for i in range(1, 101)] + Fish.objects.bulk_create(fishs) + cls.queryset = Fish.objects.all() + cls.factory = RequestFactory() + + def test_pagination_attributes(self): + request = self.factory.get("/fake-url/") + pagination = Pagination(request, Fish, self.queryset, 5) + self.assertEqual(pagination.result_count, 100) + self.assertTrue(pagination.multi_page) + pagination = Pagination(request, Fish, self.queryset, 200) + self.assertFalse(pagination.multi_page) + + def test_pagination_page_range(self): + request = self.factory.get("/fake-url/") + ELLIPSIS = "…" + case = [ + (2, 6, [1, 2, 3, 4, 5, 6, 7, 8, 9, ELLIPSIS, 49, 50]), + (3, 10, [1, 2, ELLIPSIS, 7, 8, 9, 10, 11, 12, 13, ELLIPSIS, 33, 34]), + (4, 23, [1, 2, ELLIPSIS, 20, 21, 22, 23, 24, 25]), + (5, 20, [1, 2, ELLIPSIS, 17, 18, 19, 20]), + (10, 8, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + (20, 1, [1, 2, 3, 4, 5]), + ] + for list_per_page, current_page, expected_page_range in case: + with self.subTest(list_per_page=list_per_page, current_page=current_page): + pagination = Pagination(request, Fish, self.queryset, list_per_page) + pagination.page_num = current_page + self.assertEqual(list(pagination.page_range), expected_page_range) + + def test_pagination_result_objects(self): + request = self.factory.get("/fake-url/") + case = [ + (2, 25, ["49", "50"]), + (4, 12, ["45", "46", "47", "48"]), + (5, 10, ["46", "47", "48", "49", "50"]), + (7, 11, ["71", "72", "73", "74", "75", "76", "77"]), + (10, 10, ["91", "92", "93", "94", "95", "96", "97", "98", "99", "100"]), + (200, 1, [str(i) for i in range(1, 101)]), + ] + Fish.objects.all().delete() + fishs = [Fish(name=i, price=i * 100) for i in range(1, 101)] + Fish.objects.bulk_create(fishs) + queryset = Fish.objects.all().order_by("id") + for list_per_page, current_page, expect_object_names in case: + pagination = Pagination(request, Fish, queryset, list_per_page) + pagination.page_num = current_page + objects = pagination.get_objects() + object_names = list(objects.values_list("name", flat=True)) + self.assertEqual(object_names, expect_object_names) diff --git a/cab/utils.py b/cab/utils.py index f91215ed..1cd8de11 100644 --- a/cab/utils.py +++ b/cab/utils.py @@ -2,18 +2,18 @@ import bleach from django.core.exceptions import ObjectDoesNotExist -from django.core.paginator import InvalidPage, Paginator from django.http import Http404, HttpResponse from django.template import loader from django.utils.safestring import mark_safe from markdown import markdown as markdown_func +from base.pagination import Pagination + def object_list( request, queryset, paginate_by=None, - page=None, allow_empty=True, template_name=None, template_loader=loader, @@ -28,101 +28,43 @@ def object_list( Context: object_list list of objects - is_paginated - are the results paginated? - results_per_page - number of objects per page (if paginated) - has_next - is there a next page? - has_previous - is there a prev page? - page - the current page - next - the next page - previous - the previous page - pages - number of pages, total + pagination + This is a pagination object that holds attributes + related to pagination. + For more detail, please refer to the `base.pagination.Pagination` class. hits number of objects, total - last_on_page - the result number of the last of object in the - object_list (1-indexed) - first_on_page - the result number of the first object in the - object_list (1-indexed) - page_range: - A list of the page numbers (1-indexed). """ if extra_context is None: extra_context = {} queryset = queryset._clone() + model = queryset.model + opts = model._meta if paginate_by: - paginator = Paginator(queryset, paginate_by, allow_empty_first_page=allow_empty) - if not page: - page = request.GET.get("page", 1) + pagination = Pagination(request, model, queryset, paginate_by) + object_list = pagination.get_objects() - if page == "last": - page_number = paginator.num_pages - else: - try: - page_number = int(page) - except ValueError: - # Page is not 'last', nor can it be converted to an int. - raise Http404 - try: - page_obj = paginator.page(page_number) - except InvalidPage: - raise Http404 - try: - next_page = page_obj.next_page_number() - except InvalidPage: - next_page = None - try: - previous_page = page_obj.previous_page_number() - except InvalidPage: - previous_page = None - - c = { - "%s_list" % template_object_name: page_obj.object_list, - "paginator": paginator, - "page_obj": page_obj, - "is_paginated": page_obj.has_other_pages(), - # Legacy template context stuff. New templates should use page_obj - # to access this instead. - "results_per_page": paginator.per_page, - "has_next": page_obj.has_next(), - "has_previous": page_obj.has_previous(), - "page": page_obj.number, - "next": next_page, - "previous": previous_page, - "first_on_page": page_obj.start_index(), - "last_on_page": page_obj.end_index(), - "pages": paginator.num_pages, - "hits": paginator.count, - "page_range": paginator.page_range, + context = { + "%s_list" % template_object_name: object_list, + "pagination": pagination, + "hits": pagination.result_count, } else: - c = { - "%s_list" % template_object_name: queryset, - "paginator": None, - "page_obj": None, - "is_paginated": False, + context = { + "%s_list" % template_object_name: object_list, } if not allow_empty and len(queryset) == 0: raise Http404 for key, value in extra_context.items(): if callable(value): - c[key] = value() + context[key] = value() else: - c[key] = value + context[key] = value if not template_name: - model = queryset.model - template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower()) - t = template_loader.get_template(template_name) - return HttpResponse(t.render(c, request=request), content_type=content_type) + template_name = "%s/%s_list.html" % (opts.app_label, opts.object_name.lower()) + template = template_loader.get_template(template_name) + return HttpResponse(template.render(context, request=request), content_type=content_type) def object_detail( diff --git a/djangosnippets/settings/base.py b/djangosnippets/settings/base.py index b45e644c..3e2be225 100644 --- a/djangosnippets/settings/base.py +++ b/djangosnippets/settings/base.py @@ -56,6 +56,7 @@ def user_url(user): "allauth.socialaccount.providers.bitbucket", "allauth.socialaccount.providers.github", "allauth.socialaccount.providers.twitter", + "base", "cab", "comments_spamfighter", "ratings", diff --git a/djangosnippets/settings/testing.py b/djangosnippets/settings/testing.py index 2b50b697..7c827369 100644 --- a/djangosnippets/settings/testing.py +++ b/djangosnippets/settings/testing.py @@ -27,11 +27,12 @@ "allauth.socialaccount.providers.bitbucket", "allauth.socialaccount.providers.github", "allauth.socialaccount.providers.twitter", + "base", + "base.tests", "comments_spamfighter", "cab", "ratings", "taggit", - "ratings.tests", "rest_framework", ) diff --git a/djangosnippets/static/scss/main.scss b/djangosnippets/static/scss/main.scss index 843db1e6..7a50c1ed 100644 --- a/djangosnippets/static/scss/main.scss +++ b/djangosnippets/static/scss/main.scss @@ -317,7 +317,7 @@ body.with-sidebar { @include grid-column(4); } } - .pagination, .count { + .count { text-align: center; } } @@ -358,6 +358,65 @@ body.simple { } } +nav.pagination { + display: flex; + justify-content: center; + text-align: center; + ul { + margin-left: 1rem; + margin-right: 1rem; + } + + li { + display: inline-block; + a, em, span { + padding: 5px 10px; + line-height: 20px; + border: 1px solid transparent; + border-radius: 6px; + transition: border-color .2s cubic-bezier(0.3, 0, 0.5, 1); + cursor: pointer; + } + a:hover { + border-color: $secondary-color; + text-decoration: none; + } + em { + font-style: normal; + cursor: default; + } + .current-page { + font-weight: bold; + color: white; + background-color: $secondary-color; + } + .disabled { + color: gray; + cursor: default; + border-color: transparent; + } + } + + .previous-page::before, .next-page::after { + display: inline-block; + width: 1rem; + height: 1rem; + vertical-align: text-bottom; + content: ""; + background-color: currentColor; + } + + .previous-page::before { + clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px); + margin-right: 4px; + } + + .next-page::after { + clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px); + margin-left: 4px; + } +} + footer { padding: 30px 0 30px 0; clear: both; diff --git a/djangosnippets/templates/base.html b/djangosnippets/templates/base.html index b02598f7..153a6562 100644 --- a/djangosnippets/templates/base.html +++ b/djangosnippets/templates/base.html @@ -39,11 +39,11 @@ {% block secondary_nav %} {% endblock %} diff --git a/djangosnippets/templates/base/components/pagination.html b/djangosnippets/templates/base/components/pagination.html new file mode 100644 index 00000000..aeeadbdf --- /dev/null +++ b/djangosnippets/templates/base/components/pagination.html @@ -0,0 +1,21 @@ +{% load components %} + +{% if pagination.multi_page %} + +{% endif %} diff --git a/djangosnippets/templates/cab/language_list.html b/djangosnippets/templates/cab/language_list.html index f6df2df3..949b5e2b 100644 --- a/djangosnippets/templates/cab/language_list.html +++ b/djangosnippets/templates/cab/language_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags %} +{% load core_tags components %} {% block head_title %}All languages{% endblock %} @@ -12,6 +12,6 @@ {% endfor %} -

{% if has_previous %}< Previous {{ results_per_page }}{% endif %}  {% if has_next %}Next {{ results_per_page }} >{% endif %}

+ {% pagination pagination %} {% endblock %} diff --git a/djangosnippets/templates/cab/partials/language_list.html b/djangosnippets/templates/cab/partials/language_list.html index 697a270c..d2e14142 100644 --- a/djangosnippets/templates/cab/partials/language_list.html +++ b/djangosnippets/templates/cab/partials/language_list.html @@ -1,4 +1,4 @@ -{% load static %} +{% load static components %} @@ -10,6 +10,5 @@

All languages

{% endfor %} -

{% if has_previous %}< Previous {{ results_per_page }}{% endif %}  {% if has_next %}Next {{ results_per_page }} >{% endif %}

- + {% pagination pagination %} diff --git a/djangosnippets/templates/cab/partials/most_bookmarked.html b/djangosnippets/templates/cab/partials/most_bookmarked.html index fd5031ed..b3ebae58 100644 --- a/djangosnippets/templates/cab/partials/most_bookmarked.html +++ b/djangosnippets/templates/cab/partials/most_bookmarked.html @@ -1,5 +1,5 @@ -{% load core_tags %} +{% load core_tags components %} {% load static %}

Most bookmarked snippets{% if months %} last {{ months }} months{% endif %}

@@ -30,15 +30,7 @@

Most bookmarked snippets{% if months %} last {{ months }} months{% endif %}< {% endfor %} -

- {% if has_previous %} - < Previous {{ results_per_page }} - {% endif %} -    - {% if has_next %} - Next {{ results_per_page }} > - {% endif %} -

+ {% pagination pagination %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/partials/tag_list.html b/djangosnippets/templates/cab/partials/tag_list.html index 51b725d1..9c5b083e 100644 --- a/djangosnippets/templates/cab/partials/tag_list.html +++ b/djangosnippets/templates/cab/partials/tag_list.html @@ -1,5 +1,5 @@ -{% load core_tags %} +{% load core_tags components %}

All tags

{% if object_list %} @@ -9,7 +9,7 @@

All tags

{% endfor %} -

{% if has_previous %}< Previous {{ results_per_page }}{% endif %}  {% if has_next %}Next {{ results_per_page }} >{% endif %}

+ {% pagination pagination %} {% else %}

No tags have been used yet.

{% endif %} diff --git a/djangosnippets/templates/cab/partials/top_rated.html b/djangosnippets/templates/cab/partials/top_rated.html index 78286707..0a48a82b 100644 --- a/djangosnippets/templates/cab/partials/top_rated.html +++ b/djangosnippets/templates/cab/partials/top_rated.html @@ -1,6 +1,6 @@ {% load static %} -{% load core_tags %} +{% load core_tags components %}

Top-rated snippets{% if months %} last {{ months }} months{% endif %}

@@ -28,15 +28,7 @@

Top-rated snippets{% if months %} last {{ months }} months{% endif %}

{% endfor %} -

- {% if has_previous %} - < Previous {{ results_per_page }} - {% endif %} -    - {% if has_next %} - Next {{ results_per_page }} > - {% endif %} -

+ {% pagination pagination %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/snippet_list.html b/djangosnippets/templates/cab/snippet_list.html index 2979553c..5fceeb60 100644 --- a/djangosnippets/templates/cab/snippet_list.html +++ b/djangosnippets/templates/cab/snippet_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags %} +{% load core_tags components %} {% load static %} {% block bodyclass %}snippet-list{% endblock %} {% block head_title %}All snippets{% if months %} last {{ months }} months{% endif %}{% endblock %} @@ -30,15 +30,7 @@ {% endfor %} -

- {% if has_previous %} - < Previous {{ results_per_page }} - {% endif %} -    - {% if has_next %} - Next {{ results_per_page }} > - {% endif %} -

+ {% pagination pagination %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/tag_list.html b/djangosnippets/templates/cab/tag_list.html index 4e89f3e9..77114235 100644 --- a/djangosnippets/templates/cab/tag_list.html +++ b/djangosnippets/templates/cab/tag_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags %} +{% load core_tags components %} {% block head_title %}All tags{% endblock %} {% block bodyclass %}tags-list{% endblock %} @@ -14,7 +14,7 @@ {% endfor %} -

{% if has_previous %}< Previous {{ results_per_page }}{% endif %}  {% if has_next %}Next {{ results_per_page }} >{% endif %}

+ {% pagination pagination %} {% else %}

No tags have been used yet.

{% endif %} diff --git a/djangosnippets/templates/cab/user_bookmarks.html b/djangosnippets/templates/cab/user_bookmarks.html index 3acdbb35..69be39c0 100644 --- a/djangosnippets/templates/cab/user_bookmarks.html +++ b/djangosnippets/templates/cab/user_bookmarks.html @@ -1,5 +1,5 @@ {% extends "base_user.html" %} -{% load core_tags %} +{% load core_tags components %} {% block bodyclass %}bookmarks{% endblock %} {% block head_title %}Your bookmarks{% endblock %} @@ -29,7 +29,7 @@ -

{% if has_previous %}Previous {{ results_per_page }}{% endif %}  {% if has_next %}Next {{ results_per_page }} >{% endif %} + {% pagination pagination %} {% else %}

You haven't bookmarked any snippets yet.

{% endif %} diff --git a/djangosnippets/templates/cab/user_detail.html b/djangosnippets/templates/cab/user_detail.html index fd89a959..42915ebb 100644 --- a/djangosnippets/templates/cab/user_detail.html +++ b/djangosnippets/templates/cab/user_detail.html @@ -1,5 +1,5 @@ {% extends "base_user.html" %} -{% load cache core_tags %} +{% load cache core_tags components %} {% block bodyclass %}user{% endblock %} {% load static %} @@ -35,15 +35,7 @@ {% cache 600 author_detail_sidebar author.username %}

{% if request.user.username == author.username %}You've{% else %}{{ author.username }} has{% endif %} posted {{ author.snippet_set.count }} snippet{{ author.snippet_set.count|pluralize }}.

{% endcache %} -

- {% if has_previous %} - < Previous {{ results_per_page }} - {% endif %} -    - {% if has_next %} - Next {{ results_per_page }} > - {% endif %} -

+ {% pagination pagination %} {% else %}

No snippets posted yet.

{% endif %} diff --git a/djangosnippets/templates/search/search.html b/djangosnippets/templates/search/search.html index fc356ae2..10477594 100644 --- a/djangosnippets/templates/search/search.html +++ b/djangosnippets/templates/search/search.html @@ -9,7 +9,7 @@ {% block content %} {% if form.q.value or form.version.value or form.language.value %} - {% if page_obj.object_list %} + {% if object_list %} @@ -21,7 +21,7 @@ - {% for result in page_obj.object_list %} + {% for result in object_list %} diff --git a/ratings/tests/tests.py b/ratings/tests/tests.py index 9fad7230..aaa7527b 100644 --- a/ratings/tests/tests.py +++ b/ratings/tests/tests.py @@ -7,10 +7,11 @@ from django.test.utils import override_settings from django.urls import reverse +from base.tests.models import Beverage, BeverageRating, Food + from .. import utils as ratings_utils from .. import views as ratings_views from ..models import RatedItem -from ..tests.models import Beverage, BeverageRating, Food from ..utils import ( calculate_similar_items, recommendations,
{% if not result.title|strip %}Untitled{% else %}{{ result.title }}{% endif %} {% user_display result.author %}