Django Admin Detail View
Django Admin's missing DetailView.
Allows easy creation of a DetailView via DSL for an object in Django Admin.
Why this exists
Django Admin's is missing detail views (by design). It's strengths lie in administering specific objects via form modification.
But, a common need is to allow internal staff/admins to view specific objects and and their related objects. Historically the recommendation was to build a separate website/frontend for this.
Theory
With models Company, ContactInfo, SalesLeads, Orders, Internal staff want to quickly understand the status of a particular Company so a simple View displaying these 4 objects is very beneficial.
Then I can drill down into a Order and see all related Products, OrderStatusUpdates, SalesComments.
Via DSL, it is fast to stand up DetailViews for many objects.
Beliefs
Opinionated, information dense, grid layout. Function over form.
Core API
- Add View button to
changelistfor Object. details_table_for()builds object's details table.table_for()builds a list table for related objects.ctx["layout"]holds the grid structure.
Pre-reqs
- Bootstrap as Webpack
- webpack_loader
Install
- Direct add github to
pyproject.toml,git@github.com:jenfi-eng/djadmin-detail-view.git. - Add to
INSTALLED_APPS - Create a
DetailViewand add mixinAdminDetailMixin - To the object's admin add
AdminChangeListViewDetailand functionget_default_detail_view - Return the newly created DetailView in
get_default_detail_view.
See example_project/companies/admin.py for reference.
Code Example
from django.contrib import admin
from django.views.generic import DetailView
from djadmin_detail_view.mixins import AdminChangeListViewDetail, AdminDetailMixin
from djadmin_detail_view.template_helpers import col, detail, details_table_for, table_for
from my_app.companies.models import Company
@admin.register(Company)
class CompanyAdmin(AdminChangeListViewDetail, admin.ModelAdmin):
def get_default_detail_view(self):
return CompanyDetailView
class CompanyDetailView(AdminDetailMixin, DetailView):
model = Company
def get_context_data(self, request, *args, **kwargs):
ctx = super().get_context_data(request, *args, **kwargs)
company_details = details_table_for(
panel_name="Company Details",
obj=self.object,
details=[
detail("id"),
detail("legal_name"),
detail("tax_id"),
detail("total_completed_order_amount", value=lambda x: x.total_order_value()),
]
)
# Regular table
orders_list = table_for(
panel_name="Orders",
obj_set=self.object.order_set.all(),
cols=[
col("id"),
col("legal_name"),
col("total_value"),
col("created"),
]
)
# Lazy-loaded table (loads via AJAX after page render)
large_orders_list = table_for(
panel_name="Large Orders",
obj_set=self.object.order_set.filter(total_value__gte=10000),
cols=[col("id"), col("total_value")],
lazy_load_key="large_orders",
)
ctx["layout"] = [
{
"row": [
{"col": company_details},
{"col": orders_list},
],
},
{
"row": [
{"col": large_orders_list},
],
},
]
return ctx
Template Helper API Reference
Layout Helpers
details_table_for()- Creates a detail table for displaying attributes of a single objectdetail()- Defines a single detail/column in a details table (alias:col())table_for()- Creates a list table for displaying multiple related objects
Lazy Loading
Both table_for() and details_table_for() support lazy loading to improve initial page load times. When enabled, panels display a spinner and load content via AJAX after the page renders.
# In get_context_data():
orders_list = table_for(
panel_name="Orders",
obj_set=self.object.order_set.all(),
cols=[col("id"), col("status"), col("total")],
lazy_load_key="orders", # enables lazy loading with this unique key
lazy_placeholder="Loading orders...", # optional
)
Parameters:
lazy_load_key- Unique identifier that enables lazy loading for this panel. Must be unique within the page - duplicate keys will raise an error.lazy_placeholder- Custom loading message (default: "Loading...")
How it works:
- On initial page load, the panel renders with a Bootstrap spinner placeholder
- A Stimulus controller fetches content from the lazy endpoint
- The system automatically re-runs
get_context_data()with a flag that tells this specific panel to render its actual content - The placeholder is replaced with the loaded content
Error handling:
- Non-2xx responses display an error message with status code
- Network errors retry automatically (up to 3 times with exponential backoff)
- A "Retry" button allows manual retry after failures
Menu Helpers
top_menu_btn()- Creates a button for the top menu bardropdown_item()- Creates an item for the Actions dropdown menudropdown_divider()- Creates a horizontal divider line in the dropdown menudropdown_header()- Creates a non-interactive header/label in the dropdown menu
Auto-formatting
The detail() and col() helpers automatically format common data types:
- DateTime: Formatted using
TEMPLATE_TIME_FORMATsetting - Date: Formatted using Django's
SHORT_DATE_FORMAT - Money (moneyed library): Formatted with currency symbol if available
- ImageFieldFile: Rendered as
<img>tag with max dimensions 100x100px - None: Displayed as "-"
- Model instances: Auto-linked to admin detail view if col_name is in
AUTOLINK_COL_NAMES(default:["id", "legal_name"])
Current Open Source Status
It is currently built for Jenfi and its internal needs. Thus, it has specific requirements such as django-hosts and Money that may need to be abstracted away.
PRs are welcome for review to make it more generally accessible.
VSCode
Testing
Add config to allow specs to be run inside VSCode.
// .vscode/settings.json
{
"python.testing.pytestArgs": [
""
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
}
Web Launch Config
{
"name": "Django Web",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/server.py",
"args": [],
"django": true,
"justMyCode": false
},
TODO
- Allow non-webpack based installs.
Jenfi Specific Needs
- Handles
Money(from py-moneyed) django-hosts
Credit
This project takes heavy, heavy inspiration from Rail's ActiveAdmin and its DSL.
Metadata
Release files for djadmin-detail-view 0.4.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| djadmin_detail_view-0.4.4.tar.gz | 21.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| djadmin_detail_view-0.4.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.0 kB
Release files / djadmin_detail_view-0.4.4.tar.gz
| Download URL | djadmin_detail_view-0.4.4.tar.gz |
|---|---|
| Size | 21.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b625c865cc0546e11d2712925e1d30151c918f693b1fdedf5fdb0a1861e4454
|
|
BLAKE2b-256 checksum How to use checksums |
f903606a449277a6eff58bbde6f4835e48ef408dcdcb41c5e87093578a9fae5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.2.1 CPython/3.14.2 Darwin/25.1.0
|
Release files / djadmin_detail_view-0.4.4-py3-none-any.whl
| Download URL | djadmin_detail_view-0.4.4-py3-none-any.whl |
|---|---|
| Size | 24.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16e8a721e007b6cc1504acaff8937b2767b56cd82ddfafd6e7f5498e69464cb0
|
|
BLAKE2b-256 checksum How to use checksums |
c8e8b654e2308e283dd6e3bb9cab1b1ba462c275bfcc9cde883802734608ff5b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.2.1 CPython/3.14.2 Darwin/25.1.0
|