parent
0741abd31c
commit
512b91ead4
|
@ -0,0 +1,8 @@
|
|||
[run]
|
||||
source =
|
||||
django_tables2
|
||||
tests
|
||||
|
||||
|
||||
[html]
|
||||
directory = reports/htmlcov
|
|
@ -14,4 +14,4 @@
|
|||
/docs/_build/
|
||||
/example/database.sqlite
|
||||
/example/.env
|
||||
/pylint_*
|
||||
/report.pylint
|
||||
|
|
|
@ -2,18 +2,11 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.utils.datastructures import SortedDict
|
||||
from django.utils.functional import curry
|
||||
from django.utils.safestring import SafeData
|
||||
from django_tables2.templatetags.django_tables2 import title
|
||||
from django_tables2.utils import A, AttributeDict, OrderBy, OrderByTuple
|
||||
from itertools import ifilter, islice
|
||||
import warnings
|
||||
import inspect
|
||||
|
||||
|
||||
funcs = ifilter(curry(hasattr, inspect), ('getfullargspec', 'getargspec'))
|
||||
getargspec = getattr(inspect, next(funcs))
|
||||
del funcs
|
||||
|
||||
|
||||
class Library(object):
|
||||
|
@ -31,7 +24,7 @@ class Library(object):
|
|||
"""
|
||||
Return a column object suitable for model field.
|
||||
|
||||
:returns: column object of ``None``
|
||||
:returns: column object of `None`
|
||||
"""
|
||||
# iterate in reverse order as columns are registered in order
|
||||
# of least to most specialised (i.e. Column is registered
|
||||
|
@ -57,50 +50,80 @@ class Column(object): # pylint: disable=R0902
|
|||
"""
|
||||
Represents a single column of a table.
|
||||
|
||||
:class:`Column` objects control the way a column (including the cells that
|
||||
`.Column` objects control the way a column (including the cells that
|
||||
fall within it) are rendered.
|
||||
|
||||
:param verbose_name: A human readable version of the column name. This
|
||||
should not be title case. It is converted to title
|
||||
case for use in column headers.
|
||||
:type verbose_name: ``unicode``
|
||||
:type accessor: :class:`basestring` or :class:`~.utils.Accessor`
|
||||
:param accessor: An accessor that describes how to extract values for
|
||||
this column from the :term:`table data`.
|
||||
:param default: The default value for the column. This can be a value
|
||||
or a callable object [1]_. If an object in the data
|
||||
provides :const:`None` for a column, the default will
|
||||
be used instead.
|
||||
|
||||
The default value may affect ordering, depending on
|
||||
the type of data the table is using. The only case
|
||||
where ordering is not affected is when a
|
||||
:class:`QuerySet` is used as the table data (since
|
||||
sorting is performed by the database).
|
||||
.. attribute:: attrs
|
||||
|
||||
.. [1] The provided callable object must not expect to
|
||||
receive any arguments.
|
||||
:param order_by: Allows one or more accessors to be used for ordering
|
||||
rather than ``accessor``.
|
||||
:type order_by: :class:`unicode`, :class:`tuple`, :class:`~utils.Accessor`
|
||||
:type visible: :class:`bool`
|
||||
:param visible: If :const:`False`, this column will not be in HTML from
|
||||
output generators (e.g. :meth:`as_html` or
|
||||
``{% render_table %}``).
|
||||
HTML attributes for elements that make up the column.
|
||||
|
||||
When a field is not visible, it is removed from the
|
||||
table's :attr:`~Column.columns` iterable.
|
||||
:type orderable: :class:`bool`
|
||||
:param orderable: If :const:`False`, this column will not be allowed to
|
||||
influence row ordering/sorting.
|
||||
:type attrs: :class:`dict` object
|
||||
:param attrs: HTML attributes to be added to components in the column
|
||||
:type: `dict`
|
||||
|
||||
Supported ``attrs`` keys are:
|
||||
This API is extended by subclasses to allow arbitrary HTML attributes
|
||||
to be added to the output.
|
||||
|
||||
- *th* -- ``<th>`` element in header
|
||||
- *td* -- ``<td>`` element in body
|
||||
- *cell* -- fall back for ``<th>`` and ``<td>`` should they not be specified
|
||||
By default `.Column` supports:
|
||||
|
||||
- *th* -- ``table/thead/th`` elements
|
||||
- *td* -- ``table/tbody/tr/td`` elements
|
||||
- *cell* -- fallback if *th* or *td* isn't defined
|
||||
|
||||
|
||||
.. attribute:: accessor
|
||||
|
||||
An accessor that describes how to extract values for this column from
|
||||
the :term:`table data`.
|
||||
|
||||
:type: `basestring` or `~.Accessor`
|
||||
|
||||
|
||||
.. attribute:: default
|
||||
|
||||
The default value for the column. This can be a value or a callable
|
||||
object [1]_. If an object in the data provides `None` for a column, the
|
||||
default will be used instead.
|
||||
|
||||
The default value may affect ordering, depending on the type of data
|
||||
the table is using. The only case where ordering is not affected is
|
||||
when a `.QuerySet` is used as the table data (since sorting is
|
||||
performed by the database).
|
||||
|
||||
.. [1] The provided callable object must not expect to receive any
|
||||
arguments.
|
||||
|
||||
|
||||
.. attribute:: order_by
|
||||
|
||||
Allows one or more accessors to be used for ordering rather than
|
||||
*accessor*.
|
||||
|
||||
:type: `unicode`, `tuple`, `~.Accessor`
|
||||
|
||||
|
||||
.. attribute:: orderable
|
||||
|
||||
If `False`, this column will not be allowed to influence row
|
||||
ordering/sorting.
|
||||
|
||||
:type: `bool`
|
||||
|
||||
|
||||
.. attribute:: verbose_name
|
||||
|
||||
A human readable version of the column name.
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
This should not defined in title case, but rather natural case. It is
|
||||
converted to title case for use in column headers.
|
||||
|
||||
|
||||
.. attribute:: visible
|
||||
|
||||
If `True`, this column will be included in the HTML output.
|
||||
|
||||
:type: `bool`
|
||||
"""
|
||||
#: Tracks each time a Column instance is created. Used to retain order.
|
||||
creation_counter = 0
|
||||
|
@ -146,19 +169,20 @@ class Column(object): # pylint: disable=R0902
|
|||
"""
|
||||
The value used for the column heading (e.g. inside the ``<th>`` tag).
|
||||
|
||||
By default this titlises the column's :attr:`verbose_name`. If
|
||||
``verbose_name`` is an instance of ``SafeData``, it's used unmodified.
|
||||
By default this titlises the `~.Column.verbose_name`. If
|
||||
`~.Column.verbose_name` is an instance of `~.safestring.SafeData`, it's
|
||||
used unmodified.
|
||||
|
||||
:returns: ``unicode`` or ``None``
|
||||
:returns: `unicode` or `None`
|
||||
|
||||
.. note::
|
||||
|
||||
This property typically isn't accessed directly when a table is
|
||||
rendered. Instead, :attr:`.BoundColumn.header` is accessed which
|
||||
in turn accesses this property. This allows the header to fallback
|
||||
to the column name (it's only available on a :class:`.BoundColumn`
|
||||
object hence accessing that first) when this property doesn't
|
||||
return something useful.
|
||||
rendered. Instead, `.BoundColumn.header` is accessed which in turn
|
||||
accesses this property. This allows the header to fallback to the
|
||||
column name (it's only available on a `.BoundColumn` object hence
|
||||
accessing that first) when this property doesn't return something
|
||||
useful.
|
||||
"""
|
||||
if self.verbose_name:
|
||||
if isinstance(self.verbose_name, SafeData):
|
||||
|
@ -171,22 +195,22 @@ class Column(object): # pylint: disable=R0902
|
|||
"""
|
||||
Returns the content for a specific cell.
|
||||
|
||||
This method can be overridden by :meth:`render_FOO` methods on the
|
||||
table or by subclassing :class:`Column`.
|
||||
This method can be overridden by :ref:`table.render_FOO` methods on the
|
||||
table or by subclassing `.Column`.
|
||||
|
||||
:returns: `unicode`
|
||||
|
||||
If the value for this cell is in `self.empty_values`, this method is
|
||||
If the value for this cell is in `.empty_values`, this method is
|
||||
skipped and an appropriate default value is rendered instead.
|
||||
Subclasses should set `empty_values` to `()` if they want to handle
|
||||
all values in `render`.
|
||||
Subclasses should set `.empty_values` to ``()`` if they want to handle
|
||||
all values in `.render`.
|
||||
"""
|
||||
return value
|
||||
|
||||
@property
|
||||
def sortable(self):
|
||||
"""
|
||||
*deprecated* -- use `orderable` instead.
|
||||
*deprecated* -- use `.orderable` instead.
|
||||
"""
|
||||
warnings.warn('`sortable` is deprecated, use `orderable` instead.',
|
||||
DeprecationWarning)
|
||||
|
@ -195,14 +219,14 @@ class Column(object): # pylint: disable=R0902
|
|||
@classmethod
|
||||
def from_field(cls, field):
|
||||
"""
|
||||
Return a specialised column for the model field or ``None``.
|
||||
Return a specialised column for the model field or `None`.
|
||||
|
||||
:param field: the field that needs a suitable column
|
||||
:type field: model field instance
|
||||
:returns: Column object or ``None``
|
||||
:returns: `.Column` object or `None`
|
||||
|
||||
If the column isn't specialised for the given model field, it should
|
||||
return ``None``. This gives other columns the opportunity to do better.
|
||||
return `None`. This gives other columns the opportunity to do better.
|
||||
|
||||
If the column is specialised, it should return an instance of itself
|
||||
that's configured appropriately for the field.
|
||||
|
@ -215,22 +239,21 @@ class Column(object): # pylint: disable=R0902
|
|||
|
||||
class BoundColumn(object):
|
||||
"""
|
||||
A *run-time* version of :class:`.Column`. The difference between
|
||||
``BoundColumn`` and ``Column``, is that ``BoundColumn`` objects include the
|
||||
relationship between a ``Column`` and a :class:`.Table`. In practice, this
|
||||
means that a ``BoundColumn`` knows the *"variable name"* given to the
|
||||
``Column`` when it was declared on the ``Table``.
|
||||
A *run-time* version of `.Column`. The difference between
|
||||
`.BoundColumn` and `.Column`, is that `.BoundColumn` objects include the
|
||||
relationship between a `.Column` and a `.Table`. In practice, this
|
||||
means that a `.BoundColumn` knows the *"variable name"* given to the
|
||||
`.Column` when it was declared on the `.Table`.
|
||||
|
||||
For convenience, all :class:`.Column` properties are available from this
|
||||
class.
|
||||
For convenience, all `.Column` properties are available from thisclass.
|
||||
|
||||
:type table: :class:`.Table` object
|
||||
:type table: `.Table` object
|
||||
:param table: the table in which this column exists
|
||||
:type column: :class:`.Column` object
|
||||
:type column: `.Column` object
|
||||
:param column: the type of column
|
||||
:type name: ``basestring`` object
|
||||
:type name: `basestring` object
|
||||
:param name: the variable name of the column used to when defining the
|
||||
:class:`.Table`. In this example the name is ``age``:
|
||||
`.Table`. In this example the name is ``age``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -257,7 +280,7 @@ class BoundColumn(object):
|
|||
@property
|
||||
def attrs(self):
|
||||
"""
|
||||
Proxy to ``Column.attrs`` but injects some values of our own.
|
||||
Proxy to `.Column.attrs` but injects some values of our own.
|
||||
|
||||
A ``th`` and ``td`` are guaranteed to be defined (irrespective of
|
||||
what's actually defined in the column attrs. This makes writing
|
||||
|
@ -319,10 +342,10 @@ class BoundColumn(object):
|
|||
@property
|
||||
def order_by(self):
|
||||
"""
|
||||
Returns an :class:`OrderByTuple` of appropriately prefixed data source
|
||||
Returns an `.OrderByTuple` of appropriately prefixed data source
|
||||
keys used to sort this column.
|
||||
|
||||
See :meth:`.order_by_alias` for details.
|
||||
See `.order_by_alias` for details.
|
||||
"""
|
||||
if self.column.order_by is not None:
|
||||
order_by = self.column.order_by
|
||||
|
@ -334,13 +357,13 @@ class BoundColumn(object):
|
|||
@property
|
||||
def order_by_alias(self):
|
||||
"""
|
||||
Returns an :class:`OrderBy` describing the current state of ordering
|
||||
for this column.
|
||||
Returns an `OrderBy` describing the current state of ordering for this
|
||||
column.
|
||||
|
||||
The following attempts to explain the difference between ``order_by``
|
||||
and ``order_by_alias``.
|
||||
The following attempts to explain the difference between `order_by`
|
||||
and `.order_by_alias`.
|
||||
|
||||
``order_by_alias`` returns and ``OrderBy`` instance that's based on
|
||||
`.order_by_alias` returns and `.OrderBy` instance that's based on
|
||||
the *name* of the column, rather than the keys used to order the table
|
||||
data. Understanding the difference is essential.
|
||||
|
||||
|
@ -365,7 +388,7 @@ class BoundColumn(object):
|
|||
>>> table.columns["name"].order_by
|
||||
("-first_name", "-last_name")
|
||||
|
||||
The ``OrderBy`` returned has been patched to include an extra attribute
|
||||
The `OrderBy` returned has been patched to include an extra attribute
|
||||
``next``, which returns a version of the alias that would be
|
||||
transitioned to if the user toggles sorting on this column, e.g.::
|
||||
|
||||
|
@ -402,7 +425,7 @@ class BoundColumn(object):
|
|||
@property
|
||||
def orderable(self):
|
||||
"""
|
||||
Return a ``bool`` depending on whether this column supports ordering.
|
||||
Return a `bool` depending on whether this column supports ordering.
|
||||
"""
|
||||
if self.column.orderable is not None:
|
||||
return self.column.orderable
|
||||
|
@ -414,14 +437,14 @@ class BoundColumn(object):
|
|||
Return the verbose name for this column, or fallback to prettified
|
||||
column name.
|
||||
|
||||
If the table is using queryset data, then use the corresponding
|
||||
model field's ``verbose_name``. If it's traversing a relationship,
|
||||
If the table is using queryset data, then use the corresponding model
|
||||
field's `~.db.Field.verbose_name`. If it's traversing a relationship,
|
||||
then get the last field in the accessor (i.e. stop when the
|
||||
relationship turns from ORM relationships to object attributes [e.g.
|
||||
person.upper should stop at person]).
|
||||
|
||||
If the model field's ``verbose_name`` is a ``SafeData``, it's used
|
||||
unmodified.
|
||||
If the model field's `~.db.Field.verbose_name` is a
|
||||
`~.safestring.SafeData`, it's used unmodified.
|
||||
"""
|
||||
# Favor an explicit defined verbose_name
|
||||
if self.column.verbose_name:
|
||||
|
@ -452,44 +475,37 @@ class BoundColumn(object):
|
|||
@property
|
||||
def visible(self):
|
||||
"""
|
||||
Returns a :class:`bool` depending on whether this column is visible.
|
||||
Returns a `bool` depending on whether this column is visible.
|
||||
"""
|
||||
return self.column.visible
|
||||
|
||||
|
||||
class BoundColumns(object):
|
||||
"""
|
||||
Container for spawning :class:`.BoundColumn` objects.
|
||||
Container for spawning `.BoundColumn` objects.
|
||||
|
||||
This is bound to a table and provides its :attr:`.Table.columns` property.
|
||||
This is bound to a table and provides its `.Table.columns` property.
|
||||
It provides access to those columns in different ways (iterator,
|
||||
item-based, filtered and unfiltered etc), stuff that would not be possible
|
||||
with a simple iterator in the table class.
|
||||
|
||||
A ``BoundColumns`` object is a container for holding
|
||||
``BoundColumn`` objects. It provides methods that make accessing
|
||||
columns easier than if they were stored in a ``list`` or
|
||||
``dict``. ``Columns`` has a similar API to a ``dict`` (it
|
||||
actually uses a ``SortedDict`` interally).
|
||||
A `BoundColumns` object is a container for holding `BoundColumn` objects.
|
||||
It provides methods that make accessing columns easier than if they were
|
||||
stored in a `list` or `dict`. `Columns` has a similar API to a `dict` (it
|
||||
actually uses a `~django.utils.datastructures.SortedDict` interally).
|
||||
|
||||
At the moment you'll only come across this class when you access a
|
||||
:attr:`.Table.columns` property.
|
||||
`.Table.columns` property.
|
||||
|
||||
:type table: :class:`.Table` object
|
||||
:type table: `.Table` object
|
||||
:param table: the table containing the columns
|
||||
"""
|
||||
def __init__(self, table):
|
||||
self.table = table
|
||||
self.columns = SortedDict()
|
||||
for name, column in self.table.base_columns.iteritems():
|
||||
self.columns[name] = BoundColumn(self.table, column, name)
|
||||
|
||||
# Prepare each column's ``render`` function and its expected argument
|
||||
# so they can be easily called when each row is iterated.
|
||||
for name, bound_column in self.iteritems():
|
||||
bound_column.render = getattr(self.table, 'render_' + bound_column.name,
|
||||
bound_column.column.render)
|
||||
bound_column._render_args = getargspec(bound_column.render).args[1:]
|
||||
for name, column in table.base_columns.iteritems():
|
||||
self.columns[name] = bc = BoundColumn(table, column, name)
|
||||
bc.render = getattr(table, 'render_' + name, column.render)
|
||||
|
||||
def iternames(self):
|
||||
return (name for name, column in self.iteritems())
|
||||
|
@ -499,7 +515,7 @@ class BoundColumns(object):
|
|||
|
||||
def iterall(self):
|
||||
"""
|
||||
Return an iterator that exposes all :class:`.BoundColumn` objects,
|
||||
Return an iterator that exposes all `.BoundColumn` objects,
|
||||
regardless of visiblity or sortability.
|
||||
"""
|
||||
return (column for name, column in self.iteritems())
|
||||
|
@ -510,11 +526,11 @@ class BoundColumns(object):
|
|||
def iteritems(self):
|
||||
"""
|
||||
Return an iterator of ``(name, column)`` pairs (where ``column`` is a
|
||||
:class:`.BoundColumn` object).
|
||||
`BoundColumn`).
|
||||
|
||||
This method is the mechanism for retrieving columns that takes into
|
||||
consideration all of the ordering and filtering modifiers that a table
|
||||
supports (e.g. ``exclude`` and ``sequence``).
|
||||
supports (e.g. `~Table.Meta.exclude` and `~Table.Meta.sequence`).
|
||||
"""
|
||||
for name in self.table.sequence:
|
||||
if name not in self.table.exclude:
|
||||
|
@ -525,7 +541,7 @@ class BoundColumns(object):
|
|||
|
||||
def iterorderable(self):
|
||||
"""
|
||||
Same as :meth:`.BoundColumns.all` but only returns orderable columns.
|
||||
Same as `BoundColumns.all` but only returns orderable columns.
|
||||
|
||||
This is useful in templates, where iterating over the full
|
||||
set and checking ``{% if column.sortable %}`` can be problematic in
|
||||
|
@ -549,8 +565,8 @@ class BoundColumns(object):
|
|||
|
||||
def itervisible(self):
|
||||
"""
|
||||
Same as :meth:`.iterorderable` but only returns visible
|
||||
:class:`.BoundColumn` objects.
|
||||
Same as `.iterorderable` but only returns visible `.BoundColumn`
|
||||
objects.
|
||||
|
||||
This is geared towards table rendering.
|
||||
"""
|
||||
|
@ -561,16 +577,15 @@ class BoundColumns(object):
|
|||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Convenience API, alias of :meth:`.itervisible`.
|
||||
Convenience API, alias of `.itervisible`.
|
||||
"""
|
||||
return self.itervisible()
|
||||
|
||||
def __contains__(self, item):
|
||||
"""
|
||||
Check if a column is contained within a :class:`.Columns` object.
|
||||
Check if a column is contained within a `Columns` object.
|
||||
|
||||
*item* can either be a :class:`.BoundColumn` object, or the name of a
|
||||
column.
|
||||
*item* can either be a `BoundColumn` object, or the name of a column.
|
||||
"""
|
||||
if isinstance(item, basestring):
|
||||
return item in self.iternames()
|
||||
|
@ -587,7 +602,7 @@ class BoundColumns(object):
|
|||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Retrieve a specific :class:`BoundColumn` object.
|
||||
Retrieve a specific `BoundColumn` object.
|
||||
|
||||
*index* can either be 0-indexed or the name of a column
|
||||
|
||||
|
|
|
@ -12,15 +12,15 @@ class BooleanColumn(Column):
|
|||
"""
|
||||
A column suitable for rendering boolean data.
|
||||
|
||||
:param null: is ``None`` different from ``False``?
|
||||
:type null: bool
|
||||
:param null: is `None` different from `False`?
|
||||
:type null: `bool`
|
||||
:param yesno: text to display for True/False values, comma separated
|
||||
:type yesno: iterable or string
|
||||
|
||||
Rendered values are wrapped in a ``<span>`` to allow customisation by
|
||||
themes. By default the span is given the class ``true``, ``false``.
|
||||
|
||||
In addition to ``attrs`` keys supported by ``Column``, the following are
|
||||
In addition to *attrs* keys supported by `.Column`, the following are
|
||||
available:
|
||||
|
||||
- *span* -- adds attributes to the <span> tag
|
||||
|
|
|
@ -9,7 +9,7 @@ from .base import Column, library
|
|||
@library.register
|
||||
class CheckBoxColumn(Column):
|
||||
"""
|
||||
A subclass of :class:`.Column` that renders as a checkbox form input.
|
||||
A subclass of `.Column` that renders as a checkbox form input.
|
||||
|
||||
This column allows a user to *select* a set of rows. The selection
|
||||
information can then be used to apply some operation (e.g. "delete") onto
|
||||
|
@ -22,8 +22,8 @@ class CheckBoxColumn(Column):
|
|||
This class implements some sensible defaults:
|
||||
|
||||
- HTML input's ``name`` attribute is the :term:`column name` (can override
|
||||
via ``attrs`` argument).
|
||||
- ``orderable`` defaults to :const:`False`.
|
||||
via *attrs* argument).
|
||||
- *orderable* defaults to `False`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -32,7 +32,7 @@ class CheckBoxColumn(Column):
|
|||
implemented. If you want something to actually happen, you'll need to
|
||||
implement that yourself.
|
||||
|
||||
In addition to ``attrs`` keys supported by ``Column``, the following are
|
||||
In addition to *attrs* keys supported by `.Column`, the following are
|
||||
available:
|
||||
|
||||
- *input* -- ``<input>`` elements in both ``<td>`` and ``<th>``.
|
||||
|
|
|
@ -12,10 +12,10 @@ class DateColumn(TemplateColumn):
|
|||
|
||||
:param format: format string in same format as Django's ``date`` template
|
||||
filter (optional)
|
||||
:type format: ``unicode``
|
||||
:param short: if ``format`` is not specified, use Django's
|
||||
:type format: `unicode`
|
||||
:param short: if *format* is not specified, use Django's
|
||||
``SHORT_DATE_FORMAT`` setting, otherwise use ``DATE_FORMAT``
|
||||
:type short: ``bool``
|
||||
:type short: `bool`
|
||||
"""
|
||||
def __init__(self, format=None, short=True, *args, **kwargs): # pylint: disable=W0622
|
||||
if format is None:
|
||||
|
|
|
@ -11,10 +11,10 @@ class DateTimeColumn(TemplateColumn):
|
|||
A column that renders datetimes in the local timezone.
|
||||
|
||||
:param format: format string for datetime (optional)
|
||||
:type format: ``unicode``
|
||||
:param short: if ``format`` is not specifid, use Django's
|
||||
:type format: `unicode`
|
||||
:param short: if *format* is not specifid, use Django's
|
||||
``SHORT_DATETIME_FORMAT``, else ``DATETIME_FORMAT``
|
||||
:type short: ``bool``
|
||||
:type short: `bool`
|
||||
"""
|
||||
def __init__(self, format=None, short=True, *args, **kwargs): # pylint: disable=W0622
|
||||
if format is None:
|
||||
|
|
|
@ -8,11 +8,11 @@ from .linkcolumn import BaseLinkColumn
|
|||
@library.register
|
||||
class EmailColumn(BaseLinkColumn):
|
||||
"""
|
||||
A subclass of :class:`.BaseLinkColumn` that renders the cell value as a hyperlink.
|
||||
A subclass of `.BaseLinkColumn` that renders the cell value as a hyperlink.
|
||||
|
||||
It's common to have a email value in a row hyperlinked to other page.
|
||||
|
||||
:param attrs: a :class:`dict` of HTML attributes that are added to
|
||||
:param attrs: a `dict` of HTML attributes that are added to
|
||||
the rendered ``<a href="...">...</a>`` tag
|
||||
|
||||
Example:
|
||||
|
|
|
@ -10,19 +10,25 @@ from .base import Column, library
|
|||
@library.register
|
||||
class FileColumn(Column):
|
||||
"""
|
||||
Renders a FieldFile (or other storage backend File) as a link.
|
||||
Attempts to render `.FieldFile` (or other storage backend `.File`) as a
|
||||
hyperlink.
|
||||
|
||||
In addition to ``attrs`` keys supported by ``Column``, the following are
|
||||
available:
|
||||
When the file is accessible via a URL, the file is rendered as a
|
||||
hyperlink. The `.basename` is used as the text::
|
||||
|
||||
<a href="/media/path/to/receipt.pdf" title="path/to/receipt.pdf">receipt.pdf</a>
|
||||
|
||||
When unable to determine the URL, a ``span`` is used instead::
|
||||
|
||||
<span title="path/to/receipt.pdf">receipt.pdf</span>
|
||||
|
||||
`.Column.attrs` keys ``a`` and ``span`` can be used to add additional attributes.
|
||||
|
||||
:type verify_exists: bool
|
||||
:param verify_exists: *try* to determine if the file actually exists.
|
||||
:param verify_exists: attempt to determine if the file exists
|
||||
|
||||
- *a* -- ``<a>`` elements in ``<td>``
|
||||
- *span* -- ``<span>`` elements in ``<td>`` (missing files)
|
||||
|
||||
if *verify_exists*, the HTML class ``exists`` or ``missing`` is added to
|
||||
the element.
|
||||
If *verify_exists*, the HTML class ``exists`` or ``missing`` is added to
|
||||
the element to indicate the integrity of the storage.
|
||||
"""
|
||||
def __init__(self, verify_exists=True, **kwargs):
|
||||
self.verify_exists = True
|
||||
|
|
|
@ -12,7 +12,7 @@ class BaseLinkColumn(Column):
|
|||
"""
|
||||
The base for other columns that render links.
|
||||
|
||||
Adds support for an ``a`` key in ``attrs`` which is added to the rendered
|
||||
Adds support for an ``a`` key in *attrs** which is added to the rendered
|
||||
``<a href="...">`` tag.
|
||||
"""
|
||||
def __init__(self, attrs=None, *args, **kwargs):
|
||||
|
@ -53,22 +53,22 @@ class LinkColumn(BaseLinkColumn):
|
|||
dedicated to that record.
|
||||
|
||||
The first arguments are identical to that of
|
||||
:func:`django.core.urlresolvers.reverse` and allows an internal URL to be
|
||||
described. The last argument ``attrs`` allows custom HTML attributes to
|
||||
`~django.core.urlresolvers.reverse` and allows an internal URL to be
|
||||
described. The last argument *attrs* allows custom HTML attributes to
|
||||
be added to the rendered ``<a href="...">`` tag.
|
||||
|
||||
:param viewname: See :func:`django.core.urlresolvers.reverse`.
|
||||
:param urlconf: See :func:`django.core.urlresolvers.reverse`.
|
||||
:param args: See :func:`django.core.urlresolvers.reverse`. **
|
||||
:param kwargs: See :func:`django.core.urlresolvers.reverse`. **
|
||||
:param current_app: See :func:`django.core.urlresolvers.reverse`.
|
||||
:param attrs: a :class:`dict` of HTML attributes that are added to
|
||||
:param viewname: See `~django.core.urlresolvers.reverse`.
|
||||
:param urlconf: See `~django.core.urlresolvers.reverse`.
|
||||
:param args: See `~django.core.urlresolvers.reverse`. **
|
||||
:param kwargs: See `~django.core.urlresolvers.reverse`. **
|
||||
:param current_app: See `~django.core.urlresolvers.reverse`.
|
||||
:param attrs: a `dict` of HTML attributes that are added to
|
||||
the rendered ``<input type="checkbox" .../>`` tag
|
||||
|
||||
** In order to create a link to a URL that relies on information in the
|
||||
current row, :class:`.Accessor` objects can be used in the ``args`` or
|
||||
``kwargs`` arguments. The accessor will be resolved using the row's record
|
||||
before ``reverse()`` is called.
|
||||
current row, `.Accessor` objects can be used in the *args* or
|
||||
*kwargs* arguments. The accessor will be resolved using the row's record
|
||||
before `~django.core.urlresolvers.reverse` is called.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -89,7 +89,7 @@ class LinkColumn(BaseLinkColumn):
|
|||
class PeopleTable(tables.Table):
|
||||
name = tables.LinkColumn('people_detail', args=[A('pk')])
|
||||
|
||||
In addition to ``attrs`` keys supported by ``Column``, the following are
|
||||
In addition to *attrs* keys supported by `.Column`, the following are
|
||||
available:
|
||||
|
||||
- *a* -- ``<a>`` elements in ``<td>``.
|
||||
|
|
|
@ -8,7 +8,7 @@ from .base import Column, library
|
|||
@library.register
|
||||
class TemplateColumn(Column):
|
||||
"""
|
||||
A subclass of :class:`.Column` that renders some template code to use as
|
||||
A subclass of `.Column` that renders some template code to use as
|
||||
the cell value.
|
||||
|
||||
:type template_code: `unicode`
|
||||
|
@ -16,12 +16,12 @@ class TemplateColumn(Column):
|
|||
:type template_name: `unicode`
|
||||
:param template_name: the name of the template to render
|
||||
|
||||
A :class:`django.templates.Template` object is created from the
|
||||
A `~django.template.Template` object is created from the
|
||||
*template_code* or *template_name* and rendered with a context containing:
|
||||
|
||||
- `record` -- data record for the current row
|
||||
- `value` -- value from `record` that corresponds to the current column
|
||||
- `default` -- appropriate default value to use as fallback
|
||||
- *record* -- data record for the current row
|
||||
- *value* -- value from `record` that corresponds to the current column
|
||||
- *default* -- appropriate default value to use as fallback
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -37,7 +37,7 @@ class TemplateColumn(Column):
|
|||
.. important::
|
||||
|
||||
In order to use template tags or filters that require a
|
||||
``RequestContext``, the table **must** be rendered via
|
||||
`~django.template.RequestContext`, the table **must** be rendered via
|
||||
:ref:`{% render_table %} <template-tags.render_table>`.
|
||||
"""
|
||||
empty_values = ()
|
||||
|
|
|
@ -8,26 +8,19 @@ from .linkcolumn import BaseLinkColumn
|
|||
@library.register
|
||||
class URLColumn(BaseLinkColumn):
|
||||
"""
|
||||
A subclass of :class:`.BaseLinkColumn` that renders the cell value as a hyperlink.
|
||||
Renders URL values as hyperlinks.
|
||||
|
||||
It's common to have a URL value in a row hyperlinked to other page.
|
||||
Example::
|
||||
|
||||
:param attrs: a :class:`dict` of HTML attributes that are added to
|
||||
the rendered ``<a href="...">...</a>`` tag
|
||||
>>> class CompaniesTable(tables.Table):
|
||||
... www = tables.URLColumn()
|
||||
...
|
||||
>>> table = CompaniesTable([{"www": "http://google.com"}])
|
||||
>>> table.rows[0]["www"]
|
||||
u'<a href="http://google.com">http://google.com</a>'
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# models.py
|
||||
class Person(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
web = models.URLField()
|
||||
|
||||
# tables.py
|
||||
class PeopleTable(tables.Table):
|
||||
name = tables.Column()
|
||||
web = tables.URLColumn()
|
||||
Additional attributes for the ``<a>`` tag can be specified via
|
||||
``attrs['a']``.
|
||||
|
||||
"""
|
||||
def render(self, value):
|
||||
|
|
|
@ -6,20 +6,22 @@ class RequestConfig(object):
|
|||
"""
|
||||
A configurator that uses request data to setup a table.
|
||||
|
||||
:type paginate: ``dict`` or ``bool``
|
||||
:type paginate: `dict` or `bool`
|
||||
:param paginate: indicates whether to paginate, and if so, what default
|
||||
values to use. If the value evaluates to ``False``,
|
||||
pagination will be disabled. A ``dict`` can be used to
|
||||
values to use. If the value evaluates to `False`,
|
||||
pagination will be disabled. A `dict` can be used to
|
||||
specify default values for the call to
|
||||
:meth:`.tables.Table.paginate` (e.g. to define a default
|
||||
``per_page`` value).
|
||||
`~.tables.Table.paginate` (e.g. to define a default
|
||||
*per_page* value).
|
||||
|
||||
A special ``silent`` item can be used to enable automatic
|
||||
A special *silent* item can be used to enable automatic
|
||||
handling of pagination exceptions using the following
|
||||
algorithm:
|
||||
|
||||
- If ``PageNotAnInteger`` is raised, show the first page.
|
||||
- If ``EmptyPage`` is raised, show the last page.
|
||||
- If `~django.core.paginator.PageNotAnInteger`` is raised,
|
||||
show the first page.
|
||||
- If `~django.core.paginator.EmptyPage` is raised, show
|
||||
the last page.
|
||||
|
||||
"""
|
||||
def __init__(self, request, paginate=True):
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# coding: utf-8
|
||||
from django.db import models
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from .utils import A
|
||||
from .utils import A, getargspec
|
||||
|
||||
|
||||
class BoundRow(object):
|
||||
"""
|
||||
Represents a *specific* row in a table.
|
||||
|
||||
:class:`.BoundRow` objects are a container that make it easy to access the
|
||||
`.BoundRow` objects are a container that make it easy to access the
|
||||
final 'rendered' values for cells in a row. You can simply iterate over a
|
||||
:class:`.BoundRow` object and it will take care to return values rendered
|
||||
using the correct method (e.g. :meth:`.Column.render_FOO`)
|
||||
`.BoundRow` object and it will take care to return values rendered
|
||||
using the correct method (e.g. :ref:`table.render_FOO`)
|
||||
|
||||
To access the rendered value of each cell in a row, just iterate over it:
|
||||
|
||||
|
@ -58,10 +58,10 @@ class BoundRow(object):
|
|||
...
|
||||
KeyError: 'c'
|
||||
|
||||
:param table: is the :class:`Table` in which this row exists.
|
||||
:param table: is the `.Table` in which this row exists.
|
||||
:param record: a single record from the :term:`table data` that is used to
|
||||
populate the row. A record could be a :class:`Model` object,
|
||||
a :class:`dict`, or something else.
|
||||
populate the row. A record could be a `~django.db.Model`
|
||||
object, a `dict`, or something else.
|
||||
|
||||
"""
|
||||
def __init__(self, record, table):
|
||||
|
@ -70,7 +70,7 @@ class BoundRow(object):
|
|||
|
||||
@property
|
||||
def table(self):
|
||||
"""The associated :class:`.Table` object."""
|
||||
"""The associated `.Table` object."""
|
||||
return self._table
|
||||
|
||||
@property
|
||||
|
@ -86,7 +86,7 @@ class BoundRow(object):
|
|||
Iterate over the rendered values for cells in the row.
|
||||
|
||||
Under the hood this method just makes a call to
|
||||
:meth:`.BoundRow.__getitem__` for each cell.
|
||||
`.BoundRow.__getitem__` for each cell.
|
||||
"""
|
||||
for column, value in self.items():
|
||||
# this uses __getitem__, using the name (rather than the accessor)
|
||||
|
@ -124,19 +124,26 @@ class BoundRow(object):
|
|||
if value in bound_column.column.empty_values:
|
||||
return bound_column.default
|
||||
|
||||
kwargs = {
|
||||
'value': lambda: value,
|
||||
'record': lambda: self.record,
|
||||
'column': lambda: bound_column.column,
|
||||
'bound_column': lambda: bound_column,
|
||||
'bound_row': lambda: self,
|
||||
'table': lambda: self._table,
|
||||
available = {
|
||||
'value': value,
|
||||
'record': self.record,
|
||||
'column': bound_column.column,
|
||||
'bound_column': bound_column,
|
||||
'bound_row': self,
|
||||
'table': self._table,
|
||||
}
|
||||
expected = {}
|
||||
|
||||
expected_kwargs = {}
|
||||
for arg_name in bound_column._render_args:
|
||||
expected_kwargs[arg_name] = kwargs[arg_name]()
|
||||
return bound_column.render(**expected_kwargs)
|
||||
# provide only the arguments expected by `render`
|
||||
argspec = getargspec(bound_column.render)
|
||||
if argspec.keywords:
|
||||
expected = available
|
||||
else:
|
||||
for key, value in available.items():
|
||||
if key in argspec.args[1:]:
|
||||
expected[key] = value
|
||||
|
||||
return bound_column.render(**expected)
|
||||
|
||||
def __contains__(self, item):
|
||||
"""Check by both row object and column name."""
|
||||
|
@ -149,7 +156,7 @@ class BoundRow(object):
|
|||
"""
|
||||
Returns iterator yielding ``(bound_column, cell)`` pairs.
|
||||
|
||||
``cell`` is ``row[name]`` -- the rendered unicode value that should be
|
||||
*cell* is ``row[name]`` -- the rendered unicode value that should be
|
||||
``rendered within ``<td>``.
|
||||
"""
|
||||
for column in self.table.columns:
|
||||
|
@ -158,12 +165,12 @@ class BoundRow(object):
|
|||
|
||||
class BoundRows(object):
|
||||
"""
|
||||
Container for spawning :class:`.BoundRow` objects.
|
||||
Container for spawning `.BoundRow` objects.
|
||||
|
||||
:param data: iterable of records
|
||||
:param table: the table in which the rows exist
|
||||
|
||||
This is used for :attr:`.Table.rows`.
|
||||
This is used for `.Table.rows`.
|
||||
"""
|
||||
def __init__(self, data, table):
|
||||
self.data = data
|
||||
|
@ -178,8 +185,8 @@ class BoundRows(object):
|
|||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
Slicing returns a new :class:`.BoundRows` instance, indexing returns
|
||||
a single :class:`.BoundRow` instance.
|
||||
Slicing returns a new `.BoundRows` instance, indexing returns a single
|
||||
`.BoundRow` instance.
|
||||
"""
|
||||
container = BoundRows if isinstance(key, slice) else BoundRow
|
||||
return container(self.data[key], table=self.table)
|
||||
|
|
|
@ -21,8 +21,8 @@ class TableData(object):
|
|||
Exposes a consistent API for :term:`table data`.
|
||||
|
||||
:param data: iterable containing data for each row
|
||||
:type data: :class:`QuerySet` or :class:`list` of :class:`dict`
|
||||
:param table: :class:`.Table` object
|
||||
:type data: `~django.db.query.QuerySet` or `list` of `dict`
|
||||
:param table: `.Table` object
|
||||
"""
|
||||
def __init__(self, data, table):
|
||||
self.table = table
|
||||
|
@ -81,7 +81,7 @@ class TableData(object):
|
|||
:param aliases: optionally prefixed names of columns ('-' indicates
|
||||
descending order) in order of significance with
|
||||
regard to data ordering.
|
||||
:type aliases: :class:`~.utils.OrderByTuple`
|
||||
:type aliases: `~.utils.OrderByTuple`
|
||||
"""
|
||||
accessors = []
|
||||
for alias in aliases:
|
||||
|
@ -109,7 +109,7 @@ class TableData(object):
|
|||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
Slicing returns a new :class:`.TableData` instance, indexing returns a
|
||||
Slicing returns a new `.TableData` instance, indexing returns a
|
||||
single record.
|
||||
"""
|
||||
return self.data[key]
|
||||
|
@ -119,9 +119,9 @@ class TableData(object):
|
|||
"""
|
||||
The full (singular) name for the data.
|
||||
|
||||
Queryset data has its model's ``Meta.verbose_name`` honored. List data
|
||||
is checked for a ``verbose_name`` attribute, and falls back to using
|
||||
``"item"``.
|
||||
Queryset data has its model's `~django.db.Model.Meta.verbose_name`
|
||||
honored. List data is checked for a ``verbose_name`` attribute, and
|
||||
falls back to using ``"item"``.
|
||||
"""
|
||||
if hasattr(self, "queryset"):
|
||||
return self.queryset.model._meta.verbose_name
|
||||
|
@ -132,7 +132,7 @@ class TableData(object):
|
|||
"""
|
||||
The full (plural) name of the data.
|
||||
|
||||
This uses the same approach as ``verbose_name``.
|
||||
This uses the same approach as `.verbose_name`.
|
||||
"""
|
||||
if hasattr(self, "queryset"):
|
||||
return self.queryset.model._meta.verbose_name_plural
|
||||
|
@ -141,9 +141,9 @@ class TableData(object):
|
|||
|
||||
class DeclarativeColumnsMetaclass(type):
|
||||
"""
|
||||
Metaclass that converts Column attributes on the class to a dictionary
|
||||
called ``base_columns``, taking into account parent class ``base_columns``
|
||||
as well.
|
||||
Metaclass that converts `.Column` objects defined on a class to the
|
||||
dictionary `.Table.base_columns`, taking into account parent class
|
||||
``base_columns`` as well.
|
||||
"""
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
|
||||
|
@ -198,12 +198,12 @@ class DeclarativeColumnsMetaclass(type):
|
|||
|
||||
class TableOptions(object):
|
||||
"""
|
||||
Extracts and exposes options for a :class:`.Table` from a ``class Meta``
|
||||
when the table is defined. See ``Table`` for documentation on the impact of
|
||||
Extracts and exposes options for a `.Table` from a `.Table.Meta`
|
||||
when the table is defined. See `.Table` for documentation on the impact of
|
||||
variables in this class.
|
||||
|
||||
:param options: options for a table
|
||||
:type options: :class:`Meta` on a :class:`.Table`
|
||||
:type options: `.Table.Meta` on a `.Table`
|
||||
"""
|
||||
# pylint: disable=R0902
|
||||
def __init__(self, options=None):
|
||||
|
@ -233,62 +233,125 @@ class TableOptions(object):
|
|||
|
||||
class Table(StrAndUnicode):
|
||||
"""
|
||||
A collection of columns, plus their associated data rows.
|
||||
A representation of a table.
|
||||
|
||||
:type attrs: dict
|
||||
:param attrs: A mapping of attributes to values that will be added to the
|
||||
HTML ``<table>`` tag.
|
||||
|
||||
:type data: list or QuerySet-like
|
||||
:param data: The :term:`table data`.
|
||||
.. attribute:: attrs
|
||||
|
||||
:type exclude: iterable
|
||||
:param exclude: A list of columns to be excluded from this table.
|
||||
HTML attributes to add to the ``<table>`` tag.
|
||||
|
||||
:type order_by: None, tuple or string
|
||||
:param order_by: sort the table based on these columns prior to display.
|
||||
(default :attr:`.Table.Meta.order_by`)
|
||||
:type: `dict`
|
||||
|
||||
:type order_by_field: string or None
|
||||
:param order_by_field: The name of the querystring field used to control
|
||||
the table ordering.
|
||||
When accessing the attribute, the value is always returned as an
|
||||
`.AttributeDict` to allow easily conversion to HTML.
|
||||
|
||||
:type page_field: string or None
|
||||
:param page_field: The name of the querystring field used to control which
|
||||
page of the table is displayed (used when a table is paginated).
|
||||
|
||||
:type per_page_field: string or None
|
||||
:param per_page_field: The name of the querystring field used to control
|
||||
how many records are displayed on each page of the table.
|
||||
.. attribute:: columns
|
||||
|
||||
:type prefix: string
|
||||
:param prefix: A prefix used on querystring arguments to allow multiple
|
||||
tables to be used on a single page, without having conflicts
|
||||
between querystring arguments. Depending on how the table is
|
||||
rendered, will determine how the prefix is used. For example ``{%
|
||||
render_table %}`` uses ``<prefix>-<argument>``.
|
||||
The columns in the table.
|
||||
|
||||
:type sequence: iterable
|
||||
:param sequence: The sequence/order of columns the columns (from left to
|
||||
right). Items in the sequence must be column names, or the
|
||||
*remaining items* symbol marker ``"..."`` (string containing three
|
||||
periods). If this marker is used, not all columns need to be
|
||||
defined.
|
||||
:type: `.BoundColumns`
|
||||
|
||||
:type orderable: bool
|
||||
:param orderable: Enable/disable column ordering on this table
|
||||
|
||||
:type template: string
|
||||
:param template: the template to render when using {% render_table %}
|
||||
(default ``django_tables2/table.html``)
|
||||
.. attribute:: default
|
||||
|
||||
:type empty_text: string
|
||||
:param empty_text: Empty text to render when the table has no data.
|
||||
(default :attr:`.Table.Meta.empty_text`)
|
||||
Text to render in empty cells (determined by `.Column.empty_values`,
|
||||
default `.Table.Meta.default`)
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: empty_text
|
||||
|
||||
Empty text to render when the table has no data. (default
|
||||
`.Table.Meta.empty_text`)
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: exclude
|
||||
|
||||
The names of columns that shouldn't be included in the table.
|
||||
|
||||
:type: iterable of `unicode`
|
||||
|
||||
|
||||
.. attribute:: order_by_field
|
||||
|
||||
If not `None`, defines the name of the *order by* querystring field.
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: page
|
||||
|
||||
The current page in the context of pagination.
|
||||
|
||||
Added during the call to `.Table.paginate`.
|
||||
|
||||
|
||||
.. attribute:: page_field
|
||||
|
||||
If not `None`, defines the name of the *current page* querystring
|
||||
field.
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: paginator
|
||||
|
||||
The current paginator for the table.
|
||||
|
||||
Added during the call to `.Table.paginate`.
|
||||
|
||||
|
||||
.. attribute:: per_page_field
|
||||
|
||||
If not `None`, defines the name of the *per page* querystring field.
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: prefix
|
||||
|
||||
A prefix for querystring fields to avoid name-clashes when using
|
||||
multiple tables on a single page.
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
|
||||
.. attribute:: rows
|
||||
|
||||
The rows of the table (ignoring pagination).
|
||||
|
||||
:type: `.BoundRows`
|
||||
|
||||
|
||||
.. attribute:: sequence
|
||||
|
||||
The sequence/order of columns the columns (from left to right).
|
||||
|
||||
:type: iterable
|
||||
|
||||
Items in the sequence must be :term:`column names <column name>`, or
|
||||
``"..."`` (string containing three periods). ``...`` can be used as a
|
||||
catch-all for columns that aren't specified.
|
||||
|
||||
|
||||
.. attribute:: orderable
|
||||
|
||||
Enable/disable column ordering on this table
|
||||
|
||||
:type: `bool`
|
||||
|
||||
|
||||
.. attribute:: template
|
||||
|
||||
The template to render when using ``{% render_table %}`` (default
|
||||
``"django_tables2/table.html"``)
|
||||
|
||||
:type: `unicode`
|
||||
|
||||
:type default: unicode
|
||||
:param default: Text to render in empty cells (determined by
|
||||
:attr:`Column.empty_values`, default :attr:`.Table.Meta.default`)
|
||||
"""
|
||||
__metaclass__ = DeclarativeColumnsMetaclass
|
||||
TableDataClass = TableData
|
||||
|
@ -369,12 +432,6 @@ class Table(StrAndUnicode):
|
|||
|
||||
@property
|
||||
def attrs(self):
|
||||
"""
|
||||
The attributes that should be applied to the ``<table>`` tag when
|
||||
rendering HTML.
|
||||
|
||||
:rtype: :class:`~.utils.AttributeDict` object.
|
||||
"""
|
||||
return self._attrs if self._attrs is not None else self._meta.attrs
|
||||
|
||||
@attrs.setter
|
||||
|
@ -437,17 +494,18 @@ class Table(StrAndUnicode):
|
|||
Paginates the table using a paginator and creates a ``page`` property
|
||||
containing information for the current page.
|
||||
|
||||
:type klass: Paginator ``class``
|
||||
:type klass: Paginator class
|
||||
:param klass: a paginator class to paginate the results
|
||||
:type per_page: ``int``
|
||||
:type per_page: `int`
|
||||
:param per_page: how many records are displayed on each page
|
||||
:type page: ``int``
|
||||
:type page: `int`
|
||||
:param page: which page should be displayed.
|
||||
|
||||
Extra arguments are passed to ``Paginator``.
|
||||
Extra arguments are passed to the paginator.
|
||||
|
||||
Pagination exceptions (``EmptyPage`` and ``PageNotAnInteger``) may be
|
||||
raised from this method and should be handled by the caller.
|
||||
Pagination exceptions (`~django.core.paginator.EmptyPage` and
|
||||
`~django.core.paginator.PageNotAnInteger`) may be raised from this
|
||||
method and should be handled by the caller.
|
||||
"""
|
||||
per_page = per_page or self._meta.per_page
|
||||
self.paginator = klass(self.rows, per_page, *args, **kwargs)
|
||||
|
|
|
@ -21,7 +21,7 @@ kwarg_re = re.compile(r"(?:(.+)=)?(.+)")
|
|||
|
||||
def token_kwargs(bits, parser):
|
||||
"""
|
||||
Based on Django's ``django.template.defaulttags.token_kwargs``, but with a
|
||||
Based on Django's `~django.template.defaulttags.token_kwargs`, but with a
|
||||
few changes:
|
||||
|
||||
- No legacy mode.
|
||||
|
@ -70,7 +70,7 @@ def set_url_param(parser, token):
|
|||
{% set_url_param name="help" age=20 %}
|
||||
?name=help&age=20
|
||||
|
||||
**Deprecated** as of 0.7.0, use ``querystring``.
|
||||
**Deprecated** as of 0.7.0, use `querystring`.
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
qschanges = {}
|
||||
|
@ -207,7 +207,7 @@ def render_table(parser, token):
|
|||
"""
|
||||
Render a HTML table.
|
||||
|
||||
The tag can be given either a ``Table`` object, or a queryset. An optional
|
||||
The tag can be given either a `.Table` object, or a queryset. An optional
|
||||
second argument can specify the template to use.
|
||||
|
||||
Example::
|
||||
|
@ -216,7 +216,7 @@ def render_table(parser, token):
|
|||
{% render_table table "custom.html" %}
|
||||
{% render_table user_queryset %}
|
||||
|
||||
When given a queryset, a ``Table`` class is generated dynamically as
|
||||
When given a queryset, a `.Table` class is generated dynamically as
|
||||
follows::
|
||||
|
||||
class OnTheFlyTable(tables.Table):
|
||||
|
@ -224,10 +224,10 @@ def render_table(parser, token):
|
|||
model = queryset.model
|
||||
attrs = {"class": "paleblue"}
|
||||
|
||||
For configuration beyond this, a ``Table`` class must be manually defined,
|
||||
For configuration beyond this, a `.Table` class must be manually defined,
|
||||
instantiated, and passed to this tag.
|
||||
|
||||
The context should include a ``request`` variable containing the current
|
||||
The context should include a *request* variable containing the current
|
||||
request. This allows pagination URLs to be created without clobbering the
|
||||
existing querystring.
|
||||
"""
|
||||
|
@ -266,8 +266,9 @@ def title(value):
|
|||
"""
|
||||
A slightly better title template filter.
|
||||
|
||||
Same as Django's builtin ``title`` filter, but operates on individual words
|
||||
and leaves words unchanged if they already have a capital letter.
|
||||
Same as Django's builtin `~django.template.defaultfilters.title` filter,
|
||||
but operates on individual words and leaves words unchanged if they already
|
||||
have a capital letter.
|
||||
"""
|
||||
title_word = lambda w: w if RE_UPPERCASE.search(w) else old_title(w)
|
||||
return re.sub('(\S+)', lambda m: title_word(m.group(0)), value)
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
# coding: utf-8
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.utils.functional import curry
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.test.client import FakePayload
|
||||
from itertools import chain
|
||||
from itertools import chain, ifilter
|
||||
import inspect
|
||||
from StringIO import StringIO
|
||||
import warnings
|
||||
|
||||
|
||||
class Sequence(list):
|
||||
"""
|
||||
Represents a column sequence, e.g. ("first_name", "...", "last_name")
|
||||
Represents a column sequence, e.g. ``("first_name", "...", "last_name")``
|
||||
|
||||
This is used to represent ``Table.Meta.sequence`` or the Table
|
||||
constructors's ``sequence`` keyword argument.
|
||||
This is used to represent `.Table.Meta.sequence` or the `.Table`
|
||||
constructors's *sequence* keyword argument.
|
||||
|
||||
The sequence must be a list of column names and is used to specify the
|
||||
order of the columns on a table. Optionally a "..." item can be inserted,
|
||||
|
@ -23,10 +25,10 @@ class Sequence(list):
|
|||
"""
|
||||
def expand(self, columns):
|
||||
"""
|
||||
Expands the "..." item in the sequence into the appropriate column
|
||||
Expands the ``"..."`` item in the sequence into the appropriate column
|
||||
names that should be placed there.
|
||||
|
||||
:raises: ``ValueError`` if the sequence is invalid for the columns.
|
||||
:raises: `ValueError` if the sequence is invalid for the columns.
|
||||
"""
|
||||
ellipses = self.count("...")
|
||||
if ellipses > 1:
|
||||
|
@ -52,8 +54,8 @@ class Sequence(list):
|
|||
|
||||
class OrderBy(str):
|
||||
"""
|
||||
A single item in an :class:`.OrderByTuple` object. This class is
|
||||
essentially just a :class:`str` with some extra properties.
|
||||
A single item in an `.OrderByTuple` object. This class is
|
||||
essentially just a `str` with some extra properties.
|
||||
"""
|
||||
@property
|
||||
def bare(self):
|
||||
|
@ -65,14 +67,14 @@ class OrderBy(str):
|
|||
|
||||
Example: ``age`` is the bare form of ``-age``
|
||||
|
||||
:rtype: :class:`.OrderBy` object
|
||||
:rtype: `.OrderBy` object
|
||||
"""
|
||||
return OrderBy(self[1:]) if self[:1] == '-' else self
|
||||
|
||||
@property
|
||||
def opposite(self):
|
||||
"""
|
||||
Return an :class:`.OrderBy` object with an opposite sort influence.
|
||||
Return an `.OrderBy` object with an opposite sort influence.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -82,35 +84,35 @@ class OrderBy(str):
|
|||
>>> order_by.opposite
|
||||
'-name'
|
||||
|
||||
:rtype: :class:`.OrderBy` object
|
||||
:rtype: `.OrderBy` object
|
||||
"""
|
||||
return OrderBy(self[1:]) if self.is_descending else OrderBy('-' + self)
|
||||
|
||||
@property
|
||||
def is_descending(self):
|
||||
"""
|
||||
Return :const:`True` if this object induces *descending* ordering
|
||||
Return `True` if this object induces *descending* ordering
|
||||
|
||||
:rtype: :class:`bool`
|
||||
:rtype: `bool`
|
||||
"""
|
||||
return self.startswith('-')
|
||||
|
||||
@property
|
||||
def is_ascending(self):
|
||||
"""
|
||||
Return :const:`True` if this object induces *ascending* ordering.
|
||||
Return `True` if this object induces *ascending* ordering.
|
||||
|
||||
:returns: :class:`bool`
|
||||
:returns: `bool`
|
||||
"""
|
||||
return not self.is_descending
|
||||
|
||||
|
||||
class OrderByTuple(tuple):
|
||||
"""Stores ordering as (as :class:`.OrderBy` objects). The
|
||||
:attr:`django_tables2.tables.Table.order_by` property is always converted
|
||||
to an :class:`.OrderByTuple` object.
|
||||
"""Stores ordering as (as `.OrderBy` objects). The
|
||||
`~django_tables2.tables.Table.order_by` property is always converted
|
||||
to an `.OrderByTuple` object.
|
||||
|
||||
This class is essentially just a :class:`tuple` with some useful extras.
|
||||
This class is essentially just a `tuple` with some useful extras.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -156,7 +158,7 @@ class OrderByTuple(tuple):
|
|||
True
|
||||
|
||||
:param name: The name of a column. (optionally prefixed)
|
||||
:returns: :class:`bool`
|
||||
:returns: `bool`
|
||||
"""
|
||||
name = OrderBy(name).bare
|
||||
for order_by in self:
|
||||
|
@ -166,7 +168,7 @@ class OrderByTuple(tuple):
|
|||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Allows an :class:`.OrderBy` object to be extracted via named or integer
|
||||
Allows an `.OrderBy` object to be extracted via named or integer
|
||||
based indexing.
|
||||
|
||||
When using named based indexing, it's fine to used a prefixed named.
|
||||
|
@ -181,7 +183,7 @@ class OrderByTuple(tuple):
|
|||
>>> x['-age']
|
||||
'-age'
|
||||
|
||||
:rtype: :class:`.OrderBy` object
|
||||
:rtype: `.OrderBy` object
|
||||
"""
|
||||
if isinstance(index, basestring):
|
||||
for order_by in self:
|
||||
|
@ -193,8 +195,8 @@ class OrderByTuple(tuple):
|
|||
@property
|
||||
def cmp(self):
|
||||
"""
|
||||
Return a function for use with :meth:`list.sort()` that implements this
|
||||
object's ordering. This is used to sort non-:class:`QuerySet` based
|
||||
Return a function for use with `list.sort` that implements this
|
||||
object's ordering. This is used to sort non-`.QuerySet` based
|
||||
:term:`table data`.
|
||||
|
||||
:rtype: function
|
||||
|
@ -232,7 +234,7 @@ class OrderByTuple(tuple):
|
|||
@property
|
||||
def opposite(self):
|
||||
"""
|
||||
Return version with each :class:`OrderBy` prefix toggled.
|
||||
Return version with each `.OrderBy` prefix toggled.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -248,7 +250,7 @@ class OrderByTuple(tuple):
|
|||
class Accessor(str):
|
||||
"""
|
||||
A string describing a path from one object to another via attribute/index
|
||||
accesses. For convenience, the class has an alias ``A`` to allow for more concise code.
|
||||
accesses. For convenience, the class has an alias `.A` to allow for more concise code.
|
||||
|
||||
Relations are separated by a ``.`` character.
|
||||
"""
|
||||
|
@ -263,24 +265,25 @@ class Accessor(str):
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
>>> x = Accessor('__len__`')
|
||||
>>> x = Accessor('__len__')
|
||||
>>> x.resolve('brad')
|
||||
4
|
||||
>>> x = Accessor('0.upper')
|
||||
>>> x.resolve('brad')
|
||||
'B'
|
||||
|
||||
:type context: :class:`object`
|
||||
:type context: `object`
|
||||
:param context: The root/first object to traverse.
|
||||
:type safe: `bool`
|
||||
:param safe: Don't call anything with `alters_data = True`
|
||||
:param safe: Don't call anything with ``alters_data = True``
|
||||
:type quiet: bool
|
||||
:param quiet: Smother all exceptions and instead return `None`
|
||||
:returns: target object
|
||||
:raises: anything `getattr(a, "b")` raises, e.g. `TypeError`,
|
||||
`AttributeError`, `KeyError`, `ValueError`
|
||||
:raises: anything ``getattr(a, "b")`` raises, e.g. `TypeError`,
|
||||
`AttributeError`, `KeyError`, `ValueError` (unless *quiet* ==
|
||||
`True`)
|
||||
|
||||
:meth:`~.Accessor.resolve` attempts lookups in the following order:
|
||||
`~.Accessor.resolve` attempts lookups in the following order:
|
||||
|
||||
- dictionary (e.g. ``obj[related]``)
|
||||
- attribute (e.g. ``obj.related``)
|
||||
|
@ -334,11 +337,11 @@ A = Accessor # alias
|
|||
|
||||
class AttributeDict(dict):
|
||||
"""
|
||||
A wrapper around :class:`dict` that knows how to render itself as HTML
|
||||
A wrapper around `dict` that knows how to render itself as HTML
|
||||
style tag attributes.
|
||||
|
||||
The returned string is marked safe, so it can be used safely in a template.
|
||||
See :meth:`.as_html` for a usage example.
|
||||
See `.as_html` for a usage example.
|
||||
"""
|
||||
def as_html(self):
|
||||
"""
|
||||
|
@ -353,7 +356,7 @@ class AttributeDict(dict):
|
|||
>>> attrs.as_html()
|
||||
'class="mytable" id="someid"'
|
||||
|
||||
:rtype: :class:`~django.utils.safestring.SafeUnicode` object
|
||||
:rtype: `~django.utils.safestring.SafeUnicode` object
|
||||
|
||||
"""
|
||||
return mark_safe(' '.join(['%s="%s"' % (k, escape(v))
|
||||
|
@ -374,7 +377,7 @@ def segment(sequence, aliases):
|
|||
"""
|
||||
Translates a flat sequence of items into a set of prefixed aliases.
|
||||
|
||||
This allows the value set by `QuerySet.order_by()` to be translated into
|
||||
This allows the value set by `.QuerySet.order_by` to be translated into
|
||||
a list of columns that would have the same result. These are called
|
||||
"order by aliases" which are optionally prefixed column names.
|
||||
|
||||
|
@ -417,6 +420,8 @@ class cached_property(object): # pylint: disable=C0103
|
|||
Taken directly from Django 1.4.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
from functools import wraps
|
||||
wraps(func)(self)
|
||||
self.func = func
|
||||
|
||||
def __get__(self, instance, cls):
|
||||
|
@ -424,12 +429,17 @@ class cached_property(object): # pylint: disable=C0103
|
|||
return res
|
||||
|
||||
|
||||
funcs = ifilter(curry(hasattr, inspect), ('getfullargspec', 'getargspec'))
|
||||
getargspec = getattr(inspect, next(funcs))
|
||||
del funcs
|
||||
|
||||
|
||||
def build_request(uri='/'):
|
||||
"""
|
||||
Return a fresh HTTP GET / request.
|
||||
|
||||
This is essentially a heavily cutdown version of Django 1.3's
|
||||
``django.test.client.RequestFactory``.
|
||||
`~django.test.client.RequestFactory`.
|
||||
"""
|
||||
path, _, querystring = uri.partition('?')
|
||||
return WSGIRequest({
|
||||
|
|
|
@ -7,22 +7,23 @@ from .config import RequestConfig
|
|||
class SingleTableMixin(object):
|
||||
"""
|
||||
Adds a Table object to the context. Typically used with
|
||||
``TemplateResponseMixin``.
|
||||
`.TemplateResponseMixin`.
|
||||
|
||||
:param table_class: table class
|
||||
:type table_class: subclass of ``django_tables2.Table``
|
||||
:type table_class: subclass of `.Table`
|
||||
:param table_data: data used to populate the table
|
||||
:type table_data: any compatible data source
|
||||
:param context_table_name: name of the table's template variable (default:
|
||||
"table")
|
||||
:type context_table_name: ``string``
|
||||
:param table_pagination: controls table pagination. If a dict, passed as
|
||||
the ``paginate`` keyword argument to
|
||||
``RequestConfig()``. As such, any *non-False*
|
||||
:type context_table_name: `unicode`
|
||||
:param table_pagination: controls table pagination. If a `dict`, passed as
|
||||
the *paginate* keyword argument to
|
||||
`.RequestConfig`. As such, any non-`False`
|
||||
value enables pagination.
|
||||
|
||||
This mixin plays nice with the Django's ``MultipleObjectMixin`` by using
|
||||
``get_queryset()`` as a fallback for the table data source.
|
||||
This mixin plays nice with the Django's`.MultipleObjectMixin` by using
|
||||
`.get_queryset`` as a fallback for the table data source.
|
||||
|
||||
"""
|
||||
table_class = None
|
||||
table_data = None
|
||||
|
@ -80,7 +81,7 @@ class SingleTableMixin(object):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""
|
||||
Overriden version of ``TemplateResponseMixin`` to inject the table into
|
||||
Overriden version of `.TemplateResponseMixin` to inject the table into
|
||||
the template's context.
|
||||
"""
|
||||
context = super(SingleTableMixin, self).get_context_data(**kwargs)
|
||||
|
@ -91,5 +92,5 @@ class SingleTableMixin(object):
|
|||
|
||||
class SingleTableView(SingleTableMixin, ListView):
|
||||
"""
|
||||
Generic view that renders a template and passes in a ``Table`` object.
|
||||
Generic view that renders a template and passes in a `.Table` object.
|
||||
"""
|
||||
|
|
|
@ -19,6 +19,9 @@ with open('../django_tables2/__init__.py', 'rb') as f:
|
|||
version = release.rpartition('.')[0]
|
||||
|
||||
|
||||
default_role = "py:obj"
|
||||
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
|
|
582
docs/index.rst
582
docs/index.rst
|
@ -16,6 +16,12 @@ django-tables2 turns data into HTML tables. Features:
|
|||
Report bugs at http://github.com/bradleyayers/django-tables2/issues
|
||||
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
internal
|
||||
|
||||
|
||||
Tutorial
|
||||
========
|
||||
|
||||
|
@ -59,8 +65,8 @@ Hook the view up in your URLs, and load the page, you should see:
|
|||
:align: center
|
||||
:alt: An example table rendered using django-tables2
|
||||
|
||||
While simple, passing a queryset directly to ``render_table`` doesn't allow for
|
||||
any customisation. For that, you must define a ``Table`` class.
|
||||
While simple, passing a queryset directly to ``{% render_table %}`` doesn't
|
||||
allow for any customisation. For that, you must define a `.Table` class.
|
||||
|
||||
::
|
||||
|
||||
|
@ -91,10 +97,11 @@ adding it to the context.
|
|||
RequestConfig(request).configure(table)
|
||||
return render(request, 'people.html', {'table': table})
|
||||
|
||||
Using ``RequestConfig`` automatically pulls values from ``request.GET`` and
|
||||
Using `.RequestConfig` automatically pulls values from ``request.GET`` and
|
||||
updates the table accordingly. This enables data ordering and pagination.
|
||||
|
||||
Rather than passing a queryset to ``render_table``, instead pass the table.
|
||||
Rather than passing a queryset to ``{% render_table %}``, instead pass the
|
||||
table.
|
||||
|
||||
.. sourcecode:: django
|
||||
|
||||
|
@ -253,7 +260,7 @@ however when mixing auto-generated columns (via `Table.Meta.model`) with
|
|||
manually declared columns, the column sequence becomes ambiguous.
|
||||
|
||||
To resolve the ambiguity, columns sequence can be declard via the
|
||||
``Table.Meta.sequence`` option::
|
||||
`.Table.Meta.sequence` option::
|
||||
|
||||
class PersonTable(tables.Table):
|
||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
@ -271,10 +278,8 @@ should inserted at that location. As such it can be used at most once.
|
|||
Customising column headings
|
||||
===========================
|
||||
|
||||
|
||||
The header cell for each column comes from the column's
|
||||
:meth:`~django_tables2.columns.BoundColumn.header` method. By default this
|
||||
method returns a titlised version of the column's ``verbose_name``.
|
||||
The header cell for each column comes from `~.Column.header`. By default this
|
||||
method returns a titlised version of the `~.Column.verbose_name`.
|
||||
|
||||
When using queryset data and a verbose name hasn't been explicitly
|
||||
defined for a column, the corresponding model field's verbose name will be
|
||||
|
@ -305,7 +310,7 @@ Consider the following:
|
|||
|
||||
As you can see in the last example (region name), the results are not always
|
||||
desirable when an accessor is used to cross relationships. To get around this
|
||||
be careful to define a ``verbose_name`` on such columns.
|
||||
be careful to define `.Column.verbose_name`.
|
||||
|
||||
|
||||
.. _pagination:
|
||||
|
@ -323,7 +328,7 @@ pass in the current page number, e.g.
|
|||
table.paginate(page=request.GET.get('page', 1), per_page=25)
|
||||
return render(request, 'people_listing.html', {'table': table})
|
||||
|
||||
If you're using ``RequestConfig``, pass pagination options to the constructor,
|
||||
If you're using `.RequestConfig`, pass pagination options to the constructor,
|
||||
e.g.:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
@ -343,11 +348,113 @@ Various options are available for changing the way the table is :term:`rendered
|
|||
<render>`. Each approach has a different balance of ease-of-use and
|
||||
flexibility.
|
||||
|
||||
|
||||
.. _table.render_foo:
|
||||
|
||||
:meth:`Table.render_FOO` methods
|
||||
--------------------------------
|
||||
|
||||
To change how a column is rendered, implement a ``render_FOO`` method on the
|
||||
table (where ``FOO`` is the :term:`column name`). This approach is suitable if
|
||||
you have a one-off change that you don't want to use in multiple tables.
|
||||
|
||||
Supported keyword arguments include:
|
||||
|
||||
- ``record`` -- the entire record for the row from the :term:`table data`
|
||||
- ``value`` -- the value for the cell retrieved from the :term:`table data`
|
||||
- ``column`` -- the `.Column` object
|
||||
- ``bound_column`` -- the `.BoundColumn` object
|
||||
- ``bound_row`` -- the `.BoundRow` object
|
||||
- ``table`` -- alias for ``self``
|
||||
|
||||
Here's an example where the first column displays the current row number::
|
||||
|
||||
>>> import django_tables2 as tables
|
||||
>>> import itertools
|
||||
>>> class SimpleTable(tables.Table):
|
||||
... row_number = tables.Column(empty_values=())
|
||||
... id = tables.Column()
|
||||
... age = tables.Column()
|
||||
...
|
||||
... def __init__(self, *args, **kwargs):
|
||||
... super(SimpleTable, self).__init__(*args, **kwargs)
|
||||
... self.counter = itertools.count()
|
||||
...
|
||||
... def render_row_number(self):
|
||||
... return 'Row %d' % next(self.counter)
|
||||
...
|
||||
... def render_id(self, value):
|
||||
... return '<%s>' % value
|
||||
...
|
||||
>>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
|
||||
>>> for cell in table.rows[0]:
|
||||
... print cell
|
||||
...
|
||||
Row 0
|
||||
<10>
|
||||
31
|
||||
|
||||
Python's `inspect.getargspec` is used to only pass the arguments declared by the
|
||||
function. This means it's not necessary to add a catch all (``**``) keyword
|
||||
argument.
|
||||
|
||||
.. important::
|
||||
|
||||
`render` methods are *only* called if the value for a cell is determined to
|
||||
be not an :term:`empty value`. When a value is in `.Column.empty_values`,
|
||||
a default value is rendered instead (both `.Column.render` and
|
||||
``Table.render_FOO`` are skipped).
|
||||
|
||||
|
||||
.. _subclassing-column:
|
||||
|
||||
Subclassing `.Column`
|
||||
---------------------
|
||||
|
||||
Defining a column subclass allows functionality to be reused across tables.
|
||||
Columns have a `render` method that behaves the same as :ref:`table.render_foo`
|
||||
methods on tables::
|
||||
|
||||
>>> import django_tables2 as tables
|
||||
>>>
|
||||
>>> class UpperColumn(tables.Column):
|
||||
... def render(self, value):
|
||||
... return value.upper()
|
||||
...
|
||||
>>> class Example(tables.Table):
|
||||
... normal = tables.Column()
|
||||
... upper = UpperColumn()
|
||||
...
|
||||
>>> data = [{'normal': 'Hi there!',
|
||||
... 'upper': 'Hi there!'}]
|
||||
...
|
||||
>>> table = Example(data)
|
||||
>>> table.as_html()
|
||||
u'<table><thead><tr><th>Normal</th><th>Upper</th></tr></thead><tbody><tr><td>Hi there!</td><td>HI THERE!</td></tr></tbody></table>\n'
|
||||
|
||||
See :ref:`table.render_foo` for a list of arguments that can be accepted.
|
||||
|
||||
For complicated columns, you may want to return HTML from the
|
||||
:meth:`~Column.render` method. This is fine, but be sure to mark the string as
|
||||
safe to avoid it being escaped::
|
||||
|
||||
>>> from django.utils.safestring import mark_safe
|
||||
>>> from django.utils.html import escape
|
||||
>>>
|
||||
>>> class ImageColumn(tables.Column):
|
||||
... def render(self, value):
|
||||
... return mark_safe('<img src="/media/img/%s.jpg" />'
|
||||
... % escape(value))
|
||||
...
|
||||
|
||||
|
||||
.. _css:
|
||||
|
||||
CSS
|
||||
---
|
||||
|
||||
In order to use CSS to style a table, you'll probably want to add a
|
||||
``class`` or ``id`` attribute to the ``<table>`` element. ``django-tables2`` has
|
||||
``class`` or ``id`` attribute to the ``<table>`` element. django-tables2 has
|
||||
a hook that allows abitrary attributes to be added to the ``<table>`` tag.
|
||||
|
||||
.. sourcecode:: python
|
||||
|
@ -364,62 +471,16 @@ a hook that allows abitrary attributes to be added to the ``<table>`` tag.
|
|||
>>> table.as_html()
|
||||
'<table class="mytable">...'
|
||||
|
||||
.. _custom-template:
|
||||
|
||||
.. _table.render_foo:
|
||||
Custom Template
|
||||
---------------
|
||||
|
||||
:meth:`Table.render_FOO` Methods
|
||||
--------------------------------
|
||||
And of course if you want full control over the way the table is rendered,
|
||||
ignore the built-in generation tools, and instead pass an instance of your
|
||||
`.Table` subclass into your own template, and render it yourself.
|
||||
|
||||
If you want to adjust the way table cells in a particular column are rendered,
|
||||
you can implement a ``render_FOO`` method. ``FOO`` should be the
|
||||
:term:`name <column name>` of the column.
|
||||
|
||||
This approach provides a lot of control, but is only suitable if you intend to
|
||||
customise the rendering for a single table (otherwise you'll end up having to
|
||||
copy & paste the method to every table you want to modify – which violates
|
||||
DRY).
|
||||
|
||||
Supported keyword arguments include: (only the arguments declared will be passed)
|
||||
|
||||
- ``record`` -- the entire record for the row from the :term:`table data`
|
||||
- ``value`` -- the value for the cell retrieved from the :term:`table data`
|
||||
- ``column`` -- the :class:`.Column` object
|
||||
- ``bound_column`` -- the :class:`.BoundColumn` object
|
||||
- ``bound_row`` -- the :class:`.BoundRow` object
|
||||
- ``table`` -- alias for ``self``
|
||||
|
||||
Example::
|
||||
|
||||
>>> import django_tables2 as tables
|
||||
>>> class SimpleTable(tables.Table):
|
||||
... row_number = tables.Column()
|
||||
... id = tables.Column()
|
||||
... age = tables.Column()
|
||||
...
|
||||
... def render_row_number(self):
|
||||
... value = getattr(self, '_counter', 0)
|
||||
... self._counter = value + 1
|
||||
... return 'Row %d' % value
|
||||
...
|
||||
... def render_id(self, value):
|
||||
... return '<%s>' % value
|
||||
...
|
||||
>>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
|
||||
>>> for cell in table.rows[0]:
|
||||
... print cell
|
||||
...
|
||||
Row 0
|
||||
<10>
|
||||
31
|
||||
|
||||
.. note::
|
||||
|
||||
Due to the implementation of dynamic argument passing, any "catch-extra"
|
||||
arguments (e.g. ``*args`` or ``**kwargs``) will not recieve any arguments.
|
||||
This is because `inspect.getargsspec()`__ is used to check what arguments a
|
||||
``render_FOO`` method expect, and only to supply those.
|
||||
|
||||
.. __: http://docs.python.org/library/inspect.html#inspect.getargspec
|
||||
Have a look at the ``django_tables2/table.html`` template for an example.
|
||||
|
||||
|
||||
.. _query-string-fields:
|
||||
|
@ -432,9 +493,9 @@ preferences.
|
|||
|
||||
The names of the querystring variables are configurable via the options:
|
||||
|
||||
- ``order_by_field`` -- default: ``sort``
|
||||
- ``page_field`` -- default: ``page``
|
||||
- ``per_page_field`` -- default: ``per_page``, **note:** this field currently
|
||||
- ``order_by_field`` -- default: ``"sort"``
|
||||
- ``page_field`` -- default: ``"page"``
|
||||
- ``per_page_field`` -- default: ``"per_page"``, **note:** this field currently
|
||||
isn't used by ``{% render_table %}``
|
||||
|
||||
Each of these can be specified in three places:
|
||||
|
@ -462,7 +523,7 @@ fields with a table-specific name. e.g.
|
|||
Column attributes
|
||||
=================
|
||||
|
||||
Column attributes can be specified using the :class:`dict` with specific keys.
|
||||
Column attributes can be specified using the `dict` with specific keys.
|
||||
The dict defines HTML attributes for one of more elements within the column.
|
||||
Depending on the column, different elements are supported, however ``th``,
|
||||
``td``, and ``cell`` are supported universally.
|
||||
|
@ -493,93 +554,18 @@ Built-in columns
|
|||
|
||||
For common use-cases the following columns are included:
|
||||
|
||||
- :class:`.BooleanColumn` -- renders boolean values
|
||||
- :class:`.Column` -- generic column
|
||||
- :class:`.CheckBoxColumn` -- renders checkbox form inputs
|
||||
- :class:`.DateColumn` -- date formatting
|
||||
- :class:`.DateTimeColumn` -- datetime formatting in the local timezone
|
||||
- :class:`.FileColumn` -- renders files as links
|
||||
- :class:`.EmailColumn` -- renders ``<a href="mailto:...">`` tags
|
||||
- :class:`.LinkColumn` -- renders ``<a href="...">`` tags (absolute url)
|
||||
- :class:`.TemplateColumn` -- renders template code
|
||||
- :class:`.URLColumn` -- renders ``<a href="...">`` tags (compose a django url)
|
||||
- `.BooleanColumn` -- renders boolean values
|
||||
- `.Column` -- generic column
|
||||
- `.CheckBoxColumn` -- renders checkbox form inputs
|
||||
- `.DateColumn` -- date formatting
|
||||
- `.DateTimeColumn` -- datetime formatting in the local timezone
|
||||
- `.FileColumn` -- renders files as links
|
||||
- `.EmailColumn` -- renders ``<a href="mailto:...">`` tags
|
||||
- `.LinkColumn` -- renders ``<a href="...">`` tags (absolute url)
|
||||
- `.TemplateColumn` -- renders template code
|
||||
- `.URLColumn` -- renders ``<a href="...">`` tags (compose a django url)
|
||||
|
||||
|
||||
.. _subclassing-column:
|
||||
|
||||
Subclassing :class:`Column`
|
||||
---------------------------
|
||||
|
||||
If you want to have a column behave the same way in many tables, it's best to
|
||||
create a subclass of :class:`Column` and use that when defining the table.
|
||||
|
||||
To change the way cells are rendered, simply override the
|
||||
:meth:`~Column.render` method.
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
>>> import django_tables2 as tables
|
||||
>>>
|
||||
>>> class AngryColumn(tables.Column):
|
||||
... def render(self, value):
|
||||
... return value.upper()
|
||||
...
|
||||
>>> class Example(tables.Table):
|
||||
... normal = tables.Column()
|
||||
... angry = AngryColumn()
|
||||
...
|
||||
>>> data = [{
|
||||
... 'normal': 'May I have some food?',
|
||||
... 'angry': 'Give me the food now!',
|
||||
... }, {
|
||||
... 'normal': 'Hello!',
|
||||
... 'angry': 'What are you looking at?',
|
||||
... }]
|
||||
...
|
||||
>>> table = Example(data)
|
||||
>>> table.as_html()
|
||||
u'<table><thead><tr><th>Normal</th><th>Angry</th></tr></thead><tbody><tr><td>May I have some food?</td><td>GIVE ME THE FOOD NOW!</td></tr><tr><td>Hello!</td><td>WHAT ARE YOU LOOKING AT?</td></tr></tbody></table>\n'
|
||||
|
||||
See :ref:`table.render_foo` for a list of arguments that can be accepted.
|
||||
|
||||
Which, when displayed in a browser, would look something like this:
|
||||
|
||||
+-----------------------+--------------------------+
|
||||
| Normal | Angry |
|
||||
+=======================+==========================+
|
||||
| May I have some food? | GIVE ME THE FOOD NOW! |
|
||||
+-----------------------+--------------------------+
|
||||
| Hello! | WHAT ARE YOU LOOKING AT? |
|
||||
+-----------------------+--------------------------+
|
||||
|
||||
|
||||
For complicated columns, it's sometimes necessary to return HTML from a
|
||||
:meth:`~Column.render` method, but the string must be marked as safe (otherwise
|
||||
it will be escaped when the table is rendered). This can be achieved by using
|
||||
the :func:`mark_safe` function.
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
>>> from django.utils.safestring import mark_safe
|
||||
>>>
|
||||
>>> class ImageColumn(tables.Column):
|
||||
... def render(self, value):
|
||||
... return mark_safe('<img src="/media/img/%s.jpg" />' % value)
|
||||
...
|
||||
|
||||
|
||||
.. _custom-template:
|
||||
|
||||
Custom Template
|
||||
---------------
|
||||
|
||||
And of course if you want full control over the way the table is rendered,
|
||||
ignore the built-in generation tools, and instead pass an instance of your
|
||||
:class:`.Table` subclass into your own template, and render it yourself.
|
||||
|
||||
Have a look at ``django_tables2/templates/django_tables2/table.html`` for an
|
||||
example.
|
||||
|
||||
.. _template_tags:
|
||||
|
||||
Template tags
|
||||
|
@ -590,7 +576,7 @@ Template tags
|
|||
render_table
|
||||
------------
|
||||
|
||||
Renders a :class:`~django_tables2.tables.Table` object to HTML and enables as
|
||||
Renders a `~django_tables2.tables.Table` object to HTML and enables as
|
||||
many features in the output as possible.
|
||||
|
||||
.. sourcecode:: django
|
||||
|
@ -602,17 +588,17 @@ many features in the output as possible.
|
|||
{% render_table table "path/to/custom_table_template.html" %}
|
||||
|
||||
If the second argument (template path) is given, the template will be rendered
|
||||
with a ``RequestContext`` and the table will be in the variable ``table``.
|
||||
with a `.RequestContext` and the table will be in the variable ``table``.
|
||||
|
||||
.. note::
|
||||
|
||||
This tag temporarily modifies the ``Table`` object while it is being
|
||||
This tag temporarily modifies the `.Table` object while it is being
|
||||
rendered. It adds a ``request`` attribute to the table, which allows
|
||||
:class:`Column` objects to have access to a ``RequestContext``. See
|
||||
:class:`.TemplateColumn` for an example.
|
||||
`.Column` objects to have access to a `.RequestContext`. See
|
||||
`.TemplateColumn` for an example.
|
||||
|
||||
This tag requires that the template in which it's rendered contains the
|
||||
``HttpRequest`` inside a ``request`` variable. This can be achieved by ensuring
|
||||
`~.http.HttpRequest` inside a ``request`` variable. This can be achieved by ensuring
|
||||
the ``TEMPLATE_CONTEXT_PROCESSORS`` setting contains
|
||||
``"django.core.context_processors.request"``. By default it is not included,
|
||||
and the setting itself is not even defined within your project's
|
||||
|
@ -680,7 +666,7 @@ Class Based Generic Mixins
|
|||
|
||||
Django 1.3 introduced `class based views`__ as a mechanism to reduce the
|
||||
repetition in view code. django-tables2 comes with a single class based view
|
||||
mixin: ``SingleTableMixin``. It makes it trivial to incorporate a table into a
|
||||
mixin: `.SingleTableMixin`. It makes it trivial to incorporate a table into a
|
||||
view/template.
|
||||
|
||||
The following view parameters are supported:
|
||||
|
@ -688,7 +674,7 @@ The following view parameters are supported:
|
|||
- ``table_class`` –- the table class to use, e.g. ``SimpleTable``
|
||||
- ``table_data`` (or ``get_table_data()``) -- the data used to populate the table
|
||||
- ``context_table_name`` -- the name of template variable containing the table object
|
||||
- ``table_pagination`` -- pagination options to pass to :class:`RequestConfig`
|
||||
- ``table_pagination`` -- pagination options to pass to `.RequestConfig`
|
||||
|
||||
.. __: https://docs.djangoproject.com/en/1.3/topics/class-based-views/
|
||||
|
||||
|
@ -722,27 +708,27 @@ The template could then be as simple as:
|
|||
{% render_table table %}
|
||||
|
||||
Such little code is possible due to the example above taking advantage of
|
||||
default values and ``SimpleTableMixin``'s eagarness at finding data sources
|
||||
default values and `.SimpleTableMixin`'s eagarness at finding data sources
|
||||
when one isn't explicitly defined.
|
||||
|
||||
.. note::
|
||||
|
||||
If you need more than one table on a page, use ``SingleTableView`` and use
|
||||
``get_context_data()`` to initialise the other tables and add them to the
|
||||
If you need more than one table on a page, use `.SingleTableView` and use
|
||||
`.get_context_data` to initialise the other tables and add them to the
|
||||
context.
|
||||
|
||||
.. note::
|
||||
|
||||
You don't have to base your view on ``ListView``, you're able to mix
|
||||
``SingleTableMixin`` directly.
|
||||
You don't have to base your view on `ListView`, you're able to mix
|
||||
`SingleTableMixin` directly.
|
||||
|
||||
|
||||
Table Mixins
|
||||
============
|
||||
|
||||
It's possible to create a mixin for a table that overrides something, however
|
||||
unless it itself is a subclass of :class:`.Table` class
|
||||
variable instances of :class:`.Column` will **not** be added to the class which is using the mixin.
|
||||
unless it itself is a subclass of `.Table` class variable instances of
|
||||
`.Column` will **not** be added to the class which is using the mixin.
|
||||
|
||||
Example::
|
||||
|
||||
|
@ -756,7 +742,7 @@ Example::
|
|||
['name']
|
||||
|
||||
To have a mixin contribute a column, it needs to be a subclass of
|
||||
:class:`~django_tables2.tables.Table`. With this in mind the previous example
|
||||
`~django_tables2.tables.Table`. With this in mind the previous example
|
||||
*should* have been written as follows::
|
||||
|
||||
>>> class UsefulMixin(tables.Table):
|
||||
|
@ -774,103 +760,60 @@ To have a mixin contribute a column, it needs to be a subclass of
|
|||
Tables for models
|
||||
=================
|
||||
|
||||
Most of the time you'll probably be making tables to display queryset data, and
|
||||
writing such tables involves a lot of duplicate code, e.g.::
|
||||
If you build use tables to display `.QuerySet` data, rather than defining each
|
||||
column manually in the table, the `.Table.Meta.model` option allows tables to
|
||||
be dynamically created based on a model::
|
||||
|
||||
>>> class Person(models.Model):
|
||||
... first_name = models.CharField(max_length=200)
|
||||
... last_name = models.CharField(max_length=200)
|
||||
... user = models.ForeignKey("auth.User")
|
||||
... dob = models.DateField()
|
||||
...
|
||||
>>> class PersonTable(tables.Table):
|
||||
... first_name = tables.Column()
|
||||
... last_name = tables.Column()
|
||||
... user = tables.Column()
|
||||
... dob = tables.Column()
|
||||
...
|
||||
# models.py
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(max_length=200)
|
||||
last_name = models.CharField(max_length=200)
|
||||
user = models.ForeignKey("auth.User")
|
||||
dob = models.DateField()
|
||||
|
||||
Often a table will become quite complex after time, e.g. `table.render_foo`_,
|
||||
changing ``verbose_name`` on columns, or adding an extra
|
||||
:class:`~.CheckBoxColumn`.
|
||||
# tables.py
|
||||
class PersonTable(tables.Table):
|
||||
class Meta:
|
||||
model = Person
|
||||
|
||||
``django-tables2`` offers the :attr:`.Table.Meta.model` option to ease the pain.
|
||||
The ``model`` option causes the table automatically generate columns for the
|
||||
fields in the model. This means that the above table could be re-written as
|
||||
follows::
|
||||
This has a number of benefits:
|
||||
|
||||
>>> class PersonTable(tables.Table):
|
||||
... class Meta:
|
||||
... model = Person
|
||||
...
|
||||
>>> PersonTable.base_columns.keys()
|
||||
['first_name', 'last_name', 'user', 'dob']
|
||||
- Less code, easier to write, more DRY
|
||||
- Columns use the field's `~.models.Field.verbose_name`
|
||||
- Specialised columns are used where possible (e.g. `.DateColumn` for a
|
||||
`~.models.DateField`)
|
||||
|
||||
If you want to customise one of the columns, simply define it the way you would
|
||||
normally::
|
||||
When using this approach, the following options are useful:
|
||||
|
||||
>>> from django_tables2 import A
|
||||
>>> class PersonTable(tables.Table):
|
||||
... user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
|
||||
...
|
||||
... class Meta:
|
||||
... model = Person
|
||||
...
|
||||
>>> PersonTable.base_columns.keys()
|
||||
['first_name', 'last_name', 'dob', 'user']
|
||||
|
||||
It's not immediately obvious but if you look carefully you'll notice that the
|
||||
order of the fields has now changed -- ``user`` is now last, rather than
|
||||
``dob``. This follows the same behaviour of Django's model forms, and can be
|
||||
fixed in a similar way -- the :attr:`.Table.Meta.sequence` option::
|
||||
|
||||
>>> class PersonTable(tables.Table):
|
||||
... user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
|
||||
...
|
||||
... class Meta:
|
||||
... model = Person
|
||||
... sequence = ("first_name", "last_name", "user", "dob")
|
||||
...
|
||||
>>> PersonTable.base_columns.keys()
|
||||
['first_name', 'last_name', 'user', 'dob']
|
||||
|
||||
… or use a shorter approach that makes use of the special ``"..."`` item::
|
||||
|
||||
>>> class PersonTable(tables.Table):
|
||||
... user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
|
||||
...
|
||||
... class Meta:
|
||||
... model = Person
|
||||
... sequence = ("...", "dob")
|
||||
...
|
||||
>>> PersonTable.base_columns.keys()
|
||||
['first_name', 'last_name', 'user', 'dob']
|
||||
- `~.Table.Meta.sequence` -- reorder columns
|
||||
- `~.Table.Meta.fields` -- specify model fields to *include*
|
||||
- `~.Table.Meta.exclude` -- specify model fields to *excluse*
|
||||
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
||||
:class:`Accessor` (`A`) Objects:
|
||||
--------------------------------
|
||||
`.Accessor` (`.A`)
|
||||
------------------
|
||||
|
||||
.. autoclass:: django_tables2.utils.Accessor
|
||||
|
||||
|
||||
:class:`RequestConfig` Objects:
|
||||
-------------------------------
|
||||
`.RequestConfig`
|
||||
----------------
|
||||
|
||||
.. autoclass:: django_tables2.config.RequestConfig
|
||||
|
||||
|
||||
:class:`Table` Objects:
|
||||
-----------------------
|
||||
`.Table`
|
||||
--------
|
||||
|
||||
.. autoclass:: django_tables2.tables.Table
|
||||
:members:
|
||||
:members: paginate, as_html
|
||||
|
||||
|
||||
:class:`Table.Meta` Objects:
|
||||
----------------------------
|
||||
`.Table.Meta`
|
||||
-------------
|
||||
|
||||
.. class:: Table.Meta
|
||||
|
||||
|
@ -884,7 +827,7 @@ API Reference
|
|||
:meth:`.Table.as_html` or the
|
||||
:ref:`template-tags.render_table` template tag.
|
||||
|
||||
:type: ``dict``
|
||||
:type: `dict`
|
||||
:default: ``{}``
|
||||
|
||||
This is typically used to enable a theme for a table (which is done by
|
||||
|
@ -905,10 +848,10 @@ API Reference
|
|||
|
||||
Defines the text to display when the table has no rows.
|
||||
|
||||
:type: ``string``
|
||||
:default: ``None``
|
||||
:type: `unicode`
|
||||
:default: `None`
|
||||
|
||||
If the table is empty and ``bool(empty_text)`` is ``True``, a row is
|
||||
If the table is empty and ``bool(empty_text)`` is `True`, a row is
|
||||
displayed containing ``empty_text``. This is allows a message such as
|
||||
*There are currently no FOO.* to be displayed.
|
||||
|
||||
|
@ -922,7 +865,7 @@ API Reference
|
|||
Defines which columns should be excluded from the table. This is useful
|
||||
in subclasses to exclude columns in a parent.
|
||||
|
||||
:type: tuple of ``string`` objects
|
||||
:type: tuple of `unicode`
|
||||
:default: ``()``
|
||||
|
||||
Example::
|
||||
|
@ -946,18 +889,41 @@ API Reference
|
|||
This functionality is also available via the ``exclude`` keyword
|
||||
argument to a table's constructor.
|
||||
|
||||
However, unlike some of the other ``Meta`` options, providing the
|
||||
However, unlike some of the other `.Table.Meta` options, providing the
|
||||
``exclude`` keyword to a table's constructor **won't override** the
|
||||
``Meta.exclude``. Instead, it will be effectively be *added*
|
||||
`.Meta.exclude`. Instead, it will be effectively be *added*
|
||||
to it. i.e. you can't use the constructor's ``exclude`` argument to
|
||||
*undo* an exclusion.
|
||||
|
||||
.. attribute:: fields
|
||||
|
||||
Used in conjunction with `~.Table.Meta.model`, specifies which fields
|
||||
should have columns in the table.
|
||||
|
||||
:type: tuple of `unicode` or `None`
|
||||
:default: `None`
|
||||
|
||||
If `None`, all fields are used, otherwise only those named.
|
||||
|
||||
Example::
|
||||
|
||||
# models.py
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(max_length=200)
|
||||
last_name = models.CharField(max_length=200)
|
||||
|
||||
# tables.py
|
||||
class PersonTable(tables.Table):
|
||||
class Meta:
|
||||
model = Person
|
||||
fields = ("first_name", )
|
||||
|
||||
.. attribute:: model
|
||||
|
||||
A model to inspect and automatically create corresponding columns.
|
||||
|
||||
:type: Django model
|
||||
:default: ``None``
|
||||
:default: `None`
|
||||
|
||||
This option allows a Django model to be specified to cause the table to
|
||||
automatically generate columns that correspond to the fields in a
|
||||
|
@ -968,7 +934,7 @@ API Reference
|
|||
The default ordering. e.g. ``('name', '-age')``. A hyphen ``-`` can be
|
||||
used to prefix a column name to indicate *descending* order.
|
||||
|
||||
:type: ``tuple``
|
||||
:type: `tuple`
|
||||
:default: ``()``
|
||||
|
||||
.. note::
|
||||
|
@ -981,7 +947,7 @@ API Reference
|
|||
The sequence of the table columns. This allows the default order of
|
||||
columns (the order they were defined in the Table) to be overridden.
|
||||
|
||||
:type: any iterable (e.g. ``tuple`` or ``list``)
|
||||
:type: any iterable (e.g. `tuple` or `list`)
|
||||
:default: ``()``
|
||||
|
||||
The special item ``"..."`` can be used as a placeholder that will be
|
||||
|
@ -1012,15 +978,15 @@ API Reference
|
|||
|
||||
.. attribute:: orderable
|
||||
|
||||
Default value for column's ``orderable`` attribute.
|
||||
Default value for column's *orderable* attribute.
|
||||
|
||||
:type: ``bool``
|
||||
:default: ``True``
|
||||
:type: `bool`
|
||||
:default: `True`
|
||||
|
||||
If the ``Table`` and ``Column`` don't specify a value, a column's
|
||||
If the table and column don't specify a value, a column's
|
||||
``orderable`` value will fallback to this. object specify. This
|
||||
provides an easy mechanism to disable ordering on an entire table,
|
||||
without adding ``orderable=False`` to each ``Column`` in a ``Table``.
|
||||
without adding ``orderable=False`` to each column in a table.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -1031,125 +997,91 @@ API Reference
|
|||
|
||||
The default template to use when rendering the table.
|
||||
|
||||
:type: ``unicode``
|
||||
:default: ``django_tables2/table.html``
|
||||
:type: `unicode`
|
||||
:default: ``"django_tables2/table.html"``
|
||||
|
||||
.. note::
|
||||
|
||||
This functionality is also available via the ``template`` keyword
|
||||
This functionality is also available via the *template* keyword
|
||||
argument to a table's constructor.
|
||||
|
||||
|
||||
:class:`TableData` Objects:
|
||||
------------------------------
|
||||
|
||||
.. autoclass:: django_tables2.tables.TableData
|
||||
:members: __init__, order_by, __getitem__, __len__
|
||||
|
||||
|
||||
:class:`BooleanColumn` Objects:
|
||||
-------------------------------
|
||||
`.BooleanColumn`
|
||||
----------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.BooleanColumn
|
||||
|
||||
|
||||
:class:`Column` Objects:
|
||||
------------------------
|
||||
`.Column`
|
||||
---------
|
||||
|
||||
.. autoclass:: django_tables2.columns.Column
|
||||
|
||||
|
||||
:class:`CheckBoxColumn` Objects:
|
||||
--------------------------------
|
||||
`.CheckBoxColumn`
|
||||
-----------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.CheckBoxColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`DateColumn` Objects:
|
||||
----------------------------
|
||||
`.DateColumn`
|
||||
-------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.DateColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`DateTimeColumn` Objects:
|
||||
--------------------------------
|
||||
`.DateTimeColumn`
|
||||
-----------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.DateTimeColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`EmailColumn` Objects:
|
||||
-----------------------------
|
||||
`.EmailColumn`
|
||||
--------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.EmailColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`FileColumn` Objects:
|
||||
----------------------------
|
||||
`.FileColumn`
|
||||
-------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.FileColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`LinkColumn` Objects:
|
||||
----------------------------
|
||||
`.LinkColumn`
|
||||
-------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.LinkColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`TemplateColumn` Objects:
|
||||
--------------------------------
|
||||
`.TemplateColumn`
|
||||
-----------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.TemplateColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`URLColumn` Objects:
|
||||
--------------------------------
|
||||
`.URLColumn`
|
||||
------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.URLColumn
|
||||
:members:
|
||||
|
||||
|
||||
|
||||
:class:`BoundColumns` Objects
|
||||
-----------------------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.BoundColumns
|
||||
:members: all, items, orderable, visible, __iter__,
|
||||
__contains__, __len__, __getitem__
|
||||
|
||||
|
||||
:class:`BoundColumn` Objects
|
||||
----------------------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.BoundColumn
|
||||
:members:
|
||||
|
||||
|
||||
:class:`BoundRows` Objects
|
||||
--------------------------
|
||||
|
||||
.. autoclass:: django_tables2.rows.BoundRows
|
||||
:members: __iter__, __len__
|
||||
|
||||
|
||||
:class:`BoundRow` Objects
|
||||
-------------------------
|
||||
|
||||
.. autoclass:: django_tables2.rows.BoundRow
|
||||
:members: __getitem__, __contains__, __iter__, record, table, items
|
||||
See :doc:`internal` for internal classes.
|
||||
|
||||
|
||||
Upgrading from django-tables Version 1
|
||||
======================================
|
||||
|
||||
- Change your ``INSTALLLED_APPS`` entry from ``django_tables.app`` to
|
||||
``django_tables2``.
|
||||
- Change your ``INSTALLLED_APPS`` entry from ``"django_tables.app"`` to
|
||||
``"django_tables2"``.
|
||||
|
||||
- Change all your import references from ``django_tables`` to
|
||||
``django_tables2``.
|
||||
|
@ -1215,7 +1147,7 @@ Glossary
|
|||
.. glossary::
|
||||
|
||||
accessor
|
||||
Refers to an :class:`~django_tables2.utils.Accessor` object
|
||||
Refers to an `.Accessor` object
|
||||
|
||||
column name
|
||||
The name given to a column. In the follow example, the *column name* is
|
||||
|
@ -1226,6 +1158,12 @@ Glossary
|
|||
class SimpleTable(tables.Table):
|
||||
age = tables.Column()
|
||||
|
||||
empty value
|
||||
An empty value is synonymous with "no value". Columns have an
|
||||
``empty_values`` attribute that contains values that are considered
|
||||
empty. It's a way to declare which values from the database correspond
|
||||
to *null*/*blank*/*missing* etc.
|
||||
|
||||
order by alias
|
||||
A prefixed column name that describes how a column should impact the
|
||||
order of data within the table. This allows the implementation of how
|
||||
|
@ -1251,7 +1189,7 @@ Glossary
|
|||
A single Python object used as the data for a single row.
|
||||
|
||||
render
|
||||
The act of serialising a :class:`~django_tables2.tables.Table` into
|
||||
The act of serialising a `.Table` into
|
||||
HTML.
|
||||
|
||||
template
|
||||
|
@ -1259,4 +1197,4 @@ Glossary
|
|||
|
||||
table data
|
||||
An interable of :term:`records <record>` that
|
||||
:class:`~django_tables2.tables.Table` uses to populate its rows.
|
||||
`.Table` uses to populate its rows.
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
=============
|
||||
Internal APIs
|
||||
=============
|
||||
|
||||
The items documented here are internal and subject to change. It exists here
|
||||
for convenience.
|
||||
|
||||
|
||||
`.BoundColumns`
|
||||
---------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.BoundColumns
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
||||
|
||||
`.BoundColumn`
|
||||
--------------
|
||||
|
||||
.. autoclass:: django_tables2.columns.BoundColumn
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
||||
|
||||
`.BoundRows`
|
||||
------------
|
||||
|
||||
.. autoclass:: django_tables2.rows.BoundRows
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
||||
|
||||
`.BoundRow`
|
||||
-----------
|
||||
|
||||
.. autoclass:: django_tables2.rows.BoundRow
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
||||
|
||||
`.TableData`
|
||||
------------
|
||||
|
||||
.. autoclass:: django_tables2.tables.TableData
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
|
@ -116,6 +116,23 @@ def new_attrs_should_be_supported():
|
|||
general = Tests()
|
||||
|
||||
|
||||
@general.test
|
||||
def column_render_supports_kwargs():
|
||||
class TestColumn(tables.Column):
|
||||
def render(self, **kwargs):
|
||||
expected = set(("record", "value", "column", "bound_column",
|
||||
"bound_row", "table"))
|
||||
actual = set(kwargs.keys())
|
||||
assert actual == expected
|
||||
return "success"
|
||||
|
||||
class TestTable(tables.Table):
|
||||
foo = TestColumn()
|
||||
|
||||
table = TestTable([{"foo": "bar"}])
|
||||
assert table.rows[0]["foo"] == "success"
|
||||
|
||||
|
||||
@general.test
|
||||
def column_header_should_use_titlised_verbose_name():
|
||||
class SimpleTable(tables.Table):
|
||||
|
|
12
tox.ini
12
tox.ini
|
@ -1,7 +1,8 @@
|
|||
[testenv]
|
||||
commands =
|
||||
python -W error {envbindir}/coverage run setup.py test []
|
||||
coverage xml --source=django_tables2 -o coverage.xml
|
||||
coverage html
|
||||
bash -c 'pylint --reports=no django_tables2 tests > report.pylint || true'
|
||||
|
||||
[tools]
|
||||
testing =
|
||||
|
@ -19,12 +20,13 @@ latest = git+https://github.com/django/django/#egg=Django
|
|||
1.3.x = Django>=1.3,<1.4
|
||||
1.2.x = Django>=1.2,<1.3
|
||||
|
||||
[testenv:pylint]
|
||||
comamnds =
|
||||
pylint --files-output=y --reports=no django_tables2 tests
|
||||
[testenv:docs]
|
||||
changedir = docs
|
||||
commands = make html
|
||||
deps =
|
||||
{[tools]testing}
|
||||
pylint
|
||||
{[django]latest}
|
||||
Sphinx
|
||||
|
||||
; -- python 3.2 ---------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue