added a test to reveal problem with using querysets as data sources
authorBradley Ayers <bradley.ayers@enigmainteractive.com>
Fri, 25 Feb 2011 07:36:14 +0000 (17:36 +1000)
committerBradley Ayers <bradley.ayers@enigmainteractive.com>
Fri, 25 Feb 2011 07:36:14 +0000 (17:36 +1000)
django_tables/tables.py
django_tables/tests/__init__.py
django_tables/tests/models.py
django_tables/tests/testapp/__init__.py [deleted file]
django_tables/tests/testapp/models.py [deleted file]
docs/index.rst

index df26d8f747b623807f6396561b4d229c70df4c7a..5b4f8d30a32277b65d1ade50568c25c29a71e4c0 100644 (file)
@@ -16,8 +16,9 @@ __all__ = ('Table',)
 QUERYSET_ACCESSOR_SEPARATOR = '__'
 
 class TableData(object):
-    """Exposes a consistent API for a table data. It currently supports a query
-    set and a list of dicts.
+    """Exposes a consistent API for a table data. It currently supports a
+    :class:`QuerySet` or a ``list`` of ``dict``s.
+
     """
     def __init__(self, data, table):
         from django.db.models.query import QuerySet
@@ -68,6 +69,7 @@ class TableData(object):
         """Populates self._data with missing values based on the default value
         for each column. It will create new items in the dataset (not modify
         existing ones).
+
         """
         for i, item in enumerate(data):
             # add data that is missing from the source. we do this now
@@ -99,8 +101,9 @@ class TableData(object):
     def data_for_cell(self, bound_column, bound_row, apply_formatter=True):
         """Calculate the value of a cell given a bound row and bound column.
 
-        *formatting* – Apply column formatter after retrieving the value from
-                       the data.
+        :param formatting:
+            Apply column formatter after retrieving the value from the data.
+
         """
         value = Accessor(bound_column.accessor).resolve(bound_row.data)
         # try and use default value if we've only got 'None'
@@ -116,28 +119,13 @@ 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.
+    called ``base_columns``, taking into account parent class ``base_columns``
+    as well.
+
     """
     def __new__(cls, name, bases, attrs, parent_cols_from=None):
-        """The ``parent_cols_from`` argument determines from which attribute
-        we read the columns of a base class that this table might be
-        subclassing. This is useful for ``ModelTable`` (and possibly other
-        derivatives) which might want to differ between the declared columns
-        and others.
-
-        Note that if the attribute specified in ``parent_cols_from`` is not
-        found, we fall back to the default (``base_columns``), instead of
-        skipping over that base. This makes a table like the following work:
-
-            class MyNewTable(tables.ModelTable, MyNonModelTable):
-                pass
-
-        ``MyNewTable`` will be built by the ModelTable metaclass, which will
-        call this base with a modified ``parent_cols_from`` argument
-        specific to ModelTables. Since ``MyNonModelTable`` is not a
-        ModelTable, and thus does not provide that attribute, the columns
-        from that base class would otherwise be ignored.
+        """Ughhh document this :)
+
         """
         # extract declared columns
         columns = [(name, attrs.pop(name)) for name, column in attrs.items()
@@ -188,8 +176,13 @@ class Table(StrAndUnicode):
     def __init__(self, data, order_by=DefaultOrder):
         """Create a new table instance with the iterable ``data``.
 
-        If ``order_by`` is specified, the data will be sorted accordingly.
-        Otherwise, the sort order can be specified in the table options.
+        :param order_by:
+            If specified, it must be a sequence containing the names of columns
+            in the order that they should be ordered (much the same as
+            :method:`QuerySet.order_by`)
+
+            If not specified, the table will fall back to the
+            :attr:`Meta.order_by` setting.
 
         Note that unlike a ``Form``, tables are always bound to data. Also
         unlike a form, the ``columns`` attribute is read-only and returns
@@ -200,6 +193,7 @@ class Table(StrAndUnicode):
         the perfect fit for this. Instead, ``base_colums`` is copied to
         table instances, so modifying that will not touch the class-wide
         column list.
+        
         """
         self._rows = Rows(self)  # bound rows
         self._columns = Columns(self)  # bound columns
index 2cedec1af4b9ee25dc042e3b931a931ecfd56037..5572945029406e5eedff186bbc08fb579eb1915c 100644 (file)
@@ -1,10 +1,11 @@
 from attest import Tests
 from .core import core
 from .templates import templates
+from .models import models
 #from .memory import memory
-#from .models import models
 
-tests = Tests([core, templates])
+
+tests = Tests([core, templates, models])
 
 def suite():
     return tests.test_suite()
index c0bfaa5150e15fa2d2f178ceb6363a17c36a11f2..4148822e29ddcce479e443175abd7279578d13a6 100644 (file)
@@ -1,58 +1,87 @@
-"""Test ModelTable specific functionality.
-
-Sets up a temporary Django project using a memory SQLite database.
-"""
-
+from django.contrib.auth.models import User
 from django.conf import settings
 from django.core.paginator import *
 import django_tables as tables
+import django_tables.models as django_tables_models
 from attest import Tests
 
 
+# we're going to test against User, so let's create a few
+User.objects.create_user('fake-user-1', 'fake-1@example.com', 'password')
+User.objects.create_user('fake-user-2', 'fake-2@example.com', 'password')
+User.objects.create_user('fake-user-3', 'fake-3@example.com', 'password')
+User.objects.create_user('fake-user-4', 'fake-4@example.com', 'password')
+
+
 models = Tests()
-'''
 
-def setup_module(module):
-    settings.configure(**{
-        'DATABASE_ENGINE': 'sqlite3',
-        'DATABASE_NAME': ':memory:',
-        'INSTALLED_APPS': ('tests.testapp',)
-    })
 
-    from django.db import models
-    from django.core.management import call_command
+@models.context
+def transaction():
+    print 't1'
+    yield
+    print 't2'
+
+@models.context
+def context():
+    class Context(object):
+        class UserTable(tables.Table):
+            username = tables.Column()
+            first_name = tables.Column()
+            last_name = tables.Column()
+            email = tables.Column()
+            password = tables.Column()
+            is_staff = tables.Column()
+            is_active = tables.Column()
+            is_superuser = tables.Column()
+            last_login = tables.Column()
+            date_joined = tables.Column()
+
+    print 'c1'
+    yield Context
+    print 'c2'
+
+@models.test
+def simple(context):
+    table = context.UserTable(User.objects.all())
 
-    class City(models.Model):
-        name = models.TextField()
-        population = models.IntegerField(null=True)
-        class Meta:
-            app_label = 'testapp'
-    module.City = City
-
-    class Country(models.Model):
-        name = models.TextField()
-        population = models.IntegerField()
-        capital = models.ForeignKey(City, blank=True, null=True)
-        tld = models.TextField(verbose_name='Domain Extension', max_length=2)
-        system = models.TextField(blank=True, null=True)
-        null = models.TextField(blank=True, null=True)   # tests expect this to be always null!
-        null2 = models.TextField(blank=True, null=True)  #  - " -
-        def example_domain(self):
-            return 'example.%s' % self.tld
-        class Meta:
-            app_label = 'testapp'
-    module.Country = Country
-
-    # create the tables
-    call_command('syncdb', verbosity=1, interactive=False)
-
-    # create a couple of objects
-    berlin=City(name="Berlin"); berlin.save()
-    amsterdam=City(name="Amsterdam"); amsterdam.save()
-    Country(name="Austria", tld="au", population=8, system="republic").save()
-    Country(name="Germany", tld="de", population=81, capital=berlin).save()
-    Country(name="France", tld="fr", population=64, system="republic").save()
-    Country(name="Netherlands", tld="nl", population=16, system="monarchy", capital=amsterdam).save()
+
+'''
+class City(models.Model):
+    name = models.TextField()
+    population = models.IntegerField(null=True)
+
+    class Meta:
+        app_label = 'django_tables'
+django_tables_models.City = City
+
+
+class Country(models.Model):
+    name = models.TextField()
+    population = models.IntegerField()
+    capital = models.ForeignKey(City, blank=True, null=True)
+    tld = models.TextField(verbose_name='Domain Extension', max_length=2)
+    system = models.TextField(blank=True, null=True)
+    null = models.TextField(blank=True, null=True)   # tests expect this to be always null!
+    null2 = models.TextField(blank=True, null=True)  #  - " -
+
+    class Meta:
+        app_label = 'django_tables'
+
+    def example_domain(self):
+        return 'example.%s' % self.tld
+django_tables_models.Country = Country
+
+# create the tables
+call_command('syncdb', verbosity=1, interactive=False)
+
+# create a couple of objects
+berlin=City(name="Berlin"); berlin.save()
+amsterdam=City(name="Amsterdam"); amsterdam.save()
+Country(name="Austria", tld="au", population=8, system="republic").save()
+Country(name="Germany", tld="de", population=81, capital=berlin).save()
+Country(name="France", tld="fr", population=64, system="republic").save()
+Country(name="Netherlands", tld="nl", population=16, system="monarchy", capital=amsterdam).save()
 
 
 class TestDeclaration:
diff --git a/django_tables/tests/testapp/__init__.py b/django_tables/tests/testapp/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/django_tables/tests/testapp/models.py b/django_tables/tests/testapp/models.py
deleted file mode 100644 (file)
index 7bedc38..0000000
+++ /dev/null
@@ -1 +0,0 @@
-"""Empty demo app our tests can assign models to."""
index 40cdf4a9b69a467749a961185d69c4af6807c99f..e79be2135951714447279e6e85e54dacff22763e 100644 (file)
@@ -380,9 +380,15 @@ which can be iterated over:
 API Reference
 =============
 
-:class:`Column` Objects:
+:class:`Table` Objects:
 ------------------------
 
+.. autoclass:: django_tables.tables.Table
+    :members: __init__, data, order_by, rows, columns, as_html, paginate
+
+
+:class:`Column` Objects:
+------------------------
 
 .. autoclass:: django_tables.columns.Column
     :members: __init__, default, render