Giter VIP home page Giter VIP logo

django-sorting's Introduction

How to use django-sorting
----------------------------

``django-sorting`` allows for easy sorting, and sorting links 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 = (
           # ...
           'django_sorting',
       )

2. Install the sorting middleware. Your settings file might look something
   like::
   
       MIDDLEWARE_CLASSES = (
           # ...
           'django_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>{% anchor first_name Name %}</th>
       <th>{% anchor creation_date Creation %}</th>
        ...
    </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="/path/to/your/view/?sort=first_name" title="Name">Name</a></th>
        <th><a href="/path/to/your/view/?sort=creation_date" title="Name">Creation</a></th>
        ...
    </tr>


That's it!  


django-sorting's People

Contributors

directeur avatar ericflo avatar jezdez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-sorting's Issues

Generalization of 'autosort' tag for iterables.

Right now 'autosort' tag assumes that what is passed as an var is a queryset. I guess this assumption could be relaxed a bit to any iterables. The solution below (diff) works well for me.

diff -crB django_sorting-old/templatetags/sorting_tags.py django_sorting/templatetags/sorting_tags.py                     
*** django_sorting-old/templatetags/sorting_tags.py     2010-02-20 18:56:52.000000000 +0100                               
--- django_sorting/templatetags/sorting_tags.py 2010-02-20 19:03:45.000000000 +0100                                       
***************                                                                                                           
*** 1,6 ****                                                                                                              
--- 1,8 ----                                                                                                              
  from django import template                                                                                             
  from django.http import Http404                                                                                         
  from django.conf import settings                                                                                        
+ from django.db.models.query import QuerySet                                                                             
+ from operator import attrgetter                                                                                         
                                                                                                                          
  register = template.Library()                                                                                           

***************
*** 96,102 ****
          order_by = context['request'].field
          if len(order_by) > 1:
              try:
!                 context[key] = value.order_by(order_by)
              except template.TemplateSyntaxError:
                  if INVALID_FIELD_RAISES_404:
                      raise Http404('Invalid field sorting. If DEBUG were set to ' +
--- 98,119 ----
          order_by = context['request'].field
          if len(order_by) > 1:
              try:
!                 if isinstance(value, QuerySet):
!                     # more flexible but generally more error-prone check:
!                     #    callable(getattr(value, 'order_by', None))
!                     context[key] = value.order_by(order_by)
!                 # sort iterable
!                 elif hasattr(value, '__iter__'):
!                     if order_by[0]=='-': # descending order
!                         reverse = True
!                         order_by = order_by[1:]
!                     else: # ascending order (standard)
!                         reverse = False
!                     context[key] =\
!                         sorted(value,key=attrgetter(order_by),reverse=reverse)
!                 else:
!                     raise AttributeError("Expected QuerySet or iterable under\
!                                           template variable '%s'." % key)
              except template.TemplateSyntaxError:
                  if INVALID_FIELD_RAISES_404:
                      raise Http404('Invalid field sorting. If DEBUG were set to ' +

Ordering by more than one field

Could you add an option to sort by more than one field? It would be great if this tool could manage queries like this:

MyModel.objects.order_by('first_field','second_field')

Way to sort via related objects?

So far I couldn't find a way to sort through a related object's field.
Quick and dirty example:

class Blog(models.Model):
    name = models.CharField()
    type = models.CharField()

class Entry(models.Model):
    name = models.CharField()
    blog = models.ForeignKey(Blog)

And i have a table for Entries with three headers: Entry name, Blog name and Blog type.
I can sort the table by Entry name and Blog name, but not by Blog type. If i try

{% anchor 'blog.type' %}

It comes up with a TemplateSyntaxError:
Caught an exception while rendering: missing FROM-clause entry for table "blog"
LINE 1: ...ND NOT ("testapp_entry"."id" IN (110))) ORDER BY "blog...

I'm wondering if there's a bug in here or if it's simply not implemented. A
pointer of what code to check would be great, i could try and fix/add it
myself. I'm betting that this can be accomplished by tweaking
templatetags/sorting_tags.py, but i can't discern how it could be done.

By the way, awesome extension! It was such a pleasure doing away with my hardcoded sorting code :-)

Foreign Key relationship is not working

I have table field like {{order.product.title}}. sorting header put ike {% anchor product.title %}. it show error like "Cannot resolve keyword u'title' into field."

Is it possible to add sorting for foreignkey relationship..

Package on PyPI

It'd be great if we had django-sorting on PyPI. From what I see setup.py is ready to have a python setup.py sdist bdist_egg register upload.

Translatable strings

Add possibility to translate strings in templates.

Just update "sorting_tags.py" with the following code

from django import template
from django.http import Http404
from django.conf import settings
from django.utils.translation import ugettext_lazy as _, ugettext as _f

register = template.Library()

DEFAULT_SORT_UP = getattr(settings, 'DEFAULT_SORT_UP' , 'โ†‘')
DEFAULT_SORT_DOWN = getattr(settings, 'DEFAULT_SORT_DOWN' , 'โ†“')
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'},
}

def anchor(parser, token):
"""
Parses a tag that's supposed to be in this format: {% anchor field title translate_title %}
"""
bits = [b.strip('"'') for b in token.split_contents()]
if len(bits) < 2:
raise TemplateSyntaxError, "anchor tag takes at least 1 argument"
try:
title = bits[2]
except IndexError:
title = bits[1].capitalize()
try:
translate_title = bool(bits[3])
except IndexError:
translate_title = True
return SortAnchorNode(bits[1].strip(), title.strip(), translate_title)

class SortAnchorNode(template.Node):
"""
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
currently being sorted on.

Eg.
    {% anchor name Name %} generates
    <a href="/the/current/path/?sort=name" title="Name">Name</a>

"""
def __init__(self, field, title, translate_title=True):
    self.field = field
    self.title = title
    self.translate_title = translate_title

def render(self, context):
    if self.translate_title:
        self.title = _f(self.title)
    request = context['request']
    getvars = 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 = ''
    if icon:
        title = "%s %s" % (self.title, icon)
    else:
        title = self.title

    url = '%s?sort=%s%s' % (request.path, self.field, urlappend)
    return '<a href="%s" title="%s">%s</a>' % (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])

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:
        try:
            context[key] = value.order_by(order_by)
        except template.TemplateSyntaxError:
            if INVALID_FIELD_RAISES_404:
                raise Http404('Invalid field sorting. If DEBUG were set to ' +
                'False, an HTTP 404 page would have been shown instead.')
            context[key] = value
    else:
        context[key] = value

    return ''

anchor = register.tag(anchor)
autosort = register.tag(autosort)

Field not exist checking

    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:
            try:
                try:
                    field_name = order_by
                    if order_by[0] == '-':
                        field_name = order_by[1:]
                    # check for order field exist in model
                    value.model._meta.get_field(field_name)
                    context[key] = value.order_by(order_by)
                except FieldDoesNotExist as e:
                    if settings.DEBUG == True:
                        raise e

            except template.TemplateSyntaxError:
                if INVALID_FIELD_RAISES_404:
                    raise Http404('Invalid field sorting. If DEBUG were set to ' +
                    'False, an HTTP 404 page would have been shown instead.')
                context[key] = value
        else:
            context[key] = value

        return ''

Support for 'as' in template tag

django-pagination supports the 'as' keyword in the template tag:

{% autopaginate f.qs 40 as filter_list %}

This allows us to use it with django-filter too, as noted here: http://github.com/alex/django-filter/issues#issue/13.

To combing django-sorting with pagination, if I understand correctly, we'll need to do this:

{% autosort f.qs as actionlog %}
{% autopaginate actionlog 30 %}

Currently I'm doing this through the view, passing an extra argument to the template, but it'd be nice if we could provide this backwards-compatible fix.

Exception with invalid sort GET variable

The following URL raises an exception: ?sort=foo. One would expect this would be caught and simply ignored.

Exception Type: TemplateSyntaxError at /projects/usermode/log/
Exception Value: Caught an exception while rendering: Cannot resolve keyword u'foo' into field. Choices are: action_time, action_type, content_type, id, message, object_id, object_name, user

Original Traceback (most recent call last):
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/template/debug.py", line 71, in render_node
    result = node.render(context)
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/template/defaulttags.py", line 244, in render
    if (value and not ifnot) or (ifnot and not value):
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/query.py", line 191, in __nonzero__
    iter(self).next()
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/query.py", line 185, in _result_iter
    self._fill_cache()
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/query.py", line 618, in _fill_cache
    self._result_cache.append(self._iter.next())
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/query.py", line 275, in iterator
    for row in self.query.results_iter():
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 206, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 1724, in execute_sql
    sql, params = self.as_sql()
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 261, in as_sql
    ordering = self.get_ordering()
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 656, in get_ordering
    self.model._meta, default_order=asc):
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 684, in find_ordering_name
    opts, alias, False)
  File "/home/mits/devel/envs/current/lib/python2.5/site-packages/Django-1.0.2_final-py2.5.egg/django/db/models/sql/query.py", line 1321, in setup_joins
    "Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword u'foo' into field. Choices are: action_time, action_type, content_type, id, message, object_id, object_name, user

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.