• bitcoinBitcoin(BTC)$80,075.000.39%
  • ethereumEthereum(ETH)$2,246.10-0.58%
  • tetherTether(USDT)$1.000.02%
  • binancecoinBNB(BNB)$681.590.85%
  • rippleXRP(XRP)$1.460.08%
  • usd-coinUSDC(USDC)$1.000.00%
  • solanaSolana(SOL)$90.31-1.12%
  • tronTRON(TRX)$0.351670-0.87%
  • Figure HelocFigure Heloc(FIGR_HELOC)$1.03-0.07%
  • dogecoinDogecoin(DOGE)$0.113785-1.81%
  • whitebitWhiteBIT Coin(WBT)$58.740.03%
  • USDSUSDS(USDS)$1.000.00%
  • HyperliquidHyperliquid(HYPE)$43.217.03%
  • cardanoCardano(ADA)$0.264511-1.09%
  • leo-tokenLEO Token(LEO)$10.200.52%
  • zcashZcash(ZEC)$529.170.61%
  • bitcoin-cashBitcoin Cash(BCH)$430.09-0.88%
  • chainlinkChainlink(LINK)$10.22-1.15%
  • moneroMonero(XMR)$384.36-3.49%
  • CantonCanton(CC)$0.160132-4.44%
  • the-open-networkToncoin(TON)$2.05-3.18%
  • stellarStellar(XLM)$0.158347-1.69%
  • suiSui(SUI)$1.12-7.33%
  • USD1USD1(USD1)$1.00-0.01%
  • litecoinLitecoin(LTC)$57.640.38%
  • daiDai(DAI)$1.000.00%
  • Ethena USDeEthena USDe(USDE)$1.000.01%
  • avalanche-2Avalanche(AVAX)$9.70-0.90%
  • MemeCoreMemeCore(M)$3.21-4.37%
  • hedera-hashgraphHedera(HBAR)$0.092880-1.24%
  • shiba-inuShiba Inu(SHIB)$0.000006-1.33%
  • RainRain(RAIN)$0.007380-1.77%
  • paypal-usdPayPal USD(PYUSD)$1.00-0.01%
  • Global DollarGlobal Dollar(USDG)$1.000.02%
  • crypto-com-chainCronos(CRO)$0.074327-0.60%
  • Circle USYCCircle USYC(USYC)$1.120.00%
  • BittensorBittensor(TAO)$297.52-1.19%
  • tether-goldTether Gold(XAUT)$4,546.70-3.14%
  • BlackRock USD Institutional Digital Liquidity FundBlackRock USD Institutional Digital Liquidity Fund(BUIDL)$1.000.00%
  • uniswapUniswap(UNI)$3.650.62%
  • polkadotPolkadot(DOT)$1.33-0.84%
  • mantleMantle(MNT)$0.67-1.12%
  • pax-goldPAX Gold(PAXG)$4,546.92-3.07%
  • World Liberty FinancialWorld Liberty Financial(WLFI)$0.067178-1.06%
  • nearNEAR Protocol(NEAR)$1.54-1.76%
  • Ondo US Dollar YieldOndo US Dollar Yield(USDY)$1.140.67%
  • OndoOndo(ONDO)$0.375578-2.97%
  • okbOKB(OKB)$85.660.96%
  • Falcon USDFalcon USD(USDF)$1.00-0.05%
  • HTX DAOHTX DAO(HTX)$0.000002-0.25%
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

The UK’s Tax Authority Is Turning To AI To Help Identify Fraud

Google Teases The Android-Based Googlebook

{{ 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

The UK’s Tax Authority Is Turning To AI To Help Identify Fraud
AI & Technology

The UK’s Tax Authority Is Turning To AI To Help Identify Fraud

May 15, 2026
Google Teases The Android-Based Googlebook
AI & Technology

Google Teases The Android-Based Googlebook

May 15, 2026
Best AI Agents for Software Development Ranked: A Benchmark-Driven Look at the Current Field
AI & Technology

Best AI Agents for Software Development Ranked: A Benchmark-Driven Look at the Current Field

May 15, 2026
Supertone Releases Supertonic v3: On-Device Text-to-Speech Model with 31-Language Support, Fewer Reading Failures, and Expression Tags
AI & Technology

Supertone Releases Supertonic v3: On-Device Text-to-Speech Model with 31-Language Support, Fewer Reading Failures, and Expression Tags

May 15, 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
Waymo Recalls Nearly 4,000 Robotaxis After A Car Drove Directly Into A Flooded Road

Waymo Recalls Nearly 4,000 Robotaxis After A Car Drove Directly Into A Flooded Road

May 12, 2026
Special Report: Trump speaks after shooting outside White House Correspondents’ Dinner

Special Report: Trump speaks after shooting outside White House Correspondents’ Dinner

May 15, 2026
She Racked Up 3,000 of Debt In One Year

She Racked Up $123,000 of Debt In One Year

May 13, 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!