Django Tables 2
django-tables2 is a robust Django app designed for creating dynamic HTML tables with features like sorting, pagination, and custom column rendering. It helps streamline the display of complex data in a structured, user-friendly format within Django projects. The current version is 2.9.0, with a release cadence that generally follows Django's development cycle and feature enhancements.
Warnings
- breaking When upgrading from django-tables2 version 1.x to 2.x, direct access to the request object via `table.request` was removed.
- breaking The styling and template lookup API underwent significant changes in version 2.x. Custom table templates or CSS from 1.x versions will likely be incompatible and require updates.
- deprecated The `url` argument for `LinkColumn` is deprecated and will be removed in a future major release (e.g., 3.0).
- gotcha django-tables2 provides excellent display, sorting, and pagination features but does not include built-in filtering or search capabilities.
Install
-
pip install django-tables2
Imports
- Table
from django_tables2 import Table
- Column
from django_tables2 import Column
- LinkColumn
from django_tables2 import LinkColumn
- TemplateColumn
from django_tables2 import TemplateColumn
- SingleTableView
from django_tables2.views import SingleTableView
- render_table (template tag)
{% load render_table from django_tables2 %}
Quickstart
import os
import django
from django.conf import settings
from django.urls import path
from django.http import HttpResponse
from django.db import models
# Minimal Django setup for a self-contained quickstart
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
if not settings.configured:
settings.configure(
DEBUG=True,
SECRET_KEY='a-very-secret-key-for-dev-environment',
ROOT_URLCONF=__name__,
INSTALLED_APPS=[
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_tables2',
],
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.dirname(__file__)], # Look for templates in the same directory
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
],
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
STATIC_URL='/static/',
)
django.setup()
# 1. Define a simple Django model
class Person(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
city = models.CharField(max_length=100)
class Meta:
app_label = 'myapp' # Required for in-memory models setup
def __str__(self):
return self.name
# Simulate migrations for in-memory DB
from django.core.management import call_command
call_command('migrate', verbosity=0, interactive=False)
# Create some initial data
if not Person.objects.exists():
Person.objects.create(name='Alice', age=30, city='New York')
Person.objects.create(name='Bob', age=24, city='London')
Person.objects.create(name='Charlie', age=35, city='Paris')
# 2. Define a Table class
from django_tables2 import Table, LinkColumn
from django.db.models import A # for LinkColumn accessor
class PersonTable(Table):
name = LinkColumn('person_detail', args=[("pk", A("pk"))]) # Example LinkColumn
class Meta:
model = Person
template_name = "django_tables2/bootstrap4.html" # Use a built-in template
fields = ("name", "age", "city")
order_by = ("name",) # Default ordering
# 3. Define a Django View
from django_tables2.views import SingleTableView
class PeopleView(SingleTableView):
model = Person
table_class = PersonTable
template_name = 'people_list.html'
# Simple detail view for the LinkColumn example
def person_detail_view(request, pk):
try:
person = Person.objects.get(pk=pk)
return HttpResponse(f"<h1>Detail for {person.name}</h1><p>Age: {person.age}, City: {person.city}</p><p><a href='/people/'>Back to list</a></p>")
except Person.DoesNotExist:
return HttpResponse("Person not found", status=404)
# 4. Define URLs
urlpatterns = [
path('people/', PeopleView.as_view(), name='people_list'),
path('people/<int:pk>/', person_detail_view, name='person_detail'),
]
# 5. Create a temporary template file (people_list.html)
_template_content = """
{% load render_table from django_tables2 %}
<!DOCTYPE html>
<html>
<head>
<title>People List</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>People</h1>
{% render_table table %}
</div>
</body>
</html>
"""
# Save the template content to a file for the quickstart to run
with open('people_list.html', 'w') as f:
f.write(_template_content)
# Verify the table can be initialized and rendered into context
from django.test import RequestFactory
request_factory = RequestFactory()
request = request_factory.get('/people/')
# Call the view directly to get the response and context data
response = PeopleView.as_view()(request)
# Render the response to populate context_data for SingleTableView
response.render()
context = response.context_data
assert 'table' in context
assert isinstance(context['table'], PersonTable)
print("django-tables2 quickstart setup successful! Table initialized and rendered context contains table object.")
# Clean up the temporary template file
os.remove('people_list.html')