Skip to content

Commit 2e941c7

Browse files
committed
Polish merge and bump to v0.10.1
1 parent 16df453 commit 2e941c7

File tree

10 files changed

+156
-113
lines changed

10 files changed

+156
-113
lines changed

README.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ globally, use::
6363
Change log
6464
==========
6565

66+
v0.10.1
67+
-------
68+
69+
- Fixed support for Django 1.4's paginator (thanks koledennix)
70+
- Some juggling of internal implementation. `TableData` now supports slicing
71+
and returns new `TableData` instances. `BoundRows` now takes a single
72+
argument `data` (a `TableData` instance).
73+
- Add support for `get_pagination` on `SingleTableMixin`.
74+
- `SingleTableMixin` and `SingleTableView` are now importable directly from
75+
`django_tables2`.
76+
6677
v0.10.0
6778
-------
6879

django_tables2/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
from .columns import Column, CheckBoxColumn, LinkColumn, TemplateColumn
44
from .config import RequestConfig
55
from .utils import A, Attrs
6+
from .views import SingleTableMixin, SingleTableView

django_tables2/rows.py

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -173,45 +173,28 @@ class BoundRows(object):
173173
"""
174174
Container for spawning :class:`.BoundRow` objects.
175175
176-
The :attr:`.Table.rows` attribute is a :class:`.BoundRows` object.
177-
It provides functionality that would not be possible with a simple iterator
178-
in the table class.
179-
180-
:type table: :class:`.Table` object
181-
:param table: the table in which the rows exist.
176+
:type data: :class:`.TableData` object
177+
:param data: the table in which the rows exist.
182178
179+
This is used for :attr:`.Table.rows`.
183180
"""
184-
def __init__(self, table, slice=None):
185-
self.table = table
186-
if slice is not None:
187-
self._data = table.data[slice]
188-
else:
189-
self._data = None
190-
191-
@property
192-
def data(self):
193-
if self._data:
194-
return self._data
195-
else:
196-
return self.table.data
181+
def __init__(self, data):
182+
self.data = data
197183

198184
def __iter__(self):
199-
"""Convience method for :meth:`.BoundRows.all`"""
185+
table = self.data.table # avoid repeated lookups
200186
for record in self.data:
201-
yield BoundRow(self.table, record)
187+
yield BoundRow(table, record)
202188

203189
def __len__(self):
204-
"""Returns the number of rows in the table."""
205190
return len(self.data)
206191

207-
# for compatibility with QuerySetPaginator
208-
count = __len__
209-
210192
def __getitem__(self, key):
211-
"""Allows normal list slicing syntax to be used."""
193+
"""
194+
Slicing returns a new :class:`.BoundRows` instance, indexing returns
195+
a single :class:`.BoundRow` instance.
196+
"""
212197
if isinstance(key, slice):
213-
return BoundRows(self.table, key)
214-
elif isinstance(key, int):
215-
return BoundRow(self.table, self.data[key])
198+
return BoundRows(self.data[key])
216199
else:
217-
raise TypeError('Key must be a slice or integer.')
200+
return BoundRow(self.data.table, self.data[key])

django_tables2/tables.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121

2222
class TableData(object):
2323
"""
24-
Exposes a consistent API for :term:`table data`. It currently supports a
25-
:class:`QuerySet`, or a :class:`list` of :class:`dict` objects.
24+
Exposes a consistent API for :term:`table data`.
2625
27-
This class is used by :class:`.Table` to wrap any
28-
input table data.
26+
:param data: iterable containing data for each row
27+
:type data: :class:`QuerySet` or :class:`list` of :class:`dict`
28+
:param table: :class:`.Table` object
2929
"""
3030
def __init__(self, data, table):
31-
self._table = table
31+
self.table = table
3232
# data may be a QuerySet-like objects with count() and order_by()
3333
if (hasattr(data, 'count') and callable(data.count) and
3434
hasattr(data, 'order_by') and callable(data.order_by)):
@@ -70,7 +70,7 @@ def _translate_aliases_to_accessors(self, aliases):
7070
"""
7171
Translate from order by aliases to column accessors.
7272
"""
73-
columns = (self._table.columns[OrderBy(alias).bare] for alias in aliases)
73+
columns = (self.table.columns[OrderBy(alias).bare] for alias in aliases)
7474
return OrderByTuple(itertools.chain(*(c.order_by for c in columns)))
7575

7676
def __iter__(self):
@@ -81,9 +81,16 @@ def __iter__(self):
8181
"""
8282
return iter(self.list) if hasattr(self, 'list') else iter(self.queryset)
8383

84-
def __getitem__(self, index):
85-
"""Forwards indexing accesses to underlying data"""
86-
return (self.list if hasattr(self, 'list') else self.queryset)[index]
84+
def __getitem__(self, key):
85+
"""
86+
Slicing returns a new :class:`.TableData` instance, indexing returns a
87+
single record.
88+
"""
89+
data = (self.list if hasattr(self, 'list') else self.queryset)[key]
90+
if isinstance(key, slice):
91+
return type(self)(data, self.table)
92+
else:
93+
return data
8794

8895

8996
class DeclarativeColumnsMetaclass(type):
@@ -226,9 +233,9 @@ def __init__(self, data, order_by=None, orderable=None, empty_text=None,
226233
order_by_field=None, page_field=None, per_page_field=None,
227234
template=None, sortable=None):
228235
super(Table, self).__init__()
229-
self.rows = BoundRows(self)
230-
self.columns = BoundColumns(self)
231236
self.data = self.TableDataClass(data=data, table=self)
237+
self.rows = BoundRows(self.data)
238+
self.columns = BoundColumns(self)
232239
self.attrs = attrs
233240
self.empty_text = empty_text
234241
if sortable is not None:

django_tables2/utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ class OrderBy(str):
6464
@property
6565
def bare(self):
6666
"""
67-
Return the :term:`bare <bare orderby>` form.
67+
Return the bare form.
68+
69+
The *bare form* is the non-prefixed form. Typically the bare form is
70+
just the ascending form.
71+
72+
Example: ``age`` is the bare form of ``-age``
6873
6974
:rtype: :class:`.OrderBy` object
7075
"""

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
# built documents.
5555
#
5656
# The short X.Y version.
57-
version = '0.9'
57+
version = '0.10'
5858
# The full version, including alpha/beta/rc tags.
59-
release = '0.9.6'
59+
release = '0.10.1'
6060

6161
# The language for content autogenerated by Sphinx. Refer to documentation
6262
# for a list of supported languages.

docs/index.rst

Lines changed: 45 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ It's available in a few places, feedback is always welcome.
2626
Tutorial
2727
========
2828

29-
Install the app via ``pip install django-tables2``, then add
30-
``'django_tables2'`` to ``INSTALLED_APPS``.
29+
1. ``pip install django-tables2``
30+
2. Add ``'django_tables2'`` to ``INSTALLED_APPS``
3131

3232
Find some data that you'd like to render as a table. A QuerySet will work, but
3333
ease of demonstration we'll use a list of dicts:
@@ -342,31 +342,24 @@ a hook that allows abitrary attributes to be added to the ``<table>`` tag.
342342
--------------------------------
343343

344344
If you want to adjust the way table cells in a particular column are rendered,
345-
you can implement a ``render_FOO`` method. ``FOO`` is replaced with the
345+
you can implement a ``render_FOO`` method. ``FOO`` should be the
346346
:term:`name <column name>` of the column.
347347

348348
This approach provides a lot of control, but is only suitable if you intend to
349349
customise the rendering for a single table (otherwise you'll end up having to
350350
copy & paste the method to every table you want to modify – which violates
351351
DRY).
352352

353-
For convenience, a bunch of commonly used/useful values are passed to
354-
``render_FOO`` functions, when writing the signature, simply accept the
355-
arguments you're interested in, and the function will recieve them
353+
Supported keyword arguments include: (only the arguments declared will be passed)
356354

357-
.. note:: Due to the implementation, a "catch-extra" arguments (e.g. ``*args``
358-
or ``**kwargs``) will not recieve any arguments. This is because
359-
``inspect.getargsspec()`` is used to check what arguments a ``render_FOO``
360-
method expect, and only to supply those.
355+
- ``record`` -- the entire record for the row from the :term:`table data`
356+
- ``value`` -- the value for the cell retrieved from the :term:`table data`
357+
- ``column`` -- the :class:`.Column` object
358+
- ``bound_column`` -- the :class:`.BoundColumn` object
359+
- ``bound_row`` -- the :class:`.BoundRow` object
360+
- ``table`` -- alias for ``self``
361361

362-
:param value: the value for the cell retrieved from the :term:`table data`
363-
:param record: the entire record for the row from :term:`table data`
364-
:param column: the :class:`.Column` object
365-
:param bound_column: the :class:`.BoundColumn` object
366-
:param bound_row: the :class:`.BoundRow` object
367-
:param table: alias for ``self``
368-
369-
.. code-block:: python
362+
Example::
370363

371364
>>> import django_tables2 as tables
372365
>>> class SimpleTable(tables.Table):
@@ -390,6 +383,15 @@ arguments you're interested in, and the function will recieve them
390383
<10>
391384
31
392385

386+
.. note::
387+
388+
Due to the implementation of dynamic argument passing, any "catch-extra"
389+
arguments (e.g. ``*args`` or ``**kwargs``) will not recieve any arguments.
390+
This is because `inspect.getargsspec()`__ is used to check what arguments a
391+
``render_FOO`` method expect, and only to supply those.
392+
393+
.. __: http://docs.python.org/library/inspect.html#inspect.getargspec
394+
393395

394396
.. _query-string-fields:
395397

@@ -645,37 +647,37 @@ Class Based Generic Mixins
645647
Django 1.3 introduced `class based views`__ as a mechanism to reduce the
646648
repetition in view code. django-tables2 comes with a single class based view
647649
mixin: ``SingleTableMixin``. It makes it trivial to incorporate a table into a
648-
view/template, however it requires a few variables to be defined on the view:
650+
view/template.
651+
652+
The following view parameters are supported:
649653

650654
- ``table_class`` –- the table class to use, e.g. ``SimpleTable``
651-
- ``table_data`` (or ``get_table_data()``) -- the data used to populate the
652-
table
653-
- ``context_table_name`` -- the name of template variable containing the table
654-
object
655+
- ``table_data`` (or ``get_table_data()``) -- the data used to populate the table
656+
- ``context_table_name`` -- the name of template variable containing the table object
657+
- ``table_pagination`` -- pagination options to pass to :class:`RequestConfig`
655658

656659
.. __: https://docs.djangoproject.com/en/1.3/topics/class-based-views/
657660

658661
For example:
659662

660663
.. code-block:: python
661664
662-
from django_tables2.views import SingleTableMixin
663-
from django.views.generic.list import ListView
665+
from django_tables2 import SingleTableView
664666
665667
666-
class Simple(models.Model):
668+
class Person(models.Model):
667669
first_name = models.CharField(max_length=200)
668670
last_name = models.CharField(max_length=200)
669671
670672
671-
class SimpleTable(tables.Table):
672-
first_name = tables.Column()
673-
last_name = tables.Column()
673+
class PersonTable(tables.Table):
674+
class Meta:
675+
model = Simple
674676
675677
676-
class MyTableView(SingleTableMixin, ListView):
677-
model = Simple
678-
table_class = SimpleTable
678+
class PersonList(SingleTableView):
679+
model = Person
680+
table_class = PersonTable
679681
680682
681683
The template could then be as simple as:
@@ -691,11 +693,14 @@ when one isn't explicitly defined.
691693

692694
.. note::
693695

694-
If you want more than one table on a page, at the moment the simplest way
695-
to do it is to use ``SimpleTableMixin`` for one of the tables, and write
696-
the boilerplate for the other yourself in ``get_context_data()``. Obviously
697-
this isn't particularly elegant, and as such will hopefully be resolved in
698-
the future.
696+
If you need more than one table on a page, use ``SingleTableView`` and use
697+
``get_context_data()`` to initialise the other tables and add them to the
698+
context.
699+
700+
.. note::
701+
702+
You don't have to base your view on ``ListView``, you're able to mix
703+
``SingleTableMixin`` directly.
699704

700705

701706
Table Mixins
@@ -811,8 +816,8 @@ fixed in a similar way -- the :attr:`.Table.Meta.sequence` option::
811816
API Reference
812817
=============
813818

814-
:class:`Accessor` Objects:
815-
--------------------------
819+
:class:`Accessor` (`A`) Objects:
820+
--------------------------------
816821

817822
.. autoclass:: django_tables2.utils.Accessor
818823

@@ -1060,7 +1065,7 @@ API Reference
10601065
--------------------------
10611066

10621067
.. autoclass:: django_tables2.rows.BoundRows
1063-
:members: __iter__, __len__, count
1068+
:members: __iter__, __len__
10641069

10651070

10661071
:class:`BoundRow` Objects
@@ -1070,27 +1075,6 @@ API Reference
10701075
:members: __getitem__, __contains__, __iter__, record, table, items
10711076

10721077

1073-
:class:`AttributeDict` Objects
1074-
------------------------------
1075-
1076-
.. autoclass:: django_tables2.utils.AttributeDict
1077-
:members:
1078-
1079-
1080-
:class:`OrderBy` Objects
1081-
------------------------
1082-
1083-
.. autoclass:: django_tables2.utils.OrderBy
1084-
:members:
1085-
1086-
1087-
:class:`OrderByTuple` Objects
1088-
-----------------------------
1089-
1090-
.. autoclass:: django_tables2.utils.OrderByTuple
1091-
:members: __unicode__, __contains__, __getitem__, cmp, get
1092-
1093-
10941078
Upgrading from django-tables Version 1
10951079
======================================
10961080

@@ -1163,12 +1147,6 @@ Glossary
11631147
accessor
11641148
Refers to an :class:`~django_tables2.utils.Accessor` object
11651149

1166-
bare orderby
1167-
The non-prefixed form of an :class:`~django_tables2.utils.OrderBy`
1168-
object. Typically the bare form is just the ascending form.
1169-
1170-
Example: ``age`` is the bare form of ``-age``
1171-
11721150
column name
11731151
The name given to a column. In the follow example, the *column name* is
11741152
``age``.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name='django-tables2',
7-
version='0.10.0',
7+
version='0.10.1',
88
description='Table/data-grid framework for Django',
99

1010
author='Bradley Ayers',

tests/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
from .rows import rows
1313
from .templates import templates
1414
from .utils import utils
15+
from .views import views
1516

1617

1718
loader = django_attest.FancyReporter.test_loader
18-
everything = Tests([columns, config, core, models, rows, templates, utils])
19+
everything = Tests([columns, config, core, models, rows, templates, utils,
20+
views])
1921

2022

2123
# -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)