made it compatible with the old ordering template and added rendering tests for them

This commit is contained in:
Gassan Gousseinov 2021-03-15 23:46:11 +01:00
parent 226deb5707
commit 2883a0256a
4 changed files with 108 additions and 45 deletions

View File

@ -275,33 +275,39 @@ class OrderingFilter(BaseFilterBackend):
return queryset return queryset
def get_template_context(self, request, queryset, view): def get_template_context(self, request, queryset, view):
current = self.get_ordering(request, queryset, view) # current and options should be deleted with the next major update
if not current: currents = self.get_ordering(request, queryset, view)
current = None current = None if not currents else currents[0]
options = [] options = []
options_plus = []
context = { context = {
'request': request, 'request': request,
'current': current, 'current': current,
'currents': currents,
'param': self.ordering_param, 'param': self.ordering_param,
} }
for key, label in self.get_valid_fields(queryset, view, context): for key, label in self.get_valid_fields(queryset, view, context):
options.append((key, '%s - %s' % (label, _('ascending')), *self.plus_key(current, key))) for sign, order_label in [('', _('ascending')), ('-', _('descending'))]:
options.append(('-' + key, '%s - %s' % (label, _('descending')), *self.plus_key(current, '-' + key))) item = (sign + key, '%s - %s' % (label, order_label))
options.append(item)
options_plus.append(item + self.plus_key(currents, sign + key))
context['options'] = options context['options'] = options
context['options_plus'] = options_plus
return context return context
@staticmethod @staticmethod
def plus_key(current, key): def plus_key(currents, key):
priority = None priority = None
plus_key = None plus_key = None
if current: if currents:
if len(current) > 1: if len(currents) > 1:
try: try:
priority = current.index(key) + 1 priority = currents.index(key) + 1
except ValueError: except ValueError:
pass pass
for_plus = current.copy() for_plus = currents.copy()
if key in for_plus: if key in for_plus:
# for click on minus # for click on minus
for_plus.remove(key) for_plus.remove(key)

View File

@ -87,4 +87,4 @@ pre {
#filtersModal .list-group-item:hover .glyphicon-plus[data-plus-ordering] { #filtersModal .list-group-item:hover .glyphicon-plus[data-plus-ordering] {
visibility: visible; visibility: visible;
} }

View File

@ -2,8 +2,8 @@
{% load i18n %} {% load i18n %}
<h2>{% trans "Ordering" %}</h2> <h2>{% trans "Ordering" %}</h2>
<div class="list-group"> <div class="list-group">
{% for key, label, priority, plus_key in options %} {% for key, label, priority, plus_key in options_plus %}
{% if key in current %} {% if key in currents %}
<a href="{% add_query_param request param key %}" class="list-group-item active"> <a href="{% add_query_param request param key %}" class="list-group-item active">
<span class="glyphicon glyphicon-minus" style="float: right" aria-hidden="true" <span class="glyphicon glyphicon-minus" style="float: right" aria-hidden="true"
data-plus-ordering="{% if plus_key %}{% add_query_param request param plus_key %}{% else %}{% remove_query_param request param %}{% endif %}"></span> data-plus-ordering="{% if plus_key %}{% add_query_param request param plus_key %}{% else %}{% remove_query_param request param %}{% endif %}"></span>
@ -14,7 +14,7 @@
</a> </a>
{% else %} {% else %}
<a href="{% add_query_param request param key %}" class="list-group-item"> <a href="{% add_query_param request param key %}" class="list-group-item">
{% if current %} {% if currents %}
<span class="glyphicon glyphicon-plus" style="float: right" aria-hidden="true" <span class="glyphicon glyphicon-plus" style="float: right" aria-hidden="true"
data-plus-ordering="{% add_query_param request param plus_key %}"></span> data-plus-ordering="{% add_query_param request param plus_key %}"></span>
{% endif %} {% endif %}

View File

@ -6,12 +6,15 @@ from django.core.exceptions import ImproperlyConfigured
from django.db import models from django.db import models
from django.db.models import CharField, Transform from django.db.models import CharField, Transform
from django.db.models.functions import Concat, Upper from django.db.models.functions import Concat, Upper
from django.template import Context, Template
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from rest_framework import filters, generics, serializers from rest_framework import filters, generics, serializers
from rest_framework.compat import coreschema from rest_framework.compat import coreschema
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.viewsets import ViewSet
factory = APIRequestFactory() factory = APIRequestFactory()
@ -712,43 +715,97 @@ class OrderingFilterTests(TestCase):
view(request) view(request)
class OrderingViewSet(ViewSet):
ordering_fields = [
('id', 'ID'),
('slug', 'Slug'),
('author', 'Author'),
]
oldOrderingTemplate = Template("""
{% load rest_framework %}
{% load i18n %}
<h2>{% trans "Ordering" %}</h2>
<div class="list-group">
{% for key, label in options %}
{% if key == current %}
<a href="{% add_query_param request param key %}" class="list-group-item active">
<span class="glyphicon glyphicon-ok" style="float: right" aria-hidden="true"></span> {{ label }}
</a>
{% else %}
<a href="{% add_query_param request param key %}" class="list-group-item">{{ label }}</a>
{% endif %}
{% endfor %}
</div>
""")
class OrderingFilterPlusGlyphTests(TestCase): class OrderingFilterPlusGlyphTests(TestCase):
def setUp(self): def create_objects(self, currents):
self.filter = filters.OrderingFilter() self.ordering_filter = filters.OrderingFilter()
self.request = Request(factory.get('/', {'ordering': ','.join(currents)} if currents else None))
self.view = OrderingViewSet()
def assertPlusResult(self, currents, expected):
self.create_objects(currents)
context = self.ordering_filter.get_template_context(self.request, None, self.view)
for key, expected_prio_and_plus_key in expected.items():
prio_and_plus_key = [x[2:] for x in context['options_plus'] if x[0] == key][0]
self.assertEqual(prio_and_plus_key, expected_prio_and_plus_key)
self.assertOldTemplateWillRenderProperly(context)
def assertOldTemplateWillRenderProperly(self, context_dict):
context = Context(context_dict)
result = oldOrderingTemplate.render(context)
for key, label in context_dict['options']:
self.assertIn('ordering=' + key, result)
self.assertIn(label, result)
if context_dict['current']:
self.assertIn('class="glyphicon glyphicon-ok"', result)
def test_no_ordering_defined(self): def test_no_ordering_defined(self):
self.assertEqual((None, None), self.filter.plus_key(None, 'id')) current_ordering = None
self.assertEqual((None, None), self.filter.plus_key(None, '-id')) expected = {
'id': (None, None),
'-id': (None, None),
}
self.assertPlusResult(current_ordering, expected)
def test_one_ordering_param_same_key(self): def test_one_ordering_param(self):
# there is no priority output at all current_ordering = ['id']
self.assertEqual((None, None), self.filter.plus_key(['id'], 'id')) expected = {
self.assertEqual((None, None), self.filter.plus_key(['-id'], '-id')) 'id': (None, None),
'-id': (None, '-id'),
'slug': (None, 'id,slug'),
'-slug': (None, 'id,-slug'),
}
self.assertPlusResult(current_ordering, expected)
self.assertEqual((None, '-id'), self.filter.plus_key(['id'], '-id')) current_ordering = ['-id']
self.assertEqual((None, 'id'), self.filter.plus_key(['-id'], 'id')) expected = {
'id': (None, 'id'),
'-id': (None, None),
'slug': (None, '-id,slug'),
'-slug': (None, '-id,-slug'),
}
self.assertPlusResult(current_ordering, expected)
def test_one_ordering_param_different_key(self): def test_two_ordering_params(self):
# there is no priority output at all current_ordering = ['id', 'slug']
self.assertEqual((None, 'id,slug'), self.filter.plus_key(['id'], 'slug')) expected = {
self.assertEqual((None, 'id,-slug'), self.filter.plus_key(['id'], '-slug')) 'id': (1, 'slug'),
'-id': (None, 'slug,-id'),
self.assertEqual((None, '-id,slug'), self.filter.plus_key(['-id'], 'slug')) 'slug': (2, 'id'),
self.assertEqual((None, '-id,-slug'), self.filter.plus_key(['-id'], '-slug')) '-slug': (None, 'id,-slug'),
'author': (None, 'id,slug,author'),
def test_two_ordering_param_exist_key(self): '-author': (None, 'id,slug,-author'),
self.assertEqual((1, 'slug'), self.filter.plus_key(['id', 'slug'], 'id')) }
self.assertEqual((None, 'slug,-id'), self.filter.plus_key(['id', 'slug'], '-id')) self.assertPlusResult(current_ordering, expected)
self.assertEqual((2, 'id'), self.filter.plus_key(['id', 'slug'], 'slug'))
self.assertEqual((None, 'id,-slug'), self.filter.plus_key(['id', 'slug'], '-slug'))
self.assertEqual((None, 'id,-slug'), self.filter.plus_key(['id', 'slug'], '-slug'))
self.assertEqual((2, 'id'), self.filter.plus_key(['id', 'slug'], 'slug'))
def test_two_ordering_param_other_key(self):
self.assertEqual((None, 'id,slug,author'), self.filter.plus_key(['id', 'slug'], 'author'))
self.assertEqual((None, 'id,slug,-author'), self.filter.plus_key(['id', 'slug'], '-author'))
class SensitiveOrderingFilterModel(models.Model): class SensitiveOrderingFilterModel(models.Model):