diff --git a/django_sorting/middleware.py b/django_sorting/middleware.py index cd8a076..9a67d47 100644 --- a/django_sorting/middleware.py +++ b/django_sorting/middleware.py @@ -1,17 +1,39 @@ +try: + from django.utils.deprecation import MiddlewareMixin +except ImportError: + MiddlewareMixin = object + + def get_field(self): try: - field = self.REQUEST['sort'] - except (KeyError, ValueError, TypeError): + get = self.GET + if 'sort' in get: + field = get['sort'] + else: + post = self.POST + if 'sort' in post: + field = post['sort'] + else: + field = '' + except AttributeError: field = '' return (self.direction == 'desc' and '-' or '') + field def get_direction(self): try: - return self.REQUEST['dir'] - except (KeyError, ValueError, TypeError): + get = self.GET + if 'dir' in get: + return get['dir'] + else: + post = self.POST + if 'dir' in post: + return post['sort'] + else: + return 'desc' + except AttributeError: return 'desc' -class SortingMiddleware(object): +class SortingMiddleware(MiddlewareMixin): """ Inserts a variable representing the field (with direction of sorting) onto the request object if it exists in either **GET** or **POST** @@ -19,4 +41,4 @@ class SortingMiddleware(object): """ def process_request(self, request): request.__class__.field = property(get_field) - request.__class__.direction = property(get_direction) \ No newline at end of file + request.__class__.direction = property(get_direction) diff --git a/django_sorting/templatetags/sorting_tags.py b/django_sorting/templatetags/sorting_tags.py index 7cdeb42..fae37db 100644 --- a/django_sorting/templatetags/sorting_tags.py +++ b/django_sorting/templatetags/sorting_tags.py @@ -6,34 +6,33 @@ DEFAULT_SORT_UP = getattr(settings, 'DEFAULT_SORT_UP' , '↑') DEFAULT_SORT_DOWN = getattr(settings, 'DEFAULT_SORT_DOWN' , '↓') -INVALID_FIELD_RAISES_404 = getattr(settings, +INVALID_FIELD_RAISES_404 = getattr(settings, 'SORTING_INVALID_FIELD_RAISES_404' , False) sort_directions = { - 'asc': {'icon':DEFAULT_SORT_UP, 'inverse': 'desc'}, - 'desc': {'icon':DEFAULT_SORT_DOWN, 'inverse': 'asc'}, - '': {'icon':DEFAULT_SORT_DOWN, 'inverse': 'asc'}, + 'asc': {'icon':DEFAULT_SORT_UP, 'inverse': 'desc'}, + 'desc': {'icon':DEFAULT_SORT_DOWN, 'inverse': 'asc'}, + '': {'icon':DEFAULT_SORT_DOWN, 'inverse': 'asc'}, } def anchor(parser, token): """ - Parses a tag that's supposed to be in this format: {% anchor field title %} - """ - bits = [b.strip('"\'') for b in token.split_contents()] - if len(bits) < 2: - raise TemplateSyntaxError, "anchor tag takes at least 1 argument" + Parses a tag that's supposed to be in this format: {% anchor field title %} + """ try: - title = bits[2] + + tag_name, field, title = token.split_contents() except IndexError: - title = bits[1].capitalize() - return SortAnchorNode(bits[1].strip(), title.strip()) - + tag_name, field = token.split_contents() + title = field.capitalize() + return SortAnchorNode(field, title) + class SortAnchorNode(template.Node): """ - Renders an HTML tag with a link which href attribute + Renders an HTML tag with a link which href attribute includes the field on which we sort and the direction. - and adds an up or down arrow if the field is the one + and adds an up or down arrow if the field is the one currently being sorted on. Eg. @@ -42,10 +41,21 @@ class SortAnchorNode(template.Node): """ def __init__(self, field, title): - self.field = field - self.title = title + self.field = template.Variable(field) + self.title = template.Variable(title) def render(self, context): + try: + self.rendered_field = self.field.resolve(context) + except template.VariableDoesNotExist: + self.rendered_field = str(self.field) + try: + self.rendered_title = self.title.resolve(context) + except template.VariableDoesNotExist: + self.rendered_title = str(self.title) + except AttributeError: + self.rendered_title = str(self.title) + request = context['request'] getvars = request.GET.copy() if 'sort' in getvars: @@ -58,7 +68,7 @@ def render(self, context): del getvars['dir'] else: sortdir = '' - if sortby == self.field: + if sortby == self.rendered_field: getvars['dir'] = sort_directions[sortdir]['inverse'] icon = sort_directions[sortdir]['icon'] else: @@ -67,20 +77,34 @@ def render(self, context): urlappend = "&%s" % getvars.urlencode() else: urlappend = '' + if icon: - title = "%s %s" % (self.title, icon) + title = "%s %s" % (self.rendered_title, icon) else: - title = self.title + title = self.rendered_title + + url = '%s?sort=%s%s' % (request.path, self.rendered_field, urlappend) + return '%s' % (url, self.rendered_title, title) - url = '%s?sort=%s%s' % (request.path, self.field, urlappend) - return '%s' % (url, self.title, title) def autosort(parser, token): - bits = [b.strip('"\'') for b in token.split_contents()] - if len(bits) != 2: - raise TemplateSyntaxError, "autosort tag takes exactly one argument" - return SortedDataNode(bits[1]) + bits = token.split_contents() + if len(bits) not in (2, 4): + raise template.TemplateSyntaxError("autosort tag takes exactly one argument") + try: + if bits[2] != 'as': + raise template.TemplateSyntaxError( + "Context variable assignment must take the form of {%% %s" + " queryset as context_var_name %%}" % bits[0] + ) + except IndexError: + pass + try: + return SortedDataNode(bits[1], bits[-1]) + except IndexError: + return SortedDataNode(bits[1]) + class SortedDataNode(template.Node): """ @@ -91,7 +115,10 @@ def __init__(self, queryset_var, context_var=None): self.context_var = context_var def render(self, context): - key = self.queryset_var.var + if self.context_var is None: + key = self.queryset_var.var + else: + key = self.context_var value = self.queryset_var.resolve(context) order_by = context['request'].field if len(order_by) > 1: @@ -109,4 +136,3 @@ def render(self, context): anchor = register.tag(anchor) autosort = register.tag(autosort) -