Allow select additional sort criteria on modal filter form

This commit is contained in:
Gassan Gousseinov 2021-03-14 17:52:14 +01:00
parent 883f6fe814
commit 226deb5707
6 changed files with 108 additions and 7 deletions

View File

@ -276,7 +276,8 @@ class OrderingFilter(BaseFilterBackend):
def get_template_context(self, request, queryset, view):
current = self.get_ordering(request, queryset, view)
current = None if not current else current[0]
if not current:
current = None
options = []
context = {
'request': request,
@ -284,11 +285,36 @@ class OrderingFilter(BaseFilterBackend):
'param': self.ordering_param,
}
for key, label in self.get_valid_fields(queryset, view, context):
options.append((key, '%s - %s' % (label, _('ascending'))))
options.append(('-' + key, '%s - %s' % (label, _('descending'))))
options.append((key, '%s - %s' % (label, _('ascending')), *self.plus_key(current, key)))
options.append(('-' + key, '%s - %s' % (label, _('descending')), *self.plus_key(current, '-' + key)))
context['options'] = options
return context
@staticmethod
def plus_key(current, key):
priority = None
plus_key = None
if current:
if len(current) > 1:
try:
priority = current.index(key) + 1
except ValueError:
pass
for_plus = current.copy()
if key in for_plus:
# for click on minus
for_plus.remove(key)
else:
# for click on plus - rearrange sort priorities
# remove key or -key
for_plus = [k for k in for_plus if k.lstrip('-') != key.lstrip('-')]
for_plus.append(key)
if for_plus:
plus_key = ','.join(for_plus)
return priority, plus_key
def to_html(self, request, queryset, view):
template = loader.get_template(self.template)
context = self.get_template_context(request, queryset, view)

View File

@ -80,3 +80,11 @@ pre {
#filtersModal .modal-body h2 {
margin-top: 0
}
#filtersModal .list-group-item .glyphicon-plus[data-plus-ordering] {
visibility: hidden;
}
#filtersModal .list-group-item:hover .glyphicon-plus[data-plus-ordering] {
visibility: visible;
}

View File

@ -41,6 +41,12 @@ $(document).ready(function() {
$('.form-switcher a:first').tab('show');
}
// add onclick to ordering plus and minus glyph
$('#filtersModal span[data-plus-ordering]').click(function(e) {
var glyph = $(e.target);
glyph.closest('a.list-group-item').attr('href', glyph.attr('data-plus-ordering'));
});
$(window).on('load', function() {
$('#errorModal').modal('show');
});

View File

@ -2,13 +2,24 @@
{% load i18n %}
<h2>{% trans "Ordering" %}</h2>
<div class="list-group">
{% for key, label in options %}
{% if key == current %}
{% for key, label, priority, plus_key in options %}
{% if key in 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 }}
<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>
{% if priority %}
<b style="float: right; display: inline-block; padding-right: 10px;">{{ priority }}</b>
{% endif %}
{{ label }}
</a>
{% else %}
<a href="{% add_query_param request param key %}" class="list-group-item">{{ label }}</a>
<a href="{% add_query_param request param key %}" class="list-group-item">
{% if current %}
<span class="glyphicon glyphicon-plus" style="float: right" aria-hidden="true"
data-plus-ordering="{% add_query_param request param plus_key %}"></span>
{% endif %}
{{ label }}
</a>
{% endif %}
{% endfor %}
</div>

View File

@ -10,6 +10,7 @@ from django.utils.safestring import mark_safe
from rest_framework.compat import apply_markdown, pygments_highlight
from rest_framework.renderers import HTMLFormRenderer
from rest_framework.utils.urls import remove_query_param as _remove_query_param
from rest_framework.utils.urls import replace_query_param
register = template.Library()
@ -154,6 +155,16 @@ def add_query_param(request, key, val):
return escape(replace_query_param(uri, key, val))
@register.simple_tag
def remove_query_param(request, key):
"""
Remove a query parameter from the current request url, and return the new url.
"""
iri = request.get_full_path()
uri = iri_to_uri(iri)
return escape(_remove_query_param(uri, key))
@register.filter
def as_string(value):
if value is None:

View File

@ -712,6 +712,45 @@ class OrderingFilterTests(TestCase):
view(request)
class OrderingFilterPlusGlyphTests(TestCase):
def setUp(self):
self.filter = filters.OrderingFilter()
def test_no_ordering_defined(self):
self.assertEqual((None, None), self.filter.plus_key(None, 'id'))
self.assertEqual((None, None), self.filter.plus_key(None, '-id'))
def test_one_ordering_param_same_key(self):
# there is no priority output at all
self.assertEqual((None, None), self.filter.plus_key(['id'], 'id'))
self.assertEqual((None, None), self.filter.plus_key(['-id'], '-id'))
self.assertEqual((None, '-id'), self.filter.plus_key(['id'], '-id'))
self.assertEqual((None, 'id'), self.filter.plus_key(['-id'], 'id'))
def test_one_ordering_param_different_key(self):
# there is no priority output at all
self.assertEqual((None, 'id,slug'), self.filter.plus_key(['id'], 'slug'))
self.assertEqual((None, 'id,-slug'), self.filter.plus_key(['id'], '-slug'))
self.assertEqual((None, '-id,slug'), self.filter.plus_key(['-id'], 'slug'))
self.assertEqual((None, '-id,-slug'), self.filter.plus_key(['-id'], '-slug'))
def test_two_ordering_param_exist_key(self):
self.assertEqual((1, 'slug'), self.filter.plus_key(['id', 'slug'], 'id'))
self.assertEqual((None, 'slug,-id'), self.filter.plus_key(['id', 'slug'], '-id'))
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):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)