From af701b49cdf6329218fb01842297dd4eeefe65a4 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Thu, 2 Jun 2011 23:01:48 +1000 Subject: [PATCH] Added SingleTableMixin that makes adding a table to a view trivially easy. Partially resolves #10. --- django_tables/views.py | 81 ++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 59 ++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 django_tables/views.py diff --git a/django_tables/views.py b/django_tables/views.py new file mode 100644 index 0000000..886ffe3 --- /dev/null +++ b/django_tables/views.py @@ -0,0 +1,81 @@ +from django.core.exceptions import ImproperlyConfigured +from django.views.generic.base import TemplateResponseMixin +from django.views.generic.list import BaseListView + + +class SingleTableMixin(object): + """ + Adds a Table object to the context. Typically used with + ``TemplateResponseMixin``. + + :param table_class: table class + :type table_class: subclass of ``django_tables.Table`` + + :param table_data: data used to populate the table + :type table_data: any compatible data source + + :param context_table_name: name of the table's template variable (default: + "table") + :type context_table_name: ``string`` + + This mixin plays nice with the Django's ``MultipleObjectMixin`` by using + ``get_queryset()`` as a fallback for the table data source. + """ + table_class = None + table_data = None + context_table_name = None + + def get_table(self): + """ + Return a table object to use. The table has automatic support for + sorting and pagination. + """ + table_class = self.get_table_class() + table = table_class(self.get_table_data(), + order_by=self.request.GET.get("sort")) + table.paginate(page=self.request.GET.get("page", 1)) + return table + + def get_table_class(self): + """ + Return the class to use for the table. + """ + if self.table_class: + return self.table_class + raise ImproperlyConfigured(u"A table class was not specified. Define" + u"%(cls)s.table_class" + % {"cls": self.__class__.__name__}) + + def get_context_table_name(self, table): + """ + Get the name to use for the table's template variable. + """ + return self.context_table_name or "table" + + def get_table_data(self): + """ + Return the table data that should be used to populate the rows. + """ + if self.table_data: + return self.table_data + elif hasattr(self, "get_queryset"): + return self.get_queryset() + raise ImproperlyConfigured(u"Table data was not specified. Define " + u"%(cls)s.table_data" + % {"cls": self.__class__.__name__}) + + def get_context_data(self, **kwargs): + """ + Overriden version of ``TemplateResponseMixin`` to inject the table into + the template's context. + """ + context = super(SingleTableMixin, self).get_context_data(**kwargs) + table = self.get_table() + context[self.get_context_table_name(table)] = table + return context + + +class SingleTableView(SingleTableMixin, TemplateResponseMixin, BaseListView): + """ + Generic view that renders a template and passes in a ``Table`` object. + """ diff --git a/docs/index.rst b/docs/index.rst index 5915148..d6e6a3f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -615,6 +615,65 @@ which can be iterated over: +Class Based Generic Mixins +========================== + +Django 1.3 introduced `class based views`__ as a mechanism to reduce the +repetition in view code. django-tables comes with a single class based view +mixin: ``SingleTableMixin``. It makes it trivial to incorporate a table into a +view/template, however it requires a few variables to be defined on the view: + +- ``table_class`` –- the table class to use, e.g. ``SimpleTable`` +- ``table_data`` (or ``get_table_data()``) -- the data used to populate the + table +- ``context_table_name`` -- the name of template variable containing the table + object + +.. __: https://docs.djangoproject.com/en/1.3/topics/class-based-views/ + +For example: + +.. code-block:: python + + from django_tables.views import SingleTableMixin + from django.generic.views.list import ListView + + + class Simple(models.Model): + first_name = models.CharField(max_length=200) + last_name = models.CharField(max_length=200) + + + class SimpleTable(tables.Table): + first_name = tables.Column() + last_name = tables.Column() + + + class MyTableView(SingleTableMixin, ListView): + model = Simple + table_class = SimpleTable + + +The template could then be as simple as: + +.. code-block:: django + + {% load django_tables %} + {% render_table table %} + +Such little code is possible due to the example above taking advantage of +default values and ``SimpleTableMixin``'s eagarness at finding data sources +when one isn't explicitly defined. + +.. note:: + + If you want more than one table on a page, at the moment the simplest way + to do it is to use ``SimpleTableMixin`` for one table, and write the + boilerplate for the other yourself in ``get_context_data()``. Obviously + this isn't particularly elegant, and as such will hopefully be resolved in + the future. + + API Reference ============= -- 2.26.2