Permalink
Browse files

Initial import

  • Loading branch information...
directeur committed Mar 21, 2009
0 parents commit f7ca4e4e4714b76098818596c908ce7fc2085f75
Showing with 198 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +69 −0 README.txt
  3. +1 −0 __init__.py
  4. +20 −0 middleware.py
  5. +1 −0 models.py
  6. +1 −0 templatetags/__init__.py
  7. +104 −0 templatetags/sorting_tags.py
@@ -0,0 +1,2 @@
+*.pyc
+.DS_Store
@@ -0,0 +1,69 @@
+How to use django-sorting
+----------------------------
+
+``django-sorting`` allows for easy sorting, and tables headers (<th>) generation
+without modifying your views.
+
+There are really 5 steps to setting it up with your projects.
+
+1. List this application in the ``INSTALLED_APPS`` portion of your settings
+ file. Your settings file might look something like::
+
+ INSTALLED_APPS = (
+ # ...
+ 'sorting',
+ )
+
+2. Install the sorting middleware. Your settings file might look something
+ like::
+
+ MIDDLEWARE_CLASSES = (
+ # ...
+ 'sorting.middleware.SortingMiddleware',
+ )
+
+3. If it's not already added in your setup, add the request context processor.
+ Note that context processors are set by default implicitly, so to set them
+ explicitly, you need to copy and paste this code into your under
+ the value TEMPLATE_CONTEXT_PROCESSORS::
+
+ ("django.core.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.media",
+ "django.core.context_processors.request")
+
+4. Add this line at the top of your template to load the sorting tags:
+
+ {% load sorting_tags %}
+
+
+5. Decide on a variable that you would like to sort, and use the
+ autosort tag on that variable before iterating over it.
+
+ {% autosort object_list %}
+
+
+6. Now, you want to display different headers with links to sort
+your objects_list:
+
+ <tr>
+ {% th first_name Name %}
+ {% th creation_date Creation %}
+ ...
+ </tr>
+
+ The first argument is a field of the objects list, and the second
+ one(optional) is a title that would be displayed. The previous
+ snippet will be rendered like this:
+
+ <tr>
+ <th><a href="?sort=first_name" title="Name">Name</a></th>
+ <th><a href="?sort=creation_date" title="Name">Creation</a></th>
+ ...
+ </tr>
+
+
+That's it!
+
+
@@ -0,0 +1 @@
+
@@ -0,0 +1,20 @@
+class SortingMiddleware(object):
+ """
+ Inserts a variable representing the field (with direction of sorting)
+ onto the request object if it exists in either **GET** or **POST**
+ portions of the request.
+ """
+ def process_request(self, request):
+ try:
+ request.field = str(request.REQUEST['sort'])
+ except (KeyError, ValueError, TypeError):
+ request.field = ''
+
+ try:
+ direction = str(request.REQUEST['dir'])
+ except (KeyError, ValueError, TypeError):
+ direction = 'desc'
+
+ if direction == 'asc' and request.field:
+ request.field = '-'+request.field
+
@@ -0,0 +1 @@
+
@@ -0,0 +1 @@
+
@@ -0,0 +1,104 @@
+from django import template
+from django.http import Http404
+from django.conf import settings
+
+register = template.Library()
+
+DEFAULT_SORT_UP = getattr(settings, 'DEFAULT_SORT_UP' , '&uarr;')
+DEFAULT_SORT_DOWN = getattr(settings, 'DEFAULT_SORT_DOWN' , '&darr;')
+
+sort_directions = {
+ 'asc': {'icon':DEFAULT_SORT_UP, 'inverse':'desc'},
+ 'desc': {'icon':DEFAULT_SORT_DOWN, 'inverse':'asc'},
+ '': {'icon':DEFAULT_SORT_DOWN, 'inverse':'asc'},
+}
+
+def th(parser, token):
+ """
+ Parses a tag that's supposed to be in this format:
+ {% sth field title%}
+ """
+ bits = token.contents.split()
+ if len(bits) < 2:
+ raise TemplateSyntaxError, "th tag takes at least 1 argument"
+ try:
+ title = bits[2]
+ except IndexError:
+ title = bits[1].capitalize()
+ return SortHeaderNode(bits[1].strip(), title.strip())
+
+
+class SortHeaderNode(template.Node):
+ """
+ Renedrs a <th> 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
+ currently being sorted on.
+
+ Eg.
+ {% th name Name %} generates
+ <th><a href="?sort=name" title="Name">Name</a></th>
+
+ """
+ def __init__(self, field, title):
+ self.field = field
+ self.title = title
+
+ def render(self, context):
+ getvars = context['request'].GET.copy()
+ if 'sort' in getvars:
+ sortby = getvars['sort']
+ del getvars['sort']
+ else:
+ sortby = ''
+ if 'dir' in getvars:
+ sortdir = getvars['dir']
+ del getvars['dir']
+ else:
+ sortdir = ''
+ if sortby == self.field:
+ getvars['dir'] = sort_directions[sortdir]['inverse']
+ icon = sort_directions[sortdir]['icon']
+ else:
+ icon = ''
+ if len(getvars.keys()) > 0:
+ urlappend = "&%s" % getvars.urlencode()
+ else:
+ urlappend = ''
+ self.title = "%s %s" % (self.title, icon)
+
+ url = '?sort=%s%s' % (self.field, urlappend)
+ return '<th><a href="%s" title="%s">%s</a></th>' % (url, self.title,
+ self.title)
+
+
+def autosort(parser, token):
+ bits = token.contents.split()
+ if len(bits) != 2:
+ raise TemplateSyntaxError, "autosort tag takes exactly one argument"
+ return SortedDataNode(bits[1])
+
+class SortedDataNode(template.Node):
+ """
+ automatically sort a queryset with
+ {% autosort queryset %}
+ """
+ def __init__(self, queryset_var, context_var=None):
+ self.queryset_var = template.Variable(queryset_var)
+ self.context_var = context_var
+
+ def render(self, context):
+ key = self.queryset_var.var
+ value = self.queryset_var.resolve(context)
+ order_by = context['request'].field
+ if len(order_by) > 1:
+ context[key] = value.order_by(order_by)
+ else:
+ context[key] = value
+
+ return ''
+
+
+th = register.tag(th)
+autosort = register.tag(autosort)
+

0 comments on commit f7ca4e4

Please sign in to comment.