• bitcoinBitcoin(BTC)$77,896.00-1.72%
  • ethereumEthereum(ETH)$2,463.70-1.54%
  • tetherTether(USDT)$1.00-0.01%
  • binancecoinBNB(BNB)$717.13-4.51%
  • rippleXRP(XRP)$1.38-3.54%
  • usd-coinUSDC(USDC)$1.000.00%
  • solanaSolana(SOL)$101.16-2.91%
  • tronTRON(TRX)$0.3403870.32%
  • Figure HelocFigure Heloc(FIGR_HELOC)$1.030.00%
  • zcashZcash(ZEC)$1,229.14-2.91%
  • HyperliquidHyperliquid(HYPE)$82.98-3.67%
  • dogecoinDogecoin(DOGE)$0.085206-6.23%
  • RainRain(RAIN)$0.0161410.04%
  • USDSUSDS(USDS)$1.00-0.01%
  • moneroMonero(XMR)$508.703.03%
  • whitebitWhiteBIT Coin(WBT)$80.52-1.77%
  • chainlinkChainlink(LINK)$11.85-1.85%
  • leo-tokenLEO Token(LEO)$9.230.49%
  • cardanoCardano(ADA)$0.212842-3.24%
  • stellarStellar(XLM)$0.179479-4.97%
  • bitcoin-cashBitcoin Cash(BCH)$245.39-5.04%
  • daiDai(DAI)$1.00-0.01%
  • Ethena USDeEthena USDe(USDE)$1.00-0.01%
  • USD1USD1(USD1)$1.00-0.01%
  • litecoinLitecoin(LTC)$52.22-3.79%
  • CantonCanton(CC)$0.101485-4.26%
  • the-open-networkGram (prev. Toncoin)(GRAM)$1.37-2.23%
  • uniswapUniswap(UNI)$6.01-10.20%
  • hedera-hashgraphHedera(HBAR)$0.076248-3.15%
  • avalanche-2Avalanche(AVAX)$7.74-2.95%
  • Global DollarGlobal Dollar(USDG)$1.000.01%
  • nearNEAR Protocol(NEAR)$2.43-5.59%
  • suiSui(SUI)$0.76-6.20%
  • shiba-inuShiba Inu(SHIB)$0.000005-5.51%
  • paypal-usdPayPal USD(PYUSD)$1.000.00%
  • BlackRock USD Institutional Digital Liquidity FundBlackRock USD Institutional Digital Liquidity Fund(BUIDL)$1.000.00%
  • crypto-com-chainCronos(CRO)$0.056647-6.08%
  • MemeCoreMemeCore(M)$1.201.52%
  • tether-goldTether Gold(XAUT)$4,379.42-0.65%
  • Circle USYCCircle USYC(USYC)$1.140.01%
  • BittensorBittensor(TAO)$252.41-5.56%
  • Ripple USDRipple USD(RLUSD)$1.00-0.02%
  • okbOKB(OKB)$112.06-2.12%
  • Ondo US Dollar YieldOndo US Dollar Yield(USDY)$1.14-0.10%
  • mantleMantle(MNT)$0.59-7.44%
  • AsterAster(ASTER)$0.71-5.20%
  • aaveAave(AAVE)$122.97-5.12%
  • pax-goldPAX Gold(PAXG)$4,381.25-0.70%
  • polkadotPolkadot(DOT)$1.10-7.01%
  • World Liberty FinancialWorld Liberty Financial(WLFI)$0.0563020.88%
TradePoint.io
  • Main
  • AI & Technology
  • Stock Charts
  • Market & News
  • Business
  • Finance Tips
  • Trade Tube
  • Blog
  • Shop
No Result
View All Result
TradePoint.io
No Result
View All Result

How to Build a Django-Unfold Admin Dashboard with Custom Models, Filters, Actions, and KPIs

May 15, 2026
in AI & Technology
Reading Time: 4 mins read
A A
How to Build a Django-Unfold Admin Dashboard with Custom Models, Filters, Actions, and KPIs
ShareShareShareShareShare
(ROOT / "shop" / "admin.py").write_text('''
from django.contrib import admin, messages
from django.contrib.auth.admin import (UserAdmin as DjangoUserAdmin,
                                      GroupAdmin as DjangoGroupAdmin)
from django.contrib.auth.models import User, Group
from django.shortcuts import redirect
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.contrib.filters.admin import (
   ChoicesDropdownFilter, RangeNumericFilter, RangeDateFilter,
   MultipleChoicesDropdownFilter,
)
from unfold.decorators import display, action
from .models import Category, Customer, Product, Order, OrderItem
admin.site.unregister(User); admin.site.unregister(Group)
@admin.register(User)
class UserAdmin(DjangoUserAdmin, ModelAdmin):
   pass
@admin.register(Group)
class GroupAdmin(DjangoGroupAdmin, ModelAdmin):
   pass
@admin.register(Category)
class CategoryAdmin(ModelAdmin):
   list_display = ("name", "parent", "show_active", "created_at")
   list_filter  = (("is_active", ChoicesDropdownFilter),)
   search_fields = ("name", "slug")
   prepopulated_fields = {"slug": ("name",)}
   list_filter_submit = True
   compressed_fields = True
   @display(description=_("Active"), boolean=True)
   def show_active(self, obj): return obj.is_active
@admin.register(Customer)
class CustomerAdmin(ModelAdmin):
   list_display = ("name","email","show_tier","lifetime_value","joined")
   list_filter  = (
       ("tier",            MultipleChoicesDropdownFilter),
       ("lifetime_value",  RangeNumericFilter),
       ("joined",          RangeDateFilter),
   )
   search_fields = ("name","email")
   list_filter_submit = True
   warn_unsaved_form  = True
   list_per_page = 25
   @display(description=_("Tier"), label={
       "bronze":"warning","silver":"info","gold":"success","platinum":"primary"})
   def show_tier(self, obj):
       return obj.get_tier_display(), obj.tier
class OrderItemInline(TabularInline):
   model = OrderItem
   extra = 0
   fields = ("product", "quantity", "unit_price", "position")
   ordering_field = "position"
   tab = True
@admin.register(Order)
class OrderAdmin(ModelAdmin):
   list_display = ("number","customer_link","show_status","total","created_at")
   list_filter  = (
       ("status",     ChoicesDropdownFilter),
       ("total",      RangeNumericFilter),
       ("created_at", RangeDateFilter),
   )
   search_fields = ("number","customer__name","customer__email")
   readonly_fields = ("created_at",)
   autocomplete_fields = ("customer",)
   inlines = [OrderItemInline]
   list_filter_submit = True
   fieldsets = (
       (_("Order"), {"classes":["tab"], "fields":("number","customer","status","total")}),
       (_("Notes"), {"classes":["tab"], "fields":("notes","created_at")}),
   )
   actions_list        = ["mark_paid_bulk"]
   actions_row         = ["mark_paid_row"]
   actions_detail      = ["duplicate_order"]
   actions_submit_line = ["save_and_ship"]
   @display(description=_("Status"), label={
       "pending":"warning","paid":"info","shipped":"primary",
       "delivered":"success","cancelled":"danger"})
   def show_status(self, obj):
       return obj.get_status_display(), obj.status
   @display(description=_("Customer"))
   def customer_link(self, obj):
       return format_html(\'{}\',
                          obj.customer_id, obj.customer.name)
   @action(description=_("Mark pending → PAID (all)"), icon="payments")
   def mark_paid_bulk(self, request, queryset=None):
       n = Order.objects.filter(status="pending").update(status="paid")
       self.message_user(request, f"Marked {n} orders as paid.", level=messages.SUCCESS)
   @action(description=_("Mark paid"), icon="payments", url_path="mark-paid-row")
   def mark_paid_row(self, request, object_id):
       Order.objects.filter(pk=object_id).update(status="paid")
       self.message_user(request, "Order marked as paid.", level=messages.SUCCESS)
       return redirect(request.META.get("HTTP_REFERER","/admin/"))
   @action(description=_("Duplicate"), icon="content_copy", url_path="duplicate")
   def duplicate_order(self, request, object_id):
       o = Order.objects.get(pk=object_id)
       o.pk = None; o.number = o.number + "-COPY"; o.status = "pending"; o.save()
       self.message_user(request, "Order duplicated.", level=messages.SUCCESS)
       return redirect(f"/admin/shop/order/{o.pk}/change/")
   @action(description=_("Save & ship"))
   def save_and_ship(self, request, obj):
       obj.status = "shipped"; obj.save()
       self.message_user(request, f"Order {obj.number} shipped.", level=messages.SUCCESS)
@admin.register(Product)
class ProductAdmin(ModelAdmin):
   list_display = ("name","sku","category","show_status",
                   "price_display","stock_badge","featured")
   list_editable = ("featured",)
   list_filter   = (
       ("status",   ChoicesDropdownFilter),
       ("category", admin.RelatedFieldListFilter),
       ("price",    RangeNumericFilter),
       ("featured", ChoicesDropdownFilter),
   )
   search_fields = ("name","sku")
   autocomplete_fields = ("category",)
   list_filter_submit = True
   list_per_page = 20
   save_on_top = True
   fieldsets = (
       (_("Basics"),  {"classes":["tab"],
                       "fields":("name","sku","category","status","featured")}),
       (_("Pricing"), {"classes":["tab"],
                       "fields":("price","has_discount","discount_percent","stock")}),
       (_("Content"), {"classes":["tab"], "fields":("description",)}),
   )
   conditional_fields = {"discount_percent": "has_discount == true"}
   @display(description=_("Status"), label={
       "draft":"info","active":"success","archived":"warning"})
   def show_status(self, obj):
       return obj.get_status_display(), obj.status
   @display(description=_("Price"))
   def price_display(self, obj):
       if obj.has_discount and obj.discount_percent:
           return format_html(
               \'${} \'
               \'${}\', obj.price, obj.final_price)
       return f"${obj.price}"
   @display(description=_("Stock"), ordering="stock",
            label={"out":"danger","low":"warning","ok":"success"})
   def stock_badge(self, obj):
       if obj.stock == 0:                  return "Out of stock", "out"
       if obj.stock < 10:                  return f"Low ({obj.stock})", "low"
       return f"{obj.stock} in stock", "ok"
''')
(ROOT / "templates" / "admin" / "index.html").write_text('''{% extends "admin/index.html" %}
{% load i18n %}
{% block content %}
{% for k in kpis %}

{{ k.title }}

{{ k.value }}

YOU MAY ALSO LIKE

Fujitsu Signs New Palantir AIP Agreement, Becomes Global FDE Partner – Unite.AI

AppleCare One Now Has A $50 Tier Per Month For Families

{{ k.footer }}

{% endfor %}

{% trans "Top categories" %}

    {% for c in top_cats %}
  • {{ c.name }}{{ c.n }}
  • {% endfor %}

{% trans "Orders by status" %}

    {% for s in by_status %}
  • {{ s.status }}{{ s.c }}
  • {% endfor %}
{{ block.super }} {% endblock %} ''')

Credit: Source link

ShareTweetSendSharePin

Related Posts

Fujitsu Signs New Palantir AIP Agreement, Becomes Global FDE Partner – Unite.AI
AI & Technology

Fujitsu Signs New Palantir AIP Agreement, Becomes Global FDE Partner – Unite.AI

September 10, 2026
AppleCare One Now Has A  Tier Per Month For Families
AI & Technology

AppleCare One Now Has A $50 Tier Per Month For Families

September 10, 2026
DeepSeek AI Released DeepSeek-V4.1-Flash with 1M Context, FP4 KV Cache, and Cross-Layer Attention Reuse
AI & Technology

DeepSeek AI Released DeepSeek-V4.1-Flash with 1M Context, FP4 KV Cache, and Cross-Layer Attention Reuse

September 10, 2026
2028 Volvo XC40 First Look: Hello new tech, goodbye EV
AI & Technology

2028 Volvo XC40 First Look: Hello new tech, goodbye EV

September 10, 2026
Next Post
White House Correspondents’ Dinner wrapped early, but Trump hoped to ‘let the show go on’

White House Correspondents' Dinner wrapped early, but Trump hoped to 'let the show go on'

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Search

No Result
View All Result
Nvidia Makes MediaTek Partnership Even Bigger, Huang Says

Nvidia Makes MediaTek Partnership Even Bigger, Huang Says

September 4, 2026
Federal program cuts spark concern over FDA and CDC response to cyclospora

Federal program cuts spark concern over FDA and CDC response to cyclospora

September 5, 2026
We Have 5,000 in Consumer Debt But Not Married

We Have $225,000 in Consumer Debt But Not Married

September 9, 2026

About

Learn more

Our Services

Legal

Privacy Policy

Terms of Use

Bloggers

Learn more

Article Links

Contact

Advertise

Ask us anything

©2020- TradePoint.io - All rights reserved!

Tradepoint.io, being just a publishing and technology platform, is not a registered broker-dealer or investment adviser. So we do not provide investment advice. Rather, brokerage services are provided to clients of Tradepoint.io by independent SEC-registered broker-dealers and members of FINRA/SIPC. Every form of investing carries some risk and past performance is not a guarantee of future results. “Tradepoint.io“, “Instant Investing” and “My Trading Tools” are registered trademarks of Apperbuild, LLC.

This website is operated by Apperbuild, LLC. We have no link to any brokerage firm and we do not provide investment advice. Every information and resource we provide is solely for the education of our readers. © 2020 Apperbuild, LLC. All rights reserved.

No Result
View All Result
  • Main
  • AI & Technology
  • Stock Charts
  • Market & News
  • Business
  • Finance Tips
  • Trade Tube
  • Blog
  • Shop

© 2023 - TradePoint.io - All Rights Reserved!