Sort Table Headers

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
ORDER_VAR = 'o'
ORDER_TYPE_VAR = 'ot'

class SortHeaders:
    """
    Handles generation of an argument for the Django ORM's
    ``order_by`` method and generation of table headers which reflect
    the currently selected sort, based on defined table headers with
    matching sort criteria.

    Based in part on the Django Admin application's ``ChangeList``
    functionality.
    """
    def __init__(self, request, headers, default_order_field=None,
            default_order_type='asc', additional_params=None):
        """
        request
            The request currently being processed - the current sort
            order field and type are determined based on GET
            parameters.

        headers
            A list of two-tuples of header text and matching ordering
            criteria for use with the Django ORM's ``order_by``
            method. A criterion of ``None`` indicates that a header
            is not sortable.

        default_order_field
            The index of the header definition to be used for default
            ordering and when an invalid or non-sortable header is
            specified in GET parameters. If not specified, the index
            of the first sortable header will be used.

        default_order_type
            The default type of ordering used - must be one of
            ``'asc`` or ``'desc'``.

        additional_params:
            Query parameters which should always appear in sort links,
            specified as a dictionary mapping parameter names to
            values. For example, this might contain the current page
            number if you're sorting a paginated list of items.
        """
        if default_order_field is None:
            for i, (header, query_lookup) in enumerate(headers):
                if query_lookup is not None:
                    default_order_field = i
                    break
        if default_order_field is None:
            raise AttributeError('No default_order_field was specified and none of the header definitions given were sortable.')
        if default_order_type not in ('asc', 'desc'):
            raise AttributeError('If given, default_order_type must be one of \'asc\' or \'desc\'.')
        if additional_params is None: additional_params = {}

        self.header_defs = headers
        self.additional_params = additional_params
        self.order_field, self.order_type = default_order_field, default_order_type

        # Determine order field and order type for the current request
        params = dict(request.GET.items())
        if ORDER_VAR in params:
            try:
                new_order_field = int(params[ORDER_VAR])
                if headers[new_order_field][1] is not None:
                    self.order_field = new_order_field
            except (IndexError, ValueError):
                pass # Use the default
        if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'):
            self.order_type = params[ORDER_TYPE_VAR]

    def headers(self):
        """
        Generates dicts containing header and sort link details for
        all defined headers.
        """
        for i, (header, order_criterion) in enumerate(self.header_defs):
            th_classes = []
            new_order_type = 'asc'
            if i == self.order_field:
                th_classes.append('sorted %sending' % self.order_type)
                new_order_type = {'asc': 'desc', 'desc': 'asc'}[self.order_type]
            yield {
                'text': header,
                'sortable': order_criterion is not None,
                'url': self.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
                'class_attr': (th_classes and ' class="%s"' % ' '.join(th_classes) or ''),
            }

    def get_query_string(self, params):
        """
        Creates a query string from the given dictionary of
        parameters, including any additonal parameters which should
        always be present.
        """
        params.update(self.additional_params)
        return '?%s' % '&'.join(['%s=%s' % (param, value) \
                                     for param, value in params.items()])

    def get_order_by(self):
        """
        Creates an ordering criterion based on the current order
        field and order type, for use with the Django ORM's
        ``order_by`` method.
        """
        return '%s%s' % (
            self.order_type == 'desc' and '-' or '',
            self.header_defs[self.order_field][1],
        )

More like this

  1. Yet another SQL debugging facility by miracle2k 5 years, 9 months ago
  2. Functional Filters by waterson 5 years, 7 months ago
  3. Group sequence into rows and columns for a TABLE by davidwtbuxton 2 years, 3 months ago
  4. Python Calendar wrapper template tag by dokterbob 4 years ago
  5. NewForms Readonly / Edit Pattern by FreddieP 5 years, 5 months ago

Comments

skam (on July 13, 2007):

line 66: except (IndexError, ValueError) instead of IndexError, ValueError

great work!

#

insin (on July 13, 2007):

Whoops, thanks for pointing that out - fixed it now.

#

sebastianmacias (on September 4, 2007):

Would it be possible to use ordering criteria that span relationships?

Lets say I have article model and each article belogs to a user.

I would like to order the artcles by user email

but I get an error when I add ('Email Address', 'user__email') to LIST_HEADERS.

Best,

Sebastian Macias

#

mirobe (on February 7, 2008):

I'm affraid there would be a problem when using pagination.

Do you have pagination enabled version of sorted headers list ?

Thanks

#

powerfox (on January 28, 2009):

Nice work! Thanks a lot.

#

hagan (on July 2, 2009):

This actually works quite well with the Paginator.

Just follow the example on: http://docs.djangoproject.com/en/dev/topics/pagination/

And change in your for loop:

{% for user in users %} to {% for user in users.object_list %}

That worked for me anyways...

#

leplatrem (on July 23, 2009):

A possible alternative is to use pure Javascript table sort:

http://www.kryogenix.org/code/browser/sorttable/

#

blcArmadillo (on June 17, 2010):

Is there anyway to independently sort multiple tables on a single page?

#

darrinmc (on March 21, 2011):

I'm using this code with django 1.2.5 and I get the following error in a simple list view:

Exception Value: 'generator' object has no attribute 'GET'
Exception Location: /Users/darrinmc/Projects/django/djangotest/myapp/sort_headers.py in __init__, line 60

Line 60 of sort_headers.py is this line:

params = dict(request.GET.items())

In the debug output, the request object is a generator object when this method is called. Has anyone else seen this? Thanks.

#

darrinmc (on March 26, 2011):

I figured out my problem. It was unrelated to this code.

#

VeryCool (on May 3, 2011):

I had a search form in the list page with the method get. I had to add some extra lines to include the request get query string in the sorted link path. enjoy

[HTML_REMOVED]

#

VeryCool (on May 3, 2011):

if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'): self.order_type = params[ORDER_TYPE_VAR]

  • """
  • if there is a query string in the path include it in the sorted links.
  • """
  • if request.META.has_key('QUERY_STRING'):
  • query_string = request.META["QUERY_STRING"]
  • param_list = query_string.split('&')
  • for item in param_list :
  • k, v = item.split('=')
  • if k not in (ORDER_VAR,ORDER_TYPE_VAR) and v not in (ORDER_VAR,ORDER_TYPE_VAR):
  • additional_params.update({k:v})

#

siblek31 (on April 13, 2013):

Perancis adalah negara maju, [7] dan memiliki ekonomi terbesar kedua di Eropa terbesar kelima di dunia dengan PDB nominal. Itu juga merupakan tips cepat hamil dunia terbesar kesembilan dengan PDB paritas soal ulangan harian sd daya beli [8] Perancis adalah negara terkaya di Eropa -. Dan keempat terkaya di dunia -. Dalam kekayaan rumah tangga agregat [9] teknisi komputer warga Perancis menikmati standar tinggi hidup, tingkat pendidikan publik yang tinggi, dan salah satu harapan hidup terpanjang di click here dunia. [10] Perancis telah terdaftar sebagai "perawatan kesehatan secara keseluruhan terbaik" penyedia dunia oleh Organisasi kursus bahasa inggris Kesehatan dunia. [11] ini adalah negara yang paling dikunjungi di dunia, menerima 79.500.000 turis mendapatkan uang dari internet asing per tahun [12].

#

(Forgotten your password?)