=== modified file 'lava/utils/data_tables/tables.py'
@@ -18,9 +18,13 @@
"""Tables designed to be used with the DataTables jQuery plug in.
-There are just three steps to using this:
-
-1) Define the table::
+It is expected that most tables will be backed onto database queries, but it
+is possible to create tables backed onto regular Python instances.
+
+There are just three steps to creating a database-backed table:
+
+1) Define the table, which means the columns and the queryset that supplies
+ them with data::
class BookTable(DataTablesTable):
author = Column()
@@ -33,6 +37,10 @@
def book_table_json(request):
return BookTable.json(request)
+ Don't forget urls.py:
+
+ url(r'^book_table_json$', 'book_table_json'),
+
3) Include the table in the view for the page you are building::
def book_list(request):
@@ -85,9 +93,15 @@
in the json view need to be consistent, many of the options that you can pass
to Table's __init__ are not available for DataTablesTable. In practice this
means that you need a DataTablesTable subclass for each different table.
+
+If you want to create a DataTablesTable based table, just pass a sequence to
+the data= argument of the constructor (and do not pass anything for the source
+argument) and supply the table instance to {% render_table %} (no need for a
+get_queryset method or a json view in this case). The 'params' argument in
+this case, if passed, is stored on the instance where it can be accessed if
+needed when rendering a column.
"""
-from abc import ABCMeta, abstractmethod
import simplejson
from django.template import RequestContext
@@ -99,48 +113,54 @@
from lava.utils.data_tables.backends import TableBackend
-class MetaTable(ABCMeta, Table.__metaclass__):
- pass
-
-
class DataTablesTable(Table):
"""A table designed to be used with the DataTables jQuery plug in.
"""
- __metaclass__ = MetaTable
-
def __init__(self, id, source=None, params=(), sortable=None,
- empty_text=None, attrs=None, template=None):
+ empty_text=None, attrs=None, template=None, data=None):
"""Initialize the table.
Options that Table supports that affect the data presented are not
supported in this subclass. Extra paramters are:
:param id: The id of the table in the resulting HTML. You just need
- to provide somethign that will be unique in the generated page.
+ to provide something that will be unique in the generated page.
:param source: The URL to get json data from.
:param params: A tuple of arguments to pass to the get_queryset()
method.
+ :param data: The data to base the table on, if any.
"""
+ if data is not None:
+ if source is not None or self.source is not None:
+ raise AssertionError(
+ "Do not specify both data and source when building a "
+ "DataTablesTable")
+ self.params = params
+ data_backed_table = True
+ else:
+ data_backed_table = False
+ data = []
+ if source is not None:
+ self.source = source
if template is None:
template = 'ajax_table.html'
- # The reason we pass data=[] here and patch the queryset in below is
- # because of a bootstrapping issue. We want to sort the initial
- # queryset, and this is much cleaner if the table has has its .columns
- # set up which is only done in Table.__init__...
+ # Even if this is an ajax backed table, we pass data here and patch
+ # the queryset in below because of a bootstrapping issue: we want to
+ # sort the initial queryset, and this is much cleaner if the table has
+ # has its .columns set up which is only done in Table.__init__...
super(DataTablesTable, self).__init__(
- data=[], sortable=sortable, empty_text=empty_text, attrs=attrs,
+ data=data, sortable=sortable, empty_text=empty_text, attrs=attrs,
template=template)
- self.full_queryset = self.get_queryset(*params)
- self.full_length = self.full_queryset.count()
- ordering = self.datatable_opts.get('aaSorting', [[0, 'asc']])
- sorted_queryset = TableBackend(self).apply_sorting_columns(
- self.full_queryset, ordering)
- display_length = self.datatable_opts.get('iDisplayLength', 10)
- del self.data.list
- self.data.queryset = sorted_queryset[:display_length]
- if source is not None:
- self.source = source
+ if not data_backed_table:
+ self.full_queryset = self.get_queryset(*params)
+ self.full_length = self.full_queryset.count()
+ ordering = self.datatable_opts.get('aaSorting', [[0, 'asc']])
+ sorted_queryset = TableBackend(self).apply_sorting_columns(
+ self.full_queryset, ordering)
+ display_length = self.datatable_opts.get('iDisplayLength', 10)
+ del self.data.list
+ self.data.queryset = sorted_queryset[:display_length]
# We are careful about modifying the attrs here -- if it comes from
# class Meta:-type options, we don't want to modify the original
# value!
@@ -182,13 +202,17 @@
"""The DataTable options for this table, serialized as JSON."""
opts = {
'bJQueryUI': True,
- 'bServerSide': True,
'bProcessing': True,
- 'sAjaxSource': self.source,
- 'bFilter': bool(self.searchable_columns),
- 'iDeferLoading': self.full_length,
+ 'bFilter': True,
}
opts.update(self.datatable_opts)
+ if self.source is not None:
+ opts.update({
+ 'bServerSide': True,
+ 'sAjaxSource': self.source,
+ 'bFilter': bool(self.searchable_columns),
+ 'iDeferLoading': self.full_length,
+ })
aoColumnDefs = opts['aoColumnDefs'] = []
for col in self.columns:
aoColumnDefs.append({
@@ -198,28 +222,30 @@
})
return simplejson.dumps(opts)
- # Subclasses must override get_queryset() and may want to provide values
- # for source, datatable_opts and searchable_columns.
-
- @abstractmethod
+ # Any subclass might want to provide values for datatable_opts.
+
+ # Extra DataTable options. Values you might want to override here include
+ # 'iDisplayLength' (how big to make the table's pages by default) and
+ # 'aaSorting' (the initial sort of the table). See
+ # http://datatables.net/usage/options for more.
+ datatable_opts = {}
+
+ # Subclasses that use dynamic data *must* override get_queryset() and may
+ # want to provide values for source, and searchable_columns.
+
def get_queryset(self, *args):
"""The data the table displays.
The return data will be sorted, filtered and sliced depending on how
the table is manipulated by the user.
"""
+ raise NotImplementedError(self.get_queryset)
# The URL to get data from (i.e. the sAjaxSource of the table). Often
# it's more convenient to pass this to the table __init__ to allow the
# code to be laid out in a more logical order.
source = None
- # Extra DataTable options. Values you might want to override here include
- # 'iDisplayLength' (how big to make the table's pages by default) and
- # 'aaSorting' (the initial sort of the table). See
- # http://datatables.net/usage/options for more.
- datatable_opts = {}
-
# Perform searches by looking in these columns. Searching will not be
# enabled unless you set this. Searching is only supported in textual
# columns for now (supporting an IntegerField with Choices seems possible