[Python-modules-commits] [django-tables] 01/08: Import django-tables_1.1.6.orig.tar.gz

Brian May bam at moszumanska.debian.org
Wed Apr 6 03:14:59 UTC 2016


This is an automated email from the git hooks/post-receive script.

bam pushed a commit to branch master
in repository django-tables.

commit 5119d5474f79dc86c40d7d395e374fc939b68332
Author: Brian May <bam at debian.org>
Date:   Wed Apr 6 12:53:12 2016 +1000

    Import django-tables_1.1.6.orig.tar.gz
---
 .travis.yml                                        |  12 +-
 CHANGELOG.md                                       |  29 +++
 README.md                                          |  68 -----
 README.rst                                         | 106 ++++++++
 django_tables2/__init__.py                         |  10 +-
 django_tables2/columns/__init__.py                 |   2 +-
 django_tables2/columns/base.py                     | 100 ++-----
 django_tables2/columns/booleancolumn.py            |  40 ++-
 django_tables2/columns/checkboxcolumn.py           |  55 ++--
 django_tables2/columns/datecolumn.py               |   4 +-
 django_tables2/columns/datetimecolumn.py           |   9 +-
 django_tables2/columns/emailcolumn.py              |   4 +-
 django_tables2/columns/filecolumn.py               |  27 +-
 django_tables2/columns/linkcolumn.py               |  80 +++---
 django_tables2/columns/templatecolumn.py           |  22 +-
 django_tables2/rows.py                             |  14 +-
 django_tables2/static/django_tables2/bootstrap.css |   8 +
 django_tables2/tables.py                           |  85 +++---
 .../templates/django_tables2/bootstrap.html        |  74 ++++++
 django_tables2/templates/django_tables2/table.html |  39 ++-
 django_tables2/templatetags/django_tables2.py      | 112 ++------
 django_tables2/utils.py                            | 128 ++-------
 django_tables2/views.py                            |  16 +-
 docs/conf.py                                       |   4 +-
 docs/pages/builtin-columns.rst                     |   2 +-
 docs/pages/generic-mixins.rst                      |   3 +-
 docs/pages/localization-control.rst                |   4 +-
 docs/pages/tutorial.rst                            |  15 +-
 example/app/migrations/0002_person_country.py      |  21 ++
 example/app/models.py                              |   6 +
 example/app/tables.py                              |  12 +-
 example/app/views.py                               |  27 +-
 example/settings.py                                |  57 ++--
 example/templates/bootstrap_template.html          |  22 ++
 example/templates/class_based.html                 |   8 +-
 example/urls.py                                    |   4 +-
 requirements/common.pip                            |   3 +-
 setup.py                                           |  31 ++-
 tests/app/models.py                                |  41 ++-
 tests/app/settings.py                              |  44 ++--
 tests/columns/test_booleancolumn.py                |  51 +++-
 tests/columns/test_checkboxcolumn.py               |  72 ++++--
 tests/columns/test_datecolumn.py                   |   4 +-
 tests/columns/test_datetimecolumn.py               |   6 +-
 tests/columns/test_emailcolumn.py                  |   1 +
 tests/columns/test_filecolumn.py                   |  59 +++--
 tests/columns/test_general.py                      |  91 ++++---
 tests/columns/test_linkcolumn.py                   |  73 +++---
 tests/columns/test_templatecolumn.py               |  16 +-
 tests/columns/test_timecolumn.py                   |  39 +++
 tests/columns/test_urlcolumn.py                    |   1 +
 tests/test_config.py                               |  22 +-
 tests/test_core.py                                 |  40 +--
 tests/test_models.py                               |  54 +++-
 tests/test_rows.py                                 |   5 +
 tests/test_templates.py                            | 286 +++++----------------
 tests/test_templatetags.py                         | 170 ++++++++++++
 tests/test_utils.py                                |  62 +++--
 tests/test_views.py                                |  80 ++++--
 tests/utils.py                                     |  60 ++---
 tox.ini                                            |  14 +-
 61 files changed, 1427 insertions(+), 1127 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index b4527c2..635c462 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,16 +5,12 @@ language: python
 matrix:
   include:
     - python: 2.7
-      env: TOXENV=py27-1.7
-    - python: 2.7
       env: TOXENV=py27-1.8
-    - python: 3.3
-      env: TOXENV=py33-1.7
+    - python: 2.7
+      env: TOXENV=py27-1.9
     - python: 3.3
       env: TOXENV=py33-1.8
     - python: 3.4
-      env: TOXENV=py34-1.7
-    - python: 3.4
       env: TOXENV=py34-1.8
     - python: 3.4
       env: TOXENV=py34-1.9
@@ -32,5 +28,9 @@ matrix:
       - env: TOXENV=py35-master
 install:
   - pip install tox
+  - pip install python-coveralls
 script:
   - tox
+
+after_success:
+    coveralls
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a85d6ca..e34e9f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,34 @@
 # Change log
 
+## v1.1.5 (2016-04-02)
+- Correct error message about request context processors for current Django (#314)
+
+## v1.1.4 (2016-03-22)
+- Fix broken `setup.py` if Django is not installed before django-tables2 (fixes #312)
+
+## v1.1.3 (2016-03-21)
+- Drop support for Django 1.7
+- Add argument to CheckBoxColumn to render it as checked (original PR: #208)
+
+## v1.1.2 (2016-02-16)
+- Fix `BooleanColumn` with choices set will always render as if `True` (#301)
+- Fix a bug with `TemplateColumn` while using cached template loader (#75)
+
+## v1.1.1 (2016-01-26)
+- Allow Meta.fields to be a list as well as a tuple (#250)
+- Call template.render with a dict in Django >= 1.8. (#298)
+- Added `RelatedLinkColumn()` to render links to related objects (#297)
+- Remove default value from request param to table.as_html()
+
+## v1.1.0 (2016-01-19)
+- Add tests for `TimeColumn`
+- Remove `sortable` argument for `Table` and Column constructors and its associated methods. Deprecated since 2012.
+- Remove deprecated aliases for `attrs` in `CheckboxColumn`.
+- Remove deprecated `OrderByTuple` `cmp` method (deprecated since 2013).
+- Add bootstrap template and (#293, fixes #141, #285)
+- Fix different html for tables with and without pagination (#293, fixes #149, #285)
+- Remove `{% nospaceless %}` template tag and remove wrapping template in `{% spaceless %}` **Possible breaking change**, if you use custom templates.
+
 ## v1.0.7 (2016-01-03)
 - Explicitly check if `column.verbose_name` is not None to support empty column headers (fixes #280)
 - Cleanup the example project to make it work with modern Django versions.
diff --git a/README.md b/README.md
deleted file mode 100644
index a69cd6d..0000000
--- a/README.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# django-tables2 - An app for creating HTML tables
-
-[![Build status](https://travis-ci.org/bradleyayers/django-tables2.svg)](https://travis-ci.org/bradleyayers/django-tables2)
-
-django-tables2 simplifies the task of turning sets of data into HTML tables. It
-has native support for pagination and sorting. It does for HTML tables what
-`django.forms` does for HTML forms. e.g.
-
-![An example table rendered using django-tables2](http://dl.dropbox.com/u/33499139/django-tables2/example.png)
-
-Its features include:
-
-- Any iterable can be a data-source, but special support for Django querysets is included.
-- The builtin UI does not rely on JavaScript.
-- Support for automatic table generation based on a Django model.
-- Supports custom column functionality via subclassing.
-- Pagination.
-- Column based table sorting.
-- Template tag to enable trivial rendering to HTML.
-- Generic view mixin.
-
-# Example
-
-Creating a table for a model `Simple` is as simple as:
-
-```python
-import django_tables2 as tables
-
-class SimpleTable(tables.Table):
-    class Meta:
-        model = Simple
-```
-
-This would then be used in a view:
-
-```python
-def simple_list(request):
-    queryset = Simple.objects.all()
-    table = SimpleTable(queryset)
-    return render_to_response("simple_list.html", {"table": table},
-                              context_instance=RequestContext(request))
-```
-
-And finally in the template:
-
-```
-{% load django_tables2 %}
-{% render_table table %}
-```
-
-This example shows one of the simplest cases, but django-tables2 can do a lot
-more! Check out the [documentation](http://django-tables2.readthedocs.org/en/latest/) for more details.
-
-
-# Building the documentation
-
-If you want to build the docs from within a virtualenv, and Sphinx is installed
-globally, use:
-
-    make html SPHINXBUILD="python $(which sphinx-build)"
-
-
-# Publishing a release
-
-1. Bump the version in `django-tables2/__init__.py`.
-2. Update `CHANGELOG.md`.
-3. Create a tag `git tag -a v1.0.6 -m 'tagging v1.0.6'`
-4. Run `python setup.py sdist upload --sign --identity=<your gpg identity>`.
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..bec4686
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,106 @@
+django-tables2 - An app for creating HTML tables
+------------------------------------------------
+
+.. image:: https://badge.fury.io/py/django-tables2.svg
+    :target: https://pypi.python.org/pypi/django-tables2
+    :alt: Latest PyPI version
+
+.. image:: https://travis-ci.org/bradleyayers/django-tables2.svg
+    :target: https://travis-ci.org/bradleyayers/django-tables2
+    :alt: Travis CI
+
+django-tables2 simplifies the task of turning sets of data into HTML tables. It
+has native support for pagination and sorting. It does for HTML tables what
+`django.forms` does for HTML forms. e.g.
+
+.. image:: http://dl.dropbox.com/u/33499139/django-tables2/example.png
+    :alt: An example table rendered using django-tables2
+
+Its features include:
+
+- Any iterable can be a data-source, but special support for Django querysets is included.
+- The builtin UI does not rely on JavaScript.
+- Support for automatic table generation based on a Django model.
+- Supports custom column functionality via subclassing.
+- Pagination.
+- Column based table sorting.
+- Template tag to enable trivial rendering to HTML.
+- Generic view mixin.
+
+- `Available on pypi <https://pypi.python.org/pypi/django-tables2>`_
+- `Tested with python 2.7, 3.3, 3.4, 3.5 and Django 1.8, 1.9 <https://travis-ci.org/bradleyayers/django-tables2>`_
+- `Documentation on readthedocs.org <http://django-tables2.readthedocs.org/en/latest/>`_
+
+Example
+-------
+
+Start by adding "django_tables2" to your INSTALLED_APPS setting like this:
+
+.. code:: python
+
+        INSTALLED_APPS = (
+            ...,
+            'django_tables2',
+        )
+
+Creating a table for a model `Simple` is as simple as:
+
+.. code:: python
+
+    import django_tables2 as tables
+
+    class SimpleTable(tables.Table):
+        class Meta:
+            model = Simple
+
+This would then be used in a view:
+
+.. code:: python
+
+    def simple_list(request):
+        queryset = Simple.objects.all()
+        table = SimpleTable(queryset)
+        return render(request, 'simple_list.html', {'table': table})
+
+And finally in the template:
+
+.. code::
+
+    {% load django_tables2 %}
+    {% render_table table %}
+
+This example shows one of the simplest cases, but django-tables2 can do a lot
+more! Check out the _documentation: http://django-tables2.readthedocs.org/en/latest/ for more details.
+
+Running the tests
+-----------------
+
+With ``tox`` installed, you can run the test suite by typing ``tox``. It will take
+care of installing the correct dependencies. During development, you might not
+want to wait for the tests to run in all environments. In that case, use the ``-e``
+argument to specify an environment:
+
+``tox -e py27-1.9`` to run the tests in python 2.7 with Django 1.9.
+
+To generate a html coverage report:
+
+    PYTHONPATH=. py.test -s --cov=django_tables2 --cov-report html
+
+
+Building the documentation
+--------------------------
+
+If you want to build the docs from within a virtualenv, and Sphinx is installed
+globally, use:
+
+    cd docs/
+    make html SPHINXBUILD="python $(which sphinx-build)"
+
+
+Publishing a release
+--------------------
+
+1. Bump the version in ``django-tables2/__init__.py``.
+2. Update ``CHANGELOG.md``.
+3. Create a tag ``git tag -a v1.0.6 -m 'tagging v1.0.6'``
+4. Run ``python setup.py sdist upload --sign --identity=<your gpg identity>``.
diff --git a/django_tables2/__init__.py b/django_tables2/__init__.py
index abebffd..bd7b4f5 100644
--- a/django_tables2/__init__.py
+++ b/django_tables2/__init__.py
@@ -1,15 +1,11 @@
 # coding: utf-8
-# pylint: disable=W0611
 from .tables import Table
 from .columns import (BooleanColumn, Column, CheckBoxColumn, DateColumn,
                       DateTimeColumn, EmailColumn, FileColumn, LinkColumn,
-                      TemplateColumn, URLColumn, TimeColumn)
+                      RelatedLinkColumn, TemplateColumn, TimeColumn, URLColumn)
 from .config import RequestConfig
 from .utils import A
-try:
-    from .views import SingleTableMixin, SingleTableView
-except ImportError:
-    pass
+from .views import SingleTableMixin, SingleTableView
 
 
-__version__ = "1.0.7"
+__version__ = "1.1.6"
diff --git a/django_tables2/columns/__init__.py b/django_tables2/columns/__init__.py
index 756ee01..4abd7a5 100644
--- a/django_tables2/columns/__init__.py
+++ b/django_tables2/columns/__init__.py
@@ -5,7 +5,7 @@ from .datecolumn import DateColumn
 from .datetimecolumn import DateTimeColumn
 from .emailcolumn import EmailColumn
 from .filecolumn import FileColumn
-from .linkcolumn import LinkColumn
+from .linkcolumn import LinkColumn, RelatedLinkColumn
 from .templatecolumn import TemplateColumn
 from .urlcolumn import URLColumn
 from .timecolumn import TimeColumn
diff --git a/django_tables2/columns/base.py b/django_tables2/columns/base.py
index 4d110c6..eaed533 100644
--- a/django_tables2/columns/base.py
+++ b/django_tables2/columns/base.py
@@ -1,17 +1,13 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
 
-import warnings
 from collections import OrderedDict
 from itertools import islice
 
-import six
-from django import VERSION as django_version
-from django.db.models.fields import FieldDoesNotExist
-from django_tables2.templatetags.django_tables2 import title
-from django_tables2.utils import A, AttributeDict, OrderBy, OrderByTuple
+from django.utils import six
 
-from ..utils import python_2_unicode_compatible
+from django_tables2.templatetags.django_tables2 import title
+from django_tables2.utils import Accessor, AttributeDict, OrderBy, OrderByTuple
 
 
 class Library(object):
@@ -51,7 +47,7 @@ library = Library()
 
 
 @library.register
-class Column(object):  # pylint: disable=R0902
+class Column(object):
     """
     Represents a single column of a table.
 
@@ -147,23 +143,17 @@ class Column(object):  # pylint: disable=R0902
 
     def __init__(self, verbose_name=None, accessor=None, default=None,
                  visible=True, orderable=None, attrs=None, order_by=None,
-                 sortable=None, empty_values=None, localize=None):
+                 empty_values=None, localize=None):
         if not (accessor is None or isinstance(accessor, six.string_types) or
                 callable(accessor)):
             raise TypeError('accessor must be a string or callable, not %s' %
                             type(accessor).__name__)
         if callable(accessor) and default is not None:
             raise TypeError('accessor must be string when default is used, not callable')
-        self.accessor = A(accessor) if accessor else None
+        self.accessor = Accessor(accessor) if accessor else None
         self._default = default
         self.verbose_name = verbose_name
         self.visible = visible
-        if sortable is not None:
-            warnings.warn('`sortable` is deprecated, use `orderable` instead.',
-                          DeprecationWarning)
-            # if orderable hasn't been specified, we'll use sortable's value
-            if orderable is None:
-                orderable = sortable
         self.orderable = orderable
         self.attrs = attrs or {}
         # massage order_by into an OrderByTuple or None
@@ -218,15 +208,6 @@ class Column(object):  # pylint: disable=R0902
         """
         return value
 
-    @property
-    def sortable(self):
-        """
-        *deprecated* -- use `.orderable` instead.
-        """
-        warnings.warn('`sortable` is deprecated, use `orderable` instead.',
-                      DeprecationWarning)
-        return self.orderable
-
     @classmethod
     def from_field(cls, field):
         """
@@ -245,14 +226,14 @@ class Column(object):  # pylint: disable=R0902
         # Since this method is inherited by every subclass, only provide a
         # column if this class was asked directly.
         if cls is Column:
-            if hasattr(field, "get_related_field"):
+            if hasattr(field, 'get_related_field'):
                 verbose_name = field.get_related_field().verbose_name
             else:
                 verbose_name = getattr(field, 'verbose_name', field.name)
             return cls(verbose_name=verbose_name)
 
 
- at python_2_unicode_compatible
+ at six.python_2_unicode_compatible
 class BoundColumn(object):
     """
     A *run-time* version of `.Column`. The difference between
@@ -291,7 +272,7 @@ class BoundColumn(object):
         Returns the string used to access data for this column out of the data
         source.
         """
-        return self.column.accessor or A(self.name)
+        return self.column.accessor or Accessor(self.name)
 
     @property
     def attrs(self):
@@ -307,24 +288,25 @@ class BoundColumn(object):
 
         # Find the relevant th attributes (fall back to cell if th isn't
         # explicitly specified).
-        attrs["td"] = td = AttributeDict(attrs.get('td', attrs.get('cell', {})))
-        attrs["th"] = th = AttributeDict(attrs.get("th", attrs.get("cell", {})))
+        attrs['th'] = AttributeDict(attrs.get('th', attrs.get('cell', {})))
+        attrs['td'] = AttributeDict(attrs.get('td', attrs.get('cell', {})))
+
         # make set of existing classes.
-        th_class = set((c for c in th.get("class", "").split(" ") if c))  # pylint: disable=C0103
-        td_class = set((c for c in td.get("class", "").split(" ") if c))  # pylint: disable=C0103
+        th_class = set((c for c in attrs['th'].get('class', '').split(' ') if c))
+        td_class = set((c for c in attrs['td'].get('class', '').split(' ') if c))
+
         # add classes for ordering
         if self.orderable:
-            th_class.add("orderable")
-            th_class.add("sortable")  # backwards compatible
+            th_class.add('orderable')
         if self.is_ordered:
-            th_class.add("desc" if self.order_by_alias.is_descending else "asc")
+            th_class.add('desc' if self.order_by_alias.is_descending else 'asc')
+
         # Always add the column name as a class
         th_class.add(self.name)
         td_class.add(self.name)
-        if th_class:
-            th['class'] = " ".join(sorted(th_class))
-        if td_class:
-            td['class'] = " ".join(sorted(td_class))
+
+        attrs['th']['class'] = ' '.join(sorted(th_class))
+        attrs['td']['class'] = ' '.join(sorted(td_class))
         return attrs
 
     @property
@@ -424,15 +406,6 @@ class BoundColumn(object):
         return self.name in (self.table.order_by or ())
 
     @property
-    def sortable(self):
-        """
-        *deprecated* -- use `orderable` instead.
-        """
-        warnings.warn('`%s.sortable` is deprecated, use `orderable`'
-                      % type(self).__name__, DeprecationWarning)
-        return self.orderable
-
-    @property
     def orderable(self):
         """
         Return a `bool` depending on whether this column supports ordering.
@@ -464,22 +437,7 @@ class BoundColumn(object):
         # Try to use a model field's verbose_name
         if hasattr(self.table.data, 'queryset') and hasattr(self.table.data.queryset, 'model'):
             model = self.table.data.queryset.model
-            parts = self.accessor.split('.')
-            field = None
-            for part in parts:
-
-                try:
-                    if django_version < (1, 8, 0):
-                        field, _, _, _ = model._meta.get_field_by_name(part)
-                    else:
-                        field = model._meta.get_field(part)
-
-                except FieldDoesNotExist:
-                    break
-                if hasattr(field, 'rel') and hasattr(field.rel, 'to'):
-                    model = field.rel.to
-                    continue
-                break
+            field = Accessor(self.accessor).get_field(model)
             if field:
                 if hasattr(field, 'field'):
                     name = field.field.verbose_name
@@ -566,25 +524,15 @@ class BoundColumns(object):
         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
+        set and checking ``{% if column.ordarable %}`` can be problematic in
         conjunction with e.g. ``{{ forloop.last }}`` (the last column might not
         be the actual last that is rendered).
         """
         return (x for x in self.iterall() if x.orderable)
 
-    def itersortable(self):
-        warnings.warn('`itersortable` is deprecated, use `iterorderable` instead.',
-                      DeprecationWarning)
-        return self.iterorderable()
-
     def orderable(self):
         return list(self.iterorderable())
 
-    def sortable(self):
-        warnings.warn("`sortable` is deprecated, use `orderable` instead.",
-                      DeprecationWarning)
-        return self.orderable
-
     def itervisible(self):
         """
         Same as `.iterorderable` but only returns visible `.BoundColumn`
@@ -645,5 +593,5 @@ class BoundColumns(object):
             raise KeyError("Column with name '%s' does not exist; "
                            "choices are: %s" % (index, self.names()))
         else:
-            raise TypeError('row indices must be integers or str, not %s'
+            raise TypeError('Column indices must be integers or str, not %s'
                             % type(index).__name__)
diff --git a/django_tables2/columns/booleancolumn.py b/django_tables2/columns/booleancolumn.py
index 3c9b41e..6a8fc61 100644
--- a/django_tables2/columns/booleancolumn.py
+++ b/django_tables2/columns/booleancolumn.py
@@ -1,11 +1,13 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
-from .base import Column, library
+
 from django.db import models
-from django.utils.html import escape
-from django.utils.safestring import mark_safe
-from django_tables2.utils import AttributeDict
-import six
+from django.utils import six
+from django.utils.html import escape, format_html
+
+from django_tables2.utils import Accessor, AttributeDict
+
+from .base import Column, library
 
 
 @library.register
@@ -30,16 +32,32 @@ class BooleanColumn(Column):
         self.yesno = (yesno.split(',') if isinstance(yesno, six.string_types)
                       else tuple(yesno))
         if null:
-            kwargs["empty_values"] = ()
+            kwargs['empty_values'] = ()
         super(BooleanColumn, self).__init__(**kwargs)
 
-    def render(self, value):
+    def render(self, value, record, bound_column):
+        # if record is a model, we need to check if it has choices defined.
+        # If that's the case, we need to inverse lookup the value to convert to
+        # a boolean.
+        if hasattr(record, '_meta'):
+            try:
+                field = bound_column.accessor.get_field(record)
+
+                if hasattr(field, 'choices') and field.choices is not None:
+                    value = next(val for val, name in field.choices if name == value)
+            except:
+                pass
+
         value = bool(value)
         text = self.yesno[int(not value)]
-        html = '<span %s>%s</span>'
-        attrs = {"class": six.text_type(value).lower()}
-        attrs.update(self.attrs.get("span", {}))
-        return mark_safe(html % (AttributeDict(attrs).as_html(), escape(text)))
+        attrs = {'class': six.text_type(value).lower()}
+        attrs.update(self.attrs.get('span', {}))
+
+        return format_html(
+            '<span {}>{}</span>',
+            AttributeDict(attrs).as_html(),
+            escape(text)
+        )
 
     @classmethod
     def from_field(cls, field):
diff --git a/django_tables2/columns/checkboxcolumn.py b/django_tables2/columns/checkboxcolumn.py
index d2889f6..e5b4ed1 100644
--- a/django_tables2/columns/checkboxcolumn.py
+++ b/django_tables2/columns/checkboxcolumn.py
@@ -1,8 +1,10 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
 from django.utils.safestring import mark_safe
-from django_tables2.utils import AttributeDict
-import warnings
+
+from django_tables2.utils import Accessor, AttributeDict
+
 from .base import Column, library
 
 
@@ -38,26 +40,13 @@ class CheckBoxColumn(Column):
     - *input*     -- ``<input>`` elements in both ``<td>`` and ``<th>``.
     - *th__input* -- Replaces *input* attrs in header cells.
     - *td__input* -- Replaces *input* attrs in body cells.
-    """
-    def __init__(self, attrs=None, **extra):
-        # For backwards compatibility, passing in a normal dict effectively
-        # should assign attributes to the `<input>` tag.
-        valid = set(("input", "th__input", "td__input", "th", "td", "cell"))
-        if attrs and not set(attrs) & set(valid):
-            # if none of the keys in attrs are actually valid, assume it's some
-            # old code that should be be interpreted as {"td__input": ...}
-            warnings.warn('attrs keys must be one of %s, interpreting as {"td__input": %s}'
-                          % (', '.join(valid), attrs), DeprecationWarning)
-            attrs = {"td__input": attrs}
-        # This is done for backwards compatible too, there used to be a
-        # ``header_attrs`` argument, but this has been deprecated. We'll
-        # maintain it for a while by translating it into ``head.checkbox``.
-        if "header_attrs" in extra:
-            warnings.warn('header_attrs argument is deprecated, '
-                          'use attrs={"th__input": ...} instead',
-                          DeprecationWarning)
-            attrs.setdefault('th__input', {}).update(extra.pop('header_attrs'))
 
+    To render the checkbox as checked, use the *checked* argument with a
+    accessor, boolean or callable returning boolean. If it resolves to a truthy
+    value, the checkbox will be rendered as checked.
+    """
+    def __init__(self, attrs=None, checked=None, **extra):
+        self.checked = checked
         kwargs = {'orderable': False, 'attrs': attrs}
         kwargs.update(extra)
         super(CheckBoxColumn, self).__init__(**kwargs)
@@ -70,13 +59,35 @@ class CheckBoxColumn(Column):
         attrs = AttributeDict(default, **(specific or general or {}))
         return mark_safe('<input %s/>' % attrs.as_html())
 
-    def render(self, value, bound_column):  # pylint: disable=W0221
+    def render(self, value, bound_column, record):
         default = {
             'type': 'checkbox',
             'name': bound_column.name,
             'value': value
         }
+        if self.is_checked(value, record):
+            default.update({
+                'checked': 'checked',
+            })
+
         general = self.attrs.get('input')
         specific = self.attrs.get('td__input')
         attrs = AttributeDict(default, **(specific or general or {}))
         return mark_safe('<input %s/>' % attrs.as_html())
+
+    def is_checked(self, value, record):
+        """
+        Determine if the checkbox should be checked
+        """
+        if self.checked is None:
+            return False
+        if self.checked is True:
+            return True
+
+        if callable(self.checked):
+            return bool(self.checked(value, record))
+
+        checked = Accessor(self.checked)
+        if checked in record:
+            return bool(record[checked])
+        return False
diff --git a/django_tables2/columns/datecolumn.py b/django_tables2/columns/datecolumn.py
index a2ed466..9598390 100644
--- a/django_tables2/columns/datecolumn.py
+++ b/django_tables2/columns/datecolumn.py
@@ -1,6 +1,8 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
 from django.db import models
+
 from .base import library
 from .templatecolumn import TemplateColumn
 
@@ -17,7 +19,7 @@ class DateColumn(TemplateColumn):
                    ``SHORT_DATE_FORMAT`` setting, otherwise use ``DATE_FORMAT``
     :type   short: `bool`
     """
-    def __init__(self, format=None, short=True, *args, **kwargs):  # pylint: disable=W0622
+    def __init__(self, format=None, short=True, *args, **kwargs):
         if format is None:
             format = 'SHORT_DATE_FORMAT' if short else 'DATE_FORMAT'
         template = '{{ value|date:"%s"|default:default }}' % format
diff --git a/django_tables2/columns/datetimecolumn.py b/django_tables2/columns/datetimecolumn.py
index 41c51c9..9ee469d 100644
--- a/django_tables2/columns/datetimecolumn.py
+++ b/django_tables2/columns/datetimecolumn.py
@@ -1,6 +1,8 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
 from django.db import models
+
 from .base import library
 from .templatecolumn import TemplateColumn
 
@@ -10,13 +12,14 @@ class DateTimeColumn(TemplateColumn):
     """
     A column that renders datetimes in the local timezone.
 
-    :param format: format string for datetime (optional)
+    :param format: format string for datetime (optional).
+                   Note that *format* uses Django's `date` template tag syntax.
     :type  format: `unicode`
-    :param  short: if *format* is not specifid, use Django's
+    :param  short: if *format* is not specified, use Django's
                    ``SHORT_DATETIME_FORMAT``, else ``DATETIME_FORMAT``
     :type   short: `bool`
     """
-    def __init__(self, format=None, short=True, *args, **kwargs):  # pylint: disable=W0622
+    def __init__(self, format=None, short=True, *args, **kwargs):
         if format is None:
             format = 'SHORT_DATETIME_FORMAT' if short else 'DATETIME_FORMAT'
         template = '{{ value|date:"%s"|default:default }}' % format
diff --git a/django_tables2/columns/emailcolumn.py b/django_tables2/columns/emailcolumn.py
index 5736026..b6804f8 100644
--- a/django_tables2/columns/emailcolumn.py
+++ b/django_tables2/columns/emailcolumn.py
@@ -1,6 +1,8 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
 from django.db import models
+
 from .base import library
 from .linkcolumn import BaseLinkColumn
 
@@ -31,7 +33,7 @@ class EmailColumn(BaseLinkColumn):
 
     """
     def render(self, value):
-        return self.render_link("mailto:%s" % value, text=value)
+        return self.render_link('mailto:%s' % value, text=value)
 
     @classmethod
     def from_field(cls, field):
diff --git a/django_tables2/columns/filecolumn.py b/django_tables2/columns/filecolumn.py
index 6555ec9..6517e7f 100644
--- a/django_tables2/columns/filecolumn.py
+++ b/django_tables2/columns/filecolumn.py
@@ -1,9 +1,14 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
+import os
+
 from django.db import models
+from django.utils.html import format_html
 from django.utils.safestring import mark_safe
+
 from django_tables2.utils import AttributeDict
-import os
+
 from .base import Column, library
 
 
@@ -35,7 +40,7 @@ class FileColumn(Column):
         super(FileColumn, self).__init__(**kwargs)
 
     def render(self, value):
-        storage = getattr(value, "storage", None)
+        storage = getattr(value, 'storage', None)
         exists = None
         url = None
         if storage:
@@ -45,7 +50,7 @@ class FileColumn(Column):
             url = storage.url(value.name)
 
         else:
-            if self.verify_exists and hasattr(value, "name"):
+            if self.verify_exists and hasattr(value, 'name'):
                 # ignore negatives, perhaps the file has a name but it doesn't
                 # represent a local path... better to stay neutral than give a
                 # false negative.
@@ -57,19 +62,17 @@ class FileColumn(Column):
         if url:
             attrs['href'] = url
 
-        # add "exists" or "missing" to the class list
         classes = [c for c in attrs.get('class', '').split(' ') if c]
-        if exists is True:
-            classes.append("exists")
-        elif exists is False:
-            classes.append("missing")
-        attrs['class'] = " ".join(classes)
+        if exists is not None:
+            classes.append('exists' if exists else 'missing')
+        attrs['class'] = ' '.join(classes)
 
-        html = '<{tag} {attrs}>{text}</{tag}>'.format(
+        return format_html(
+            '<{tag} {attrs}>{text}</{tag}>',
             tag=tag,
             attrs=attrs.as_html(),
-            text=os.path.basename(value.name))
-        return mark_safe(html)
+            text=os.path.basename(value.name)
+        )
 
     @classmethod
     def from_field(cls, field):
diff --git a/django_tables2/columns/linkcolumn.py b/django_tables2/columns/linkcolumn.py
index 3b15cdc..2e3488c 100644
--- a/django_tables2/columns/linkcolumn.py
+++ b/django_tables2/columns/linkcolumn.py
@@ -1,11 +1,10 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
 
-import warnings
-
 from django.core.urlresolvers import reverse
 from django.utils.html import format_html
-from django_tables2.utils import A, AttributeDict
+
+from django_tables2.utils import Accessor, AttributeDict
 
 from .base import Column, library
 
@@ -18,13 +17,6 @@ class BaseLinkColumn(Column):
     ``<a href="...">`` tag.
     """
     def __init__(self, attrs=None, *args, **kwargs):
-        valid = set(("a", "th", "td", "cell"))
-        if attrs and not set(attrs) & set(valid):
-            # if none of the keys in attrs are actually valid, assume it's some
-            # old code that should be be interpreted as {"a": ...}
-            warnings.warn('attrs keys must be one of %s, interpreting as {"a": %s}'
-                          % (', '.join(valid), attrs), DeprecationWarning)
-            attrs = {"a": attrs}
         kwargs['attrs'] = attrs
         super(BaseLinkColumn, self).__init__(*args, **kwargs)
 
@@ -40,9 +32,11 @@ class BaseLinkColumn(Column):
                               self.attrs.get('a', {}))
         attrs['href'] = uri
 
-        return format_html('<a {attrs}>{text}</a>',
-                           attrs=attrs.as_html(),
-                           text=text)
+        return format_html(
+            '<a {attrs}>{text}</a>',
+            attrs=attrs.as_html(),
+            text=text
+        )
 
 
 @library.register
@@ -127,49 +121,49 @@ class LinkColumn(BaseLinkColumn):
         self.current_app = current_app
         self.text_value = text
 
-    def compose_url(self, record):
+    def compose_url(self, record, *args, **kwargs):
         '''Compose the url if the column is constructed with a viewname.'''
-        if isinstance(self.viewname, A):
-            viewname = self.viewname.resolve(record)
-        else:
-            viewname = self.viewname
 
-        # The following params + if statements create optional arguments to
-        # pass to Django's reverse() function.
+        if self.viewname is None:
+            if not hasattr(record, 'get_absolute_url'):
+                raise TypeError('if viewname=None, record must define a get_absolute_url')
+            return record.get_absolute_url()
+
+        def resolve_if_accessor(val):
+            return val.resolve(record) if isinstance(val, Accessor) else val
+
+        viewname = resolve_if_accessor(self.viewname)
+
+        # Collect the optional arguments for django's reverse()
         params = {}
         if self.urlconf:
-            params['urlconf'] = (self.urlconf.resolve(record)
-                                 if isinstance(self.urlconf, A)
-                                 else self.urlconf)
+            params['urlconf'] = resolve_if_accessor(self.urlconf)
         if self.args:
-            params['args'] = [a.resolve(record) if isinstance(a, A) else a
-                              for a in self.args]
+            params['args'] = [resolve_if_accessor(a) for a in self.args]
         if self.kwargs:
-            params['kwargs'] = {}
-            for key, val in self.kwargs.items():
-                # If we're dealing with an Accessor (A), resolve it, otherwise
-                # use the value verbatim.
-                params['kwargs'][str(key)] = (val.resolve(record)
-                                              if isinstance(val, A) else val)
+            params['kwargs'] = {key: resolve_if_accessor(val) for key, val in self.kwargs.items()}
         if self.current_app:
-            params['current_app'] = (self.current_app.resolve(record)
-                                     if isinstance(self.current_app, A)
-                                     else self.current_app)
+            params['current_app'] = resolve_if_accessor(self.current_app)
 
         return reverse(viewname, **params)
 
-    def render(self, value, record, bound_column):  # pylint: disable=W0221
-        if self.viewname is None:
-            if not hasattr(record, 'get_absolute_url'):
-                raise TypeError('if viewname=None, record must define a get_absolute_url')
-            url = record.get_absolute_url()
-        else:
-            url = self.compose_url(record)
-
+    def render(self, value, record, bound_column):
         text_value = value
         if self.text_value:
             text_value = self.text_value
             if callable(text_value):
                 text_value = text_value(record)
 
-        return self.render_link(url, text=text_value)
+        return self.render_link(self.compose_url(record, bound_column), text=text_value)
+
+
+ at library.register
+class RelatedLinkColumn(LinkColumn):
+    '''
+    Render a link to a related object using related object's ``get_absolute_url``
+    '''
+
+    def compose_url(self, record, bound_column):
+        accessor = self.accessor if self.accessor else Accessor(bound_column)
+
+        return accessor.resolve(record).get_absolute_url()
diff --git a/django_tables2/columns/templatecolumn.py b/django_tables2/columns/templatecolumn.py
index 223e566..4686d2c 100644
--- a/django_tables2/columns/templatecolumn.py
+++ b/django_tables2/columns/templatecolumn.py
@@ -1,7 +1,9 @@
 # coding: utf-8
 from __future__ import absolute_import, unicode_literals
+
... 3504 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-tables.git



More information about the Python-modules-commits mailing list