16 |
17 |
58 |
59 |
60 | {% render_table people %}
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/example/urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | from django.conf.urls import include, url
4 |
5 | import app.views
6 |
7 |
8 | urlpatterns = [
9 | url(r'^$', app.views.base, name='base'),
10 | url(r'^datasource/ajax/$', app.views.ajax, name='ajax'),
11 | url(r'^datasource/ajaxsource/$', app.views.ajax_source, name='ajax_source'),
12 | url(r'^datasource/ajaxsource/api/$', app.views.MyDataView.as_view(), name='ajax_source_api'),
13 |
14 | url(r'^column/sequence/$', app.views.sequence_column, name='sequence_column'),
15 | url(r'^column/calendar/$', app.views.calendar_column, name='calendar_column'),
16 | url(r'^column/link/$', app.views.link_column, name='link_column'),
17 | url(r'^column/checkbox/$', app.views.checkbox_column, name='checkbox_column'),
18 |
19 | url(r'^extensions/buttons/$', app.views.buttons_extension, name='buttons_extension'),
20 |
21 | url(r'^user/(\d+)/$', app.views.user_profile, name='user_profile'),
22 | url(r'^table/', include('table.urls')),
23 | ]
24 |
--------------------------------------------------------------------------------
/example/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for table project.
3 |
4 | This module contains the WSGI application used by Django's development server
5 | and any production WSGI deployments. It should expose a module-level variable
6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
7 | this application via the ``WSGI_APPLICATION`` setting.
8 |
9 | Usually you will have the standard Django WSGI application here, but it also
10 | might make sense to replace the whole Django WSGI application with a custom one
11 | that later delegates to the Django one. For example, you could introduce WSGI
12 | middleware here, or combine a Django application with an application of another
13 | framework.
14 |
15 | """
16 | import os
17 |
18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "table.settings")
19 |
20 | # This application object is used by any WSGI server configured to use this
21 | # file. This includes Django's development server, if the WSGI_APPLICATION
22 | # setting points here.
23 | from django.core.wsgi import get_wsgi_application
24 | application = get_wsgi_application()
25 |
26 | # Apply WSGI middleware here.
27 | # from helloworld.wsgi import HelloWorldApplication
28 | # application = HelloWorldApplication(application)
29 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | from setuptools import setup, find_packages
4 |
5 |
6 | setup(
7 | name='django-datatable',
8 | version='0.3.1',
9 | author='shymonk',
10 | author_email='hellojohn201@gmail.com',
11 | url='https://github.com/shymonk/django-datatable',
12 | description='A simple Django app to origanize data in tabular form.',
13 | long_description=open('README.rst').read(),
14 | packages=find_packages(exclude=['test*', 'example*']),
15 | include_package_data=True,
16 | zip_safe=False,
17 | install_requires=["django>=1.5"],
18 | license='MIT License',
19 | classifiers=[
20 | 'Development Status :: 3 - Alpha',
21 | 'Environment :: Web Environment',
22 | 'Framework :: Django',
23 | 'Intended Audience :: Developers',
24 | 'License :: OSI Approved :: MIT License',
25 | 'Operating System :: OS Independent',
26 | 'Programming Language :: Python',
27 | 'Programming Language :: Python :: 2',
28 | 'Programming Language :: Python :: 2.7',
29 | 'Topic :: Internet :: WWW/HTTP',
30 | 'Topic :: Software Development :: Libraries',
31 | ],
32 | )
33 |
--------------------------------------------------------------------------------
/table/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 |
5 | from .tables import Table, TableData # NOQA
6 |
--------------------------------------------------------------------------------
/table/columns/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | from .base import Column, BoundColumn # NOQA
4 | from .linkcolumn import LinkColumn, Link, ImageLink # NOQA
5 | from .datetimecolumn import DatetimeColumn # NOQA
6 | from .calendarcolumn import MonthsColumn, WeeksColumn, DaysColumn, CalendarColumn # NOQA
7 | from .sequencecolumn import SequenceColumn # NOQA
8 | from .checkboxcolumn import CheckboxColumn # NOQA
9 |
--------------------------------------------------------------------------------
/table/columns/base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | from django.utils.html import escape
4 |
5 | from table.utils import Accessor, AttributesDict
6 |
7 |
8 | class Column(object):
9 | """ Represents a single column.
10 | """
11 |
12 | instance_order = 0
13 |
14 | def __init__(self, field=None, header=None, attrs=None, header_attrs=None,
15 | header_row_order=0, sortable=True, searchable=True, safe=True,
16 | visible=True, space=True):
17 | self.field = field
18 | self.attrs = attrs or {}
19 | self.sortable = sortable
20 | self.searchable = searchable
21 | self.safe = safe
22 | self.visible = visible
23 | self.space = space
24 | self.header = ColumnHeader(header, header_attrs, header_row_order)
25 |
26 | self.instance_order = Column.instance_order
27 | Column.instance_order += 1
28 |
29 | def __str__(self):
30 | return self.header.text
31 |
32 | def render(self, obj):
33 | text = Accessor(self.field).resolve(obj)
34 | return escape(text)
35 |
36 |
37 | class BoundColumn(object):
38 | """ A run-time version of Column. The difference between
39 | BoundColumn and Column is that BoundColumn objects include the
40 | relationship between a Column and a object. In practice, this
41 | means that a BoundColumn knows the "field value" given to the
42 | Column when it was declared on the Table.
43 | """
44 | def __init__(self, obj, column):
45 | self.obj = obj
46 | self.column = column
47 | self.base_attrs = column.attrs.copy()
48 |
49 | # copy non-object-related attributes to self directly
50 | self.field = column.field
51 | self.sortable = column.sortable
52 | self.searchable = column.searchable
53 | self.safe = column.safe
54 | self.visible = column.visible
55 | self.header = column.header
56 |
57 | @property
58 | def html(self):
59 | text = self.column.render(self.obj)
60 | if text is None:
61 | return ''
62 | else:
63 | return text
64 |
65 | @property
66 | def attrs(self):
67 | attrs = {}
68 | for attr_name, attr in self.base_attrs.items():
69 | if callable(attr):
70 | attrs[attr_name] = attr(self.obj, self.field)
71 | elif isinstance(attr, Accessor):
72 | attrs[attr_name] = attr.resolve(self.obj)
73 | else:
74 | attrs[attr_name] = attr
75 | return AttributesDict(attrs).render()
76 |
77 |
78 | class ColumnHeader(object):
79 | def __init__(self, text=None, attrs=None, row_order=0):
80 | self.text = text
81 | self.base_attrs = attrs or {}
82 | self.row_order = row_order
83 |
84 | @property
85 | def attrs(self):
86 | return AttributesDict(self.base_attrs).render()
87 |
--------------------------------------------------------------------------------
/table/columns/calendarcolumn.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 | import calendar
4 | from datetime import timedelta
5 |
6 | from table.columns.base import Column
7 | from table.columns.sequencecolumn import SequenceColumn
8 |
9 |
10 | class DaysColumn(SequenceColumn):
11 | def __init__(self, field=None, start_date=None, end_date=None, **kwargs):
12 | total_days = (end_date - start_date).days + 1
13 | headers = [(start_date + timedelta(day)).strftime("%d")
14 | for day in range(total_days)]
15 | super(DaysColumn, self).__init__(field, headers, **kwargs)
16 |
17 |
18 | class WeeksColumn(SequenceColumn):
19 | WEEK_NAME = calendar.day_abbr
20 |
21 | def __init__(self, field=None, start_date=None, end_date=None, **kwargs):
22 | total_days = (end_date - start_date).days + 1
23 | headers = [self.WEEK_NAME[(start_date + timedelta(day)).weekday()]
24 | for day in range(total_days)]
25 | super(WeeksColumn, self).__init__(field, headers, **kwargs)
26 |
27 |
28 | class MonthsColumn(SequenceColumn):
29 | MONTH_NAME = calendar.month_name[1:]
30 |
31 | def __init__(self, field=None, start_date=None, end_date=None, **kwargs):
32 | delta_year = end_date.year - start_date.year
33 | delta_month = end_date.month - start_date.month
34 | total_months = delta_year * 12 + delta_month + 1
35 | headers = [self.MONTH_NAME[(start_date.month + month - 1) % 12]
36 | for month in range(total_months)]
37 | super(MonthsColumn, self).__init__(field, headers, **kwargs)
38 |
39 |
40 | class InlineDaysColumn(DaysColumn):
41 | def __init__(self, field=None, start_date=None, end_date=None, **kwargs):
42 | kwargs['sortable'] = False
43 | kwargs.setdefault('header_attrs', {})
44 | kwargs['header_attrs'].update({'class': 'calendar'})
45 | super(InlineDaysColumn, self).__init__(field, start_date, end_date, **kwargs)
46 |
47 |
48 | class InlineWeeksColumn(WeeksColumn):
49 | def __init__(self, start_date=None, end_date=None, **kwargs):
50 | kwargs['space'] = False
51 | kwargs['sortable'] = False
52 | kwargs.setdefault('header_attrs', {})
53 | kwargs['header_attrs'].update({'class': 'calendar'})
54 | super(InlineWeeksColumn, self).__init__(start_date=start_date, end_date=end_date, **kwargs)
55 |
56 |
57 | class InlineMonthsColumn(MonthsColumn):
58 | def __init__(self, start_date=None, end_date=None, **kwargs):
59 | self.start_date = start_date
60 | self.end_date = end_date
61 | kwargs['space'] = False
62 | kwargs['sortable'] = False
63 | super(InlineMonthsColumn, self).__init__(start_date=start_date, end_date=end_date, **kwargs)
64 |
65 | def get_column(self, key):
66 | return Column(field=self.get_field(key),
67 | header=self.get_header(key),
68 | header_attrs=self.get_column_header_attrs(key),
69 | **self.kwargs)
70 |
71 | def get_column_header_attrs(self, index):
72 | header_attrs = self.kwargs.pop("header_attrs", {})
73 | header_attrs.update({"colspan": self.get_column_span(index)})
74 | return header_attrs
75 |
76 | def get_column_span(self, index):
77 | """
78 | Get `colspan` value for