*.pyc
/*.komodoproject
/*.egg-info/
+/*.egg
/MANIFEST
/dist/
/build/
KeyError: 'c'
"""
- def __init__(self, table, data):
+ def __init__(self, table, record):
"""Initialise a new :class:`BoundRow` object where:
* *table* is the :class:`Table` in which this row exists.
- * *data* is a chunk of data that describes the information for this
- row. A "chunk" of data might be a :class:`Model` object, a ``dict``,
- or perhaps something else.
+ * *record* is a single record from the data source that is posed to
+ populate the row. A record could be a :class:`Model` object, a
+ ``dict``, or something else.
"""
- self.table = table
- self.data = data
+ self._table = table
+ self._record = record
+
+ @property
+ def table(self):
+ """The associated :term:`table`."""
+ return self._table
+
+ @property
+ def record(self):
+ """The data record from the data source which is used to populate this
+ row with data.
+
+ """
+ return self._record
def __iter__(self):
"""Iterate over the rendered values for cells in the row.
each cell.
"""
- for value in self.values:
- yield value
+ for column in self.table.columns:
+ # this uses __getitem__, using the name (rather than the accessor)
+ # is correct – it's what __getitem__ expects.
+ yield self[column.name]
def __getitem__(self, name):
"""Returns the final rendered value for a cell in the row, given the
else:
return item in self
- @property
- def values(self):
- for column in self.table.columns:
- # this uses __getitem__, using the name (rather than the accessor)
- # is correct – it's what __getitem__ expects.
- yield self[column.name]
-
class Rows(object):
"""Container for spawning BoundRows.
Apply column formatter after retrieving the value from the data.
"""
- value = Accessor(bound_column.accessor).resolve(bound_row.data)
+ value = Accessor(bound_column.accessor).resolve(bound_row.record)
# try and use default value if we've only got 'None'
if value is None and bound_column.default is not None:
value = bound_column.default()
"""
-Allows setting/changing/removing of chosen url query string parameters,
-while maintaining any existing others.
+Allows setting/changing/removing of chosen url query string parameters, while
+maintaining any existing others.
Expects the current request to be available in the context as ``request``.
{% set_url_param page=next_page %}
{% set_url_param page="" %}
{% set_url_param filter="books" page=1 %}
-"""
+"""
import urllib
import tokenize
import StringIO
from django.template.loader import get_template
from django.utils.safestring import mark_safe
+
register = template.Library()
return '?' + urllib.urlencode(params, doseq=True)
-def do_set_url_param(parser, token):
+@register.tag
+def set_url_param(parser, token):
bits = token.contents.split()
qschanges = {}
for i in bits[1:]:
"Argument syntax wrong: should be key=value")
return SetUrlParamNode(qschanges)
-register.tag('set_url_param', do_set_url_param)
-
class RenderTableNode(template.Node):
def __init__(self, table_var_name):
return get_template('django_tables/table.html').render(context)
-def do_render_table(parser, token):
+@register.tag
+def render_table(parser, token):
try:
_, table_var_name = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError,\
"%r tag requires a single argument" % token.contents.split()[0]
return RenderTableNode(table_var_name)
-
-register.tag('render_table', do_render_table)
+++ /dev/null
-from attest import Tests
-from .core import core
-from .templates import templates
-from .models import models
-#from .memory import memory
-
-
-tests = Tests([core, templates, models])
-
-def suite():
- return tests.test_suite()
-
-if __name__ == '__main__':
- tests.main()
+++ /dev/null
-"""Test the memory table functionality.
-
-TODO: A bunch of those tests probably fit better into test_basic, since
-they aren't really MemoryTable specific.
-"""
-
-from math import sqrt
-from attest import Tests
-from django.core.paginator import Paginator
-import django_tables as tables
-
-memory = Tests()
-
-@memory.test
-def basics():
- class StuffTable(tables.Table):
- name = tables.Column()
- answer = tables.Column(default=42)
- c = tables.Column(name="count", default=1)
- email = tables.Column(data="@")
-
- stuff = StuffTable([
- {'id': 1, 'name': 'Foo Bar', '@': 'foo@bar.org'},
- ])
-
- # access without order_by works
- stuff.data
- stuff.rows
-
- # make sure BoundColumnn.name always gives us the right thing, whether
- # the column explicitely defines a name or not.
- stuff.columns['count'].name == 'count'
- stuff.columns['answer'].name == 'answer'
-
- for r in stuff.rows:
- # unknown fields are removed/not-accessible
- assert 'name' in r
- assert not 'id' in r
- # missing data is available as default
- assert 'answer' in r
- assert r['answer'] == 42 # note: different from prev. line!
-
- # all that still works when name overrides are used
- assert not 'c' in r
- assert 'count' in r
- assert r['count'] == 1
-
- # columns with data= option work fine
- assert r['email'] == 'foo@bar.org'
-
- # [bug] splicing the table gives us valid, working rows
- assert list(stuff[0]) == list(stuff.rows[0])
- assert stuff[0]['name'] == 'Foo Bar'
-
- # changing an instance's base_columns does not change the class
- assert id(stuff.base_columns) != id(StuffTable.base_columns)
- stuff.base_columns['test'] = tables.Column()
- assert not 'test' in StuffTable.base_columns
-
- # optionally, exceptions can be raised when input is invalid
- tables.options.IGNORE_INVALID_OPTIONS = False
- try:
- assert_raises(ValueError, setattr, stuff, 'order_by', '-name,made-up-column')
- assert_raises(ValueError, setattr, stuff, 'order_by', ('made-up-column',))
- # when a column name is overwritten, the original won't work anymore
- assert_raises(ValueError, setattr, stuff, 'order_by', 'c')
- # reset for future tests
- finally:
- tables.options.IGNORE_INVALID_OPTIONS = True
-
-
-class TestRender:
- """Test use of the render_* methods.
- """
-
- def test(self):
- class TestTable(tables.MemoryTable):
- private_name = tables.Column(name='public_name')
- def render_public_name(self, data):
- # We are given the actual data dict and have direct access
- # to additional values for which no field is defined.
- return "%s:%s" % (data['private_name'], data['additional'])
-
- table = TestTable([{'private_name': 'FOO', 'additional': 'BAR'}])
- assert table.rows[0]['public_name'] == 'FOO:BAR'
-
- def test_not_sorted(self):
- """The render methods are not considered when sorting.
- """
- class TestTable(tables.MemoryTable):
- foo = tables.Column()
- def render_foo(self, data):
- return -data['foo'] # try to cause a reverse sort
- table = TestTable([{'foo': 1}, {'foo': 2}], order_by='asc')
- # Result is properly sorted, and the render function has never been called
- assert [r['foo'] for r in table.rows] == [-1, -2]
-
-
-def test_caches():
- """Ensure the various caches are effective.
- """
-
- class BookTable(tables.MemoryTable):
- name = tables.Column()
- answer = tables.Column(default=42)
- books = BookTable([
- {'name': 'Foo: Bar'},
- ])
-
- assert id(list(books.columns)[0]) == id(list(books.columns)[0])
- # TODO: row cache currently not used
- #assert id(list(books.rows)[0]) == id(list(books.rows)[0])
-
- # test that caches are reset after an update()
- old_column_cache = id(list(books.columns)[0])
- old_row_cache = id(list(books.rows)[0])
- books.update()
- assert id(list(books.columns)[0]) != old_column_cache
- assert id(list(books.rows)[0]) != old_row_cache
-
-def test_meta_sortable():
- """Specific tests for sortable table meta option."""
-
- def mktable(default_sortable):
- class BookTable(tables.MemoryTable):
- id = tables.Column(sortable=True)
- name = tables.Column(sortable=False)
- author = tables.Column()
- class Meta:
- sortable = default_sortable
- return BookTable([])
-
- global_table = mktable(None)
- for default_sortable, results in (
- (None, (True, False, True)), # last bool is global default
- (True, (True, False, True)), # last bool is table default
- (False, (True, False, False)), # last bool is table default
- ):
- books = mktable(default_sortable)
- assert [c.sortable for c in books.columns] == list(results)
-
- # it also works if the meta option is manually changed after
- # class and instance creation
- global_table._meta.sortable = default_sortable
- assert [c.sortable for c in global_table.columns] == list(results)
-
-
-def test_sort():
- class BookTable(tables.MemoryTable):
- id = tables.Column(direction='desc')
- name = tables.Column()
- pages = tables.Column(name='num_pages') # test rewritten names
- language = tables.Column(default='en') # default affects sorting
- rating = tables.Column(data='*') # test data field option
-
- books = BookTable([
- {'id': 1, 'pages': 60, 'name': 'Z: The Book', '*': 5}, # language: en
- {'id': 2, 'pages': 100, 'language': 'de', 'name': 'A: The Book', '*': 2},
- {'id': 3, 'pages': 80, 'language': 'de', 'name': 'A: The Book, Vol. 2', '*': 4},
- {'id': 4, 'pages': 110, 'language': 'fr', 'name': 'A: The Book, French Edition'}, # rating (with data option) is missing
- ])
-
- # None is normalized to an empty order by tuple, ensuring iterability;
- # it also supports all the cool methods that we offer for order_by.
- # This is true for the default case...
- assert books.order_by == ()
- iter(books.order_by)
- assert hasattr(books.order_by, 'toggle')
- # ...as well as when explicitly set to None.
- books.order_by = None
- assert books.order_by == ()
- iter(books.order_by)
- assert hasattr(books.order_by, 'toggle')
-
- # test various orderings
- def test_order(order, result):
- books.order_by = order
- assert [b['id'] for b in books.rows] == result
- test_order(('num_pages',), [1,3,2,4])
- test_order(('-num_pages',), [4,2,3,1])
- test_order(('name',), [2,4,3,1])
- test_order(('language', 'num_pages'), [3,2,1,4])
- # using a simple string (for convinience as well as querystring passing
- test_order('-num_pages', [4,2,3,1])
- test_order('language,num_pages', [3,2,1,4])
- # if overwritten, the declared fieldname has no effect
- test_order('pages,name', [2,4,3,1]) # == ('name',)
- # sort by column with "data" option
- test_order('rating', [4,2,3,1])
-
- # test the column with a default ``direction`` set to descending
- test_order('id', [4,3,2,1])
- test_order('-id', [1,2,3,4])
- # changing the direction afterwards is fine too
- books.base_columns['id'].direction = 'asc'
- test_order('id', [1,2,3,4])
- test_order('-id', [4,3,2,1])
- # a invalid direction string raises an exception
- assert_raises(ValueError, setattr, books.base_columns['id'], 'direction', 'blub')
-
- # [bug] test alternative order formats if passed to constructor
- BookTable([], 'language,-num_pages')
-
- # test invalid order instructions
- books.order_by = 'xyz'
- assert not books.order_by
- books.base_columns['language'].sortable = False
- books.order_by = 'language'
- assert not books.order_by
- test_order(('language', 'num_pages'), [1,3,2,4]) # as if: 'num_pages'
-
- # [bug] order_by did not run through setter when passed to init
- books = BookTable([], order_by='name')
- assert books.order_by == ('name',)
-
- # test table.order_by extensions
- books.order_by = ''
- assert books.order_by.polarize(False) == ()
- assert books.order_by.polarize(True) == ()
- assert books.order_by.toggle() == ()
- assert books.order_by.polarize(False, ['id']) == ('id',)
- assert books.order_by.polarize(True, ['id']) == ('-id',)
- assert books.order_by.toggle(['id']) == ('id',)
- books.order_by = 'id,-name'
- assert books.order_by.polarize(False, ['name']) == ('id', 'name')
- assert books.order_by.polarize(True, ['name']) == ('id', '-name')
- assert books.order_by.toggle(['name']) == ('id', 'name')
- # ``in`` operator works
- books.order_by = 'name'
- assert 'name' in books.order_by
- books.order_by = '-name'
- assert 'name' in books.order_by
- assert not 'language' in books.order_by
-
-
-def test_callable():
- """Data fields and the ``default`` option can be callables.
- """
-
- class MathTable(tables.MemoryTable):
- lhs = tables.Column()
- rhs = tables.Column()
- op = tables.Column(default='+')
- sum = tables.Column(default=lambda d: calc(d['op'], d['lhs'], d['rhs']))
-
- math = MathTable([
- {'lhs': 1, 'rhs': lambda x: x['lhs']*3}, # 1+3
- {'lhs': 9, 'rhs': lambda x: x['lhs'], 'op': '/'}, # 9/9
- {'lhs': lambda x: x['rhs']+3, 'rhs': 4, 'op': '-'}, # 7-4
- ])
-
- # function is called when queried
- def calc(op, lhs, rhs):
- if op == '+': return lhs+rhs
- elif op == '/': return lhs/rhs
- elif op == '-': return lhs-rhs
- assert [calc(row['op'], row['lhs'], row['rhs']) for row in math] == [4,1,3]
-
- # field function is called while sorting
- math.order_by = ('-rhs',)
- assert [row['rhs'] for row in math] == [9,4,3]
-
- # default function is called while sorting
- math.order_by = ('sum',)
- assert [row['sum'] for row in math] == [1,3,4]
-
-
-# TODO: all the column stuff might warrant it's own test file
-def test_columns():
- """Test Table.columns container functionality.
- """
-
- class BookTable(tables.MemoryTable):
- id = tables.Column(sortable=False, visible=False)
- name = tables.Column(sortable=True)
- pages = tables.Column(sortable=True)
- language = tables.Column(sortable=False)
- books = BookTable([])
-
- assert list(books.columns.sortable()) == [c for c in books.columns if c.sortable]
-
- # .columns iterator only yields visible columns
- assert len(list(books.columns)) == 3
- # visiblity of columns can be changed at instance-time
- books.columns['id'].visible = True
- assert len(list(books.columns)) == 4
-
-
-def test_column_order():
- """Test the order functionality of bound columns.
- """
-
- class BookTable(tables.MemoryTable):
- id = tables.Column()
- name = tables.Column()
- pages = tables.Column()
- language = tables.Column()
- books = BookTable([])
-
- # the basic name property is a no-brainer
- books.order_by = ''
- assert [c.name for c in books.columns] == ['id','name','pages','language']
-
- # name_reversed will always reverse, no matter what
- for test in ['', 'name', '-name']:
- books.order_by = test
- assert [c.name_reversed for c in books.columns] == ['-id','-name','-pages','-language']
-
- # name_toggled will always toggle
- books.order_by = ''
- assert [c.name_toggled for c in books.columns] == ['id','name','pages','language']
- books.order_by = 'id'
- assert [c.name_toggled for c in books.columns] == ['-id','name','pages','language']
- books.order_by = '-name'
- assert [c.name_toggled for c in books.columns] == ['id','name','pages','language']
- # other columns in an order_by will be dismissed
- books.order_by = '-id,name'
- assert [c.name_toggled for c in books.columns] == ['id','-name','pages','language']
-
- # with multi-column order, this is slightly more complex
- books.order_by = ''
- assert [str(c.order_by) for c in books.columns] == ['id','name','pages','language']
- assert [str(c.order_by_reversed) for c in books.columns] == ['-id','-name','-pages','-language']
- assert [str(c.order_by_toggled) for c in books.columns] == ['id','name','pages','language']
- books.order_by = 'id'
- assert [str(c.order_by) for c in books.columns] == ['id','id,name','id,pages','id,language']
- assert [str(c.order_by_reversed) for c in books.columns] == ['-id','id,-name','id,-pages','id,-language']
- assert [str(c.order_by_toggled) for c in books.columns] == ['-id','id,name','id,pages','id,language']
- books.order_by = '-pages,id'
- assert [str(c.order_by) for c in books.columns] == ['-pages,id','-pages,id,name','pages,id','-pages,id,language']
- assert [str(c.order_by_reversed) for c in books.columns] == ['-pages,-id','-pages,id,-name','-pages,id','-pages,id,-language']
- assert [str(c.order_by_toggled) for c in books.columns] == ['-pages,-id','-pages,id,name','pages,id','-pages,id,language']
-
- # querying whether a column is ordered is possible
- books.order_by = ''
- assert [c.is_ordered for c in books.columns] == [False, False, False, False]
- books.order_by = 'name'
- assert [c.is_ordered for c in books.columns] == [False, True, False, False]
- assert [c.is_ordered_reverse for c in books.columns] == [False, False, False, False]
- assert [c.is_ordered_straight for c in books.columns] == [False, True, False, False]
- books.order_by = '-pages'
- assert [c.is_ordered for c in books.columns] == [False, False, True, False]
- assert [c.is_ordered_reverse for c in books.columns] == [False, False, True, False]
- assert [c.is_ordered_straight for c in books.columns] == [False, False, False, False]
- # and even works with multi-column ordering
- books.order_by = 'id,-pages'
- assert [c.is_ordered for c in books.columns] == [True, False, True, False]
- assert [c.is_ordered_reverse for c in books.columns] == [False, False, True, False]
- assert [c.is_ordered_straight for c in books.columns] == [True, False, False, False]
+++ /dev/null
-from django.contrib.auth.models import User
-from django.conf import settings
-from django.core.paginator import *
-import django_tables as tables
-from django_attest import TestContext
-from attest import Tests
-
-
-models = Tests()
-
-
-models.context(TestContext())
-
-
-@models.context
-def samples():
- 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()
-
- # 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')
-
- yield Context
-
-
-@models.test
-def simple(dj, samples):
- table = samples.UserTable(User.objects.all())
-
-
-'''
-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:
- """Test declaration, declared columns and default model field columns.
- """
-
- def test_autogen_basic(self):
- class CountryTable(tables.ModelTable):
- class Meta:
- model = Country
-
- assert len(CountryTable.base_columns) == 8
- assert 'name' in CountryTable.base_columns
- assert not hasattr(CountryTable, 'name')
-
- # Override one model column, add another custom one, exclude one
- class CountryTable(tables.ModelTable):
- capital = tables.TextColumn(verbose_name='Name of capital')
- projected = tables.Column(verbose_name="Projected Population")
- class Meta:
- model = Country
- exclude = ['tld']
-
- assert len(CountryTable.base_columns) == 8
- assert 'projected' in CountryTable.base_columns
- assert 'capital' in CountryTable.base_columns
- assert not 'tld' in CountryTable.base_columns
-
- # Inheritance (with a different model) + field restrictions
- class CityTable(CountryTable):
- class Meta:
- model = City
- columns = ['id', 'name']
- exclude = ['capital']
-
- print CityTable.base_columns
- assert len(CityTable.base_columns) == 4
- assert 'id' in CityTable.base_columns
- assert 'name' in CityTable.base_columns
- assert 'projected' in CityTable.base_columns # declared in parent
- assert not 'population' in CityTable.base_columns # not in Meta:columns
- assert 'capital' in CityTable.base_columns # in exclude, but only works on model fields (is that the right behaviour?)
-
- def test_columns_custom_order(self):
- """Using the columns meta option, you can also modify the ordering.
- """
- class CountryTable(tables.ModelTable):
- foo = tables.Column()
- class Meta:
- model = Country
- columns = ('system', 'population', 'foo', 'tld',)
-
- assert [c.name for c in CountryTable().columns] == ['system', 'population', 'foo', 'tld']
-
- def test_columns_verbose_name(self):
- """Tests that the model field's verbose_name is used for the column
- """
- class CountryTable(tables.ModelTable):
- class Meta:
- model = Country
- columns = ('tld',)
-
- assert [c.column.verbose_name for c in CountryTable().columns] == ['Domain Extension']
-
-
-def test_basic():
- """Some tests here are copied from ``test_basic.py`` but need to be
- rerun with a ModelTable, as the implementation is different."""
-
- class CountryTable(tables.ModelTable):
- null = tables.Column(default="foo")
- tld = tables.Column(name="domain")
- class Meta:
- model = Country
- exclude = ('id',)
- countries = CountryTable()
-
- def test_country_table(table):
- for r in table.rows:
- # "normal" fields exist
- assert 'name' in r
- # unknown fields are removed/not accessible
- assert not 'does-not-exist' in r
- # ...so are excluded fields
- assert not 'id' in r
- # [bug] access to data that might be available, but does not
- # have a corresponding column is denied.
- assert_raises(Exception, "r['id']")
- # missing data is available with default values
- assert 'null' in r
- assert r['null'] == "foo" # note: different from prev. line!
- # if everything else fails (no default), we get None back
- assert r['null2'] is None
-
- # all that still works when name overrides are used
- assert not 'tld' in r
- assert 'domain' in r
- assert len(r['domain']) == 2 # valid country tld
- test_country_table(countries)
-
- # repeat the avove tests with a table that is not associated with a
- # model, and all columns being created manually.
- class CountryTable(tables.ModelTable):
- name = tables.Column()
- population = tables.Column()
- capital = tables.Column()
- system = tables.Column()
- null = tables.Column(default="foo")
- null2 = tables.Column()
- tld = tables.Column(name="domain")
- countries = CountryTable(Country)
- test_country_table(countries)
-
-
-def test_invalid_accessor():
- """Test that a column being backed by a non-existent model property
- is handled correctly.
-
- Regression-Test: There used to be a NameError here.
- """
- class CountryTable(tables.ModelTable):
- name = tables.Column(data='something-i-made-up')
- countries = CountryTable(Country)
- assert_raises(ValueError, countries[0].__getitem__, 'name')
-
-
-def test_caches():
- """Make sure the caches work for model tables as well (parts are
- reimplemented).
- """
- class CountryTable(tables.ModelTable):
- class Meta:
- model = Country
- exclude = ('id',)
- countries = CountryTable()
-
- assert id(list(countries.columns)[0]) == id(list(countries.columns)[0])
- # TODO: row cache currently not used
- #assert id(list(countries.rows)[0]) == id(list(countries.rows)[0])
-
- # test that caches are reset after an update()
- old_column_cache = id(list(countries.columns)[0])
- old_row_cache = id(list(countries.rows)[0])
- countries.update()
- assert id(list(countries.columns)[0]) != old_column_cache
- assert id(list(countries.rows)[0]) != old_row_cache
-
-def test_sort():
- class CountryTable(tables.ModelTable):
- tld = tables.Column(name="domain")
- population = tables.Column()
- system = tables.Column(default="republic")
- custom1 = tables.Column()
- custom2 = tables.Column(sortable=True)
- class Meta:
- model = Country
- countries = CountryTable()
-
- def test_order(order, result, table=countries):
- table.order_by = order
- assert [r['id'] for r in table.rows] == result
-
- # test various orderings
- test_order(('population',), [1,4,3,2])
- test_order(('-population',), [2,3,4,1])
- test_order(('name',), [1,3,2,4])
- # test sorting with a "rewritten" column name
- countries.order_by = 'domain,tld' # "tld" would be invalid...
- countries.order_by == ('domain',) # ...and is therefore removed
- test_order(('-domain',), [4,3,2,1])
- # test multiple order instructions; note: one row is missing a "system"
- # value, but has a default set; however, that has no effect on sorting.
- test_order(('system', '-population'), [2,4,3,1])
- # using a simple string (for convinience as well as querystring passing)
- test_order('-population', [2,3,4,1])
- test_order('system,-population', [2,4,3,1])
-
- # test column with a default ``direction`` set to descending
- class CityTable(tables.ModelTable):
- name = tables.Column(direction='desc')
- class Meta:
- model = City
- cities = CityTable()
- test_order('name', [1,2], table=cities) # Berlin to Amsterdam
- test_order('-name', [2,1], table=cities) # Amsterdam to Berlin
-
- # test invalid order instructions...
- countries.order_by = 'invalid_field,population'
- assert countries.order_by == ('population',)
- # ...in case of ModelTables, this primarily means that only
- # model-based colunns are currently sortable at all.
- countries.order_by = ('custom1', 'custom2')
- assert countries.order_by == ()
-
-def test_default_sort():
- class SortedCountryTable(tables.ModelTable):
- class Meta:
- model = Country
- order_by = '-name'
-
- # the order_by option is provided by TableOptions
- assert_equal('-name', SortedCountryTable()._meta.order_by)
-
- # the default order can be inherited from the table
- assert_equal(('-name',), SortedCountryTable().order_by)
- assert_equal(4, SortedCountryTable().rows[0]['id'])
-
- # and explicitly set (or reset) via __init__
- assert_equal(2, SortedCountryTable(order_by='system').rows[0]['id'])
- assert_equal(1, SortedCountryTable(order_by=None).rows[0]['id'])
-
-def test_callable():
- """Some of the callable code is reimplemented for modeltables, so
- test some specifics again.
- """
-
- class CountryTable(tables.ModelTable):
- null = tables.Column(default=lambda s: s['example_domain'])
- example_domain = tables.Column()
- class Meta:
- model = Country
- countries = CountryTable(Country)
-
- # model method is called
- assert [row['example_domain'] for row in countries] == \
- ['example.'+row['tld'] for row in countries]
-
- # column default method is called
- assert [row['example_domain'] for row in countries] == \
- [row['null'] for row in countries]
-
-
-def test_relationships():
- """Test relationship spanning."""
-
- class CountryTable(tables.ModelTable):
- # add relationship spanning columns (using different approaches)
- capital_name = tables.Column(data='capital__name')
- capital__population = tables.Column(name="capital_population")
- invalid = tables.Column(data="capital__invalid")
- class Meta:
- model = Country
- countries = CountryTable(Country.objects.select_related('capital'))
-
- # ordering and field access works
- countries.order_by = 'capital_name'
- assert [row['capital_name'] for row in countries.rows] == \
- [None, None, 'Amsterdam', 'Berlin']
-
- countries.order_by = 'capital_population'
- assert [row['capital_population'] for row in countries.rows] == \
- [None, None, None, None]
-
- # ordering by a column with an invalid relationship fails silently
- countries.order_by = 'invalid'
- assert countries.order_by == ()
-
-
-def test_pagination():
- """Pretty much the same as static table pagination, but make sure we
- provide the capability, at least for paginators that use it, to not
- have the complete queryset loaded (by use of a count() query).
-
- Note: This test changes the available cities, make sure it is last,
- or that tests that follow are written appropriately.
- """
- from django.db import connection
-
- class CityTable(tables.ModelTable):
- class Meta:
- model = City
- columns = ['name']
- cities = CityTable()
-
- # add some sample data
- City.objects.all().delete()
- for i in range(1,101):
- City.objects.create(name="City %d"%i)
-
- # for query logging
- settings.DEBUG = True
-
- # external paginator
- start_querycount = len(connection.queries)
- paginator = Paginator(cities.rows, 10)
- assert paginator.num_pages == 10
- page = paginator.page(1)
- assert len(page.object_list) == 10
- assert page.has_previous() == False
- assert page.has_next() == True
- # Make sure the queryset is not loaded completely - there must be two
- # queries, one a count(). This check is far from foolproof...
- assert len(connection.queries)-start_querycount == 2
-
- # using a queryset paginator is possible as well (although unnecessary)
- paginator = QuerySetPaginator(cities.rows, 10)
- assert paginator.num_pages == 10
-
- # integrated paginator
- start_querycount = len(connection.queries)
- cities.paginate(Paginator, 10, page=1)
- # rows is now paginated
- assert len(list(cities.rows.page())) == 10
- assert len(list(cities.rows.all())) == 100
- # new attributes
- assert cities.paginator.num_pages == 10
- assert cities.page.has_previous() == False
- assert cities.page.has_next() == True
- assert len(connection.queries)-start_querycount == 2
-
- # reset
- settings.DEBUG = False
-'''
# built documents.
#
# The short X.Y version.
-version = '0.4.0.alpha2.dev'
+version = '0.4.0.alpha2'
# The full version, including alpha/beta/rc tags.
-release = '0.4.0.alpha2.dev'
+release = '0.4.0.alpha2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-------------------------
.. autoclass:: django_tables.rows.BoundRow
- :members: __init__, values, __getitem__, __contains__, __iter__
+ :members: __init__, __getitem__, __contains__, __iter__, record, table
+
+
+Glossary
+========
+
+.. glossary::
+
+ table
+ The traditional concept of a table. i.e. a grid of rows and columns
+ containing data.
setup(
name='django-tables',
- version='0.4.0.alpha2.dev',
+ version='0.4.0.alpha2',
description='Table framework for Django',
author='Bradley Ayers',
include_package_data=True, # declarations in MANIFEST.in
install_requires=['Django >=1.1'],
+ tests_require=['Django >=1.1', 'Attest >=0.4', 'django_attest'],
+
+ test_loader='attest:FancyReporter.test_loader',
+ test_suite='tests.everything',
classifiers=[
'Environment :: Web Environment',
--- /dev/null
+from attest import AssertImportHook, Tests
+
+# Django's django.utils.module_loading.module_has_submodule is busted
+AssertImportHook.disable()
+
+
+from django.conf import settings
+
+# It's important to configure prior to importing the tests, as some of them
+# import Django's DB stuff.
+settings.configure(
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ }
+ },
+ INSTALLED_APPS = [
+ 'django_tables'
+ ]
+)
+
+
+from .core import core
+from .templates import templates
+from .models import models
+
+
+everything = Tests([core, templates, models])
"""Test the core table functionality."""
-
import copy
from attest import Tests, Assert
from django.http import Http404
--- /dev/null
+from django.contrib.auth.models import User
+from django.conf import settings
+from django.core.paginator import *
+import django_tables as tables
+from django_attest import TestContext
+from attest import Tests
+
+
+models = Tests()
+models.context(TestContext())
+
+
+@models.context
+def samples():
+ 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()
+
+ # 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')
+
+ yield Context
+
+
+@models.test
+def simple(dj, samples):
+ users = User.objects.all()
+ table = samples.UserTable(users)
+
+ for index, row in enumerate(table.rows):
+ user = users[index]
+ Assert(user.username) == row['username']
+ Assert(user.email) == row['email']