Registry / web-framework / django-tables2

django-tables2

JSON →
library3.0.0pypypi✓ verified 23d ago

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.

pip install django-tables2
INSTALL
IMPORT
SIG · DJANGO-TABLES2
D
django-tables2
web-frameworkpythonv3.0.0
Install
3.5s avg
Import
Disk
66MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v3.0.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.000s · 67.2MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 3.5s · import 0.000s · 68MB
66MB installed
● package 66MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Table
from django_tables2 import Table
from django_tables2 import Table

This quickstart demonstrates how to integrate `django-tables2` into a minimal Django project. It defines a simple model, creates a `Table` subclass with a `LinkColumn`, uses `SingleTableView` to fetch and display data, and renders it using the `render_table` template tag with a Bootstrap 4 theme. The example uses an in-memory SQLite database and creates temporary files for a fully self-contained, runnable setup.

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')
Debug
Known issues
breakingWhen upgrading from django-tables2 version 1.x to 2.x, direct access to the request object via `table.request` was removed.
fix
Access the request object by passing it into the template context (e.g., `Context(request=request)`) and then accessing it via `table.context['request']` within table methods or custom columns. Alternatively, override `Table.__init__` to explicitly pass the request.
affects: 1.x to 2.x
breakingThe 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.
fix
Review the new `template_name` options and styling documentation for 2.x. Re-evaluate and rewrite custom templates based on the new structure. Available templates like `django_tables2/bootstrap4.html` provide good starting points.
affects: 1.x to 2.x
deprecatedThe `url` argument for `LinkColumn` is deprecated and will be removed in a future major release (e.g., 3.0).
fix
Use the `viewname` argument instead, which takes the name of a Django URL pattern. For example, `LinkColumn('my_app:my_detail_view', args=[A('pk')])` is the preferred approach.
affects: 2.0+
gotchadjango-tables2 provides excellent display, sorting, and pagination features but does not include built-in filtering or search capabilities.
fix
To add filtering or searching, integrate with `django-filter` (a commonly recommended approach) or implement custom filtering logic in your Django views before passing the filtered queryset to the table.
affects: All versions
Upgrade
Version history
3.0.0latest on PyPI · released Apr 13, 2026
Audit
Dependencies
DjangorequiredPeer dependency; django-tables2 requires a compatible Django version (e.g., >=3.2 for 2.9.0).
Agent activity
14 hits · last 30 days
node
12
OpenAI (training)
1
Resources
django-tables2 — pip install django-tables2 · libregistry