django+admin常用功能
一、编辑页面增加自定义按钮:
利用原来的input框下面的help_text,可以直接添加html类内容,制作各种按钮。
def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) # ✅ 公司名称:按钮放在 help_text 里 form.base_fields['gongyingshang'].help_text = ( '<div style="margin-top:5px;">' '<div id="btn_fill_customer" ' 'class="el-button el-button--primary el-button--small" ' 'style="cursor:pointer; display:inline-block;">' '<i class="el-icon-check"></i> 填充选中供应商和ID号' '</div>' '</div>' ) # ✅ 客户ID:只加说明,不加按钮 form.base_fields['chanpinmingcheng'].help_text = ( '系统自动回填,无需手动填写' ) return form 效果图如下:二、编辑页调用自定义js代码:
# 如果需要自定义媒体文件 class Media: js = ( 'admin/js/jquery.init.js', # Admin自带的jQuery初始化 'admin/js/admin.list.caigou.js', #自定义js1 'admin/js/custom-autocomplete.js', #自定义js2 )
在admin.py的指定模型里添加后,编辑页面就能调用到指定位置的自定义js文件了。
三、常用的admin.py中字段意义详解
# 定义Admin类 Q: @admin.register(Fapiao_admin) A: 将Fapiao_admin这个类注册到默认的django的admin.py中,必须在头部引用
from .models import Fapiao_admin Q:class FapiaoAdmin(admin.ModelAdmin): #设置一个FapiaoAdmin菜单独立管理 # 设置actions actions = [direct_total_nopay_action_fapiao] #设置一个批量管理功能 actions如下这义,必须和模型同级别,没有缩进 。
# app1/admin.py from django.contrib import admin from django.urls import reverse from django.utils.safestring import mark_safe from django.db.models import Sum from decimal import Decimal from datetime import datetime from .models import Order_admin,ProductImage # ================================== # 1 ️⃣ Action:批量切换合同状态 # ================================== def batch_update_hetong_status(modeladmin, request, queryset): """ 将选中的“执行中”合同批量改为“完毕” """ updated = queryset.filter(hetongzhuangtai='执行中').update( hetongzhuangtai='完毕' ) modeladmin.message_user( request, f"成功切换 {updated} 条数据的合同状态为【完毕】", level='success' ) batch_update_hetong_status.short_description = "批量切换合同状态为【完毕】" # ================================== # 2 ️⃣ Action:统计未收金额 # ================================== def direct_total_nopay_action(modeladmin, request, queryset): """ 统计选中记录的未收金额 """ if not queryset.exists(): modeladmin.message_user( request, "请先选择要统计的记录", level='info' ) return total = queryset.aggregate( sum_amount=Sum('weishoujine') )['sum_amount'] or Decimal('0') count = queryset.count() html = f""" <div style=" background:#2f3640; color:white; padding:15px; border-radius:8px; margin:10px 0; "> <h3 style="margin:0 0 10px;">🧮 金额统计结果</h3> <p>记录数:<b>{count}</b></p> <p>未收金额:<b>¥{total:.4f}</b></p> <small>统计时间:{datetime.now()}</small> </div> """ modeladmin.message_user( request, mark_safe(html), level='success' ) direct_total_nopay_action.short_description = "🧮 统计未收金额总和"
这样设置就可以了。
# 新窗口打开编辑 START
def edit_link(self, obj):
if obj.pk:
return format_html('<a href="/admin/app1/fapiao_admin/{}/change/" target="_blank">编辑</a>', obj.id)
return "-"
edit_link.short_description = '操作'
# 新窗口打开编辑 END
# 双下划线语法的模糊查询,包含某个公司名查询,设置可以搜索的列
search_fields = [
'cw_guanlianhetong_cg',
'cw_guanlianhetong_xs',
'cw_beizhu',
]
# 列表显示字段,在列表显示的字段,每一行是一列,列的位置和这里行对应
list_display = [
'id',
'edit_link',
'cw_fapiaobianhao',
'cw_fapiaoleibie',
'cw_fapiaoleixing',
'cw_guanlianhetong_cg',
'cw_guanlianhetong_xs',
'cw_kaipiaojine',
'cw_yingshoushuie',
'cw_shishoushuie',
'cw_jinxiangshuie',
'cw_dikouchae',
'colored_cw_shifoukaijv',
'cw_kehukaipiaoxinxi',
'get_xiaoguotu_JS', # 改为新的方法名
'get_fapiaofujian_JS', # 改为新的方法名
'cw_beizhu',
'cw_chuangjianshijian',
'cw_gengxinshijian'
]
# 如果需要,可以添加只读字段,添加了只读字段的,编辑时的值是不可以修改的
readonly_fields = ['get_xiaoguotu_JS', 'get_fapiaofujian_JS']
# 在Django admin中,需要单独定义fieldsets或使用filter_horizontal/filter_vertical处理多对多字段
# 如果cw_guanlianhetong和cw_guanliancaigouhetong是多对多字段,可以这样处理:
filter_horizontal = ['cw_guanlianhetong', 'cw_guanliancaigouhetong'] # 或者使用filter_vertical
# 设置过滤器,通过过滤器搜索对应的列字段
list_filter = [
'cw_fapiaoleibie',
'cw_fapiaoleixing',
'cw_fapiaobianhao',
'cw_shifoukaijv',
'cw_gengxinshijian'
]
# 设置可以点击进入编辑的字段
四、内联管理
from .models import ProductImage #导入模型中定义的一个类 # 1. 内联类 class ProductImageInline(admin.TabularInline): #将这个模型定义为一个内联,也就是在指定的编辑页的最底部显示,没有独立的菜单项管理 model = ProductImage #指定model为导入的这个Model extra = 1 #作为内联时默认显示的条数,为0则不显示,需要点按钮才能添加一个 # 可选:控制内联显示的字段,内联的列显示哪些字段 fields = ('p_name','p_sku','image','p_color','p_period', 'order') readonly_fields = ('image_preview',) #设置为只读就没办法编辑了 autocomplete_fields = ['p_sku'] # 将p_sku变成带搜索的下拉框,前提是p_sku必须是
这种类型: p_sku = models.ForeignKey( ProductSpec, on_delete=models.CASCADE, verbose_name='所属分类ID', related_name='product_images' # 更新related_name )
# 从 autocomplete_fields 改为 raw_id_fields,字段必须为ForeignKey raw_id_fields = ['p_sku'] # ✅ 弹窗选择器,点击一个放大镜弹窗搜索,数据量大于1万条,切换用这个 2026-5-7 13:47:21 #直接在html中显示灯箱弹窗显示图片 def image_preview(self, obj): """在HTML中直接嵌入JS,最可靠""" if obj.image: return format_html( ''' <div style="position:relative;"> <img src="{0}" onclick=" var overlay = document.createElement('div'); overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.92);z-index:9999;display:flex;align-items:center;justify-content:center;'; var img = document.createElement('img'); img.src = '{0}'; img.style.maxWidth = '90vw'; img.style.maxHeight = '90vh'; img.style.borderRadius = '8px'; img.style.boxShadow = '0 10px 50px rgba(0,0,0,0.5)'; var closeBtn = document.createElement('div'); closeBtn.innerHTML = '×'; closeBtn.style.cssText = 'position:absolute;top:20px;right:20px;color:white;font-size:40px;cursor:pointer;z-index:10000;width:50px;height:50px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.5);'; overlay.onclick = function(e) {{ if(e.target === overlay || e.target === closeBtn) {{ document.body.removeChild(overlay); }} }}; overlay.appendChild(closeBtn); overlay.appendChild(img); document.body.appendChild(overlay); " style="max-height:80px; max-width:80px; border:1px solid #ddd; border-radius:4px; padding:2px; cursor:zoom-in;" title="点击放大" /> </div> ''', obj.image.url ) return "—" image_preview.short_description = '图片预览' 如果想在哪个admin.py中的模型使用这个内联,内联定义和模型同级别的缩进,在模型里缩进一个字段,设置:
# 内联 inlines = [ProductImageInline]
这样就会在当前编辑页面里,显示ProductImageInline 这个内联了。
# 🔴 关键:添加这行,引入自定义JS
class Media:
js = (
#'admin/js/debug.js', # 调试文件
'admin/js/admin.list.chanpinguanli.js',
'admin/js/jquery.init.js', # Admin自带的jQuery初始化
'admin/js/admin.paste_upload.js', # 粘贴上传功能
)
# 🔴 关键:添加这行,引入自定义CSS
css = { 'all': ('admin/css/paste_upload.css',) } 五、让后台默认显示日志
# admin.py from django.contrib.admin.models import LogEntry # 注册 LogEntry 到 Admin 后台,让后台显示日志版块 2026-4-30 00:46:06 @admin.register(LogEntry) class LogEntryAdmin(admin.ModelAdmin): """显示操作日志""" list_display = ['action_time', 'user', 'content_type', 'object_repr', 'action_flag'] list_filter = ['action_time', 'user', 'content_type'] readonly_fields = ['action_time', 'user', 'content_type', 'object_id', 'action_flag', 'change_message'] search_fields = ['object_repr', 'change_message'] # 禁止在日志页面进行增删改操作(日志是只读的) def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False 六、常用(一个完整的列表管理标签)
# 标签管理 START # 先注册标签模型,因为产品模型要用到 @admin.register(Biaoqian_admin) # 使用装饰器注册 class BiaoqianAdmin(ImportExportActionModelAdmin): # 继承 ModelAdmin """标签管理后台""" # 排序配置 ordering = ['id'] # 同 Xadmin 的 ordering,按id降序排列,-id就是按id升序排列,这种方式可以结合系统的sort功能实现拖动的排序。 list_per_page = 20 # 同 Xadmin 的 list_per_page,每页显示几条数据 # 列表页显示字段 list_display = ('biaoqianmingcheng', 'paixv', 'chuangjianshijian') # 搜索字段(需要取消注释并修改),哪些可以搜索 search_fields = ('biaoqianmingcheng',) # 列表页可点击的字段(需要取消注释并修改),哪些列可以点击进入编辑页面 list_display_links = ('biaoqianmingcheng',) # 只读字段(需要在表单页使用),表单页只显示不能修改 readonly_fields = ('some_field',) # 可选:添加过滤器,筛选器 list_filter = ('paixv',) # 可选:添加日期分层导航,显示一个2026年5月,5月20日、5月22日这种时间归档的筛选 date_hierarchy = 'chuangjianshijian' # 可选:字段别名显示 def get_list_display(self, request): """自定义显示字段,可以添加计算字段""" base_list = list(super().get_list_display(request)) # 可以在这里添加自定义计算字段 return base_list # 标签管理 END
实际应用示例
示例1:根据用户权限显示不同字段
为什么要用这个方法?
优点:
-
动态控制:根据条件动态显示/隐藏字段
-
权限控制:不同用户看到不同字段
-
灵活性:可以在运行时修改字段
-
计算字段:可以添加非数据库字段
缺点:
-
稍微复杂:比静态
list_display复杂 -
性能:每次加载列表都要执行
何时使用?
-
✅ 需要权限控制时
-
✅ 需要动态字段时
-
✅ 需要添加计算字段时
-
❌ 字段固定不变时,直接用
list_display更简单
七、字段分组
# 字段分组(编辑页)
fieldsets = (
('基本信息', {
'fields': ('chanpinmingcheng', 'chanpinguige', 'chanpintupian', )
}),
('关联信息', {
'fields': ('related_gongyingshang','related_gongyingshang_id', 'chanpinbiaoqian'),
'description': '使用左右穿梭框选择'
}),
('库存成本', {
'fields': ('chanpinchengben', 'chanpinkucun','kucunchengben','pandianshijian', 'weizhi')
}),
('其他信息', {
'fields': ('erweima', 'beizhu'),
'classes': ('collapse',) # 可折叠
}),
)
设置了fieldsets之后,字段就按这个分类显示了,最后一个可以设置为折叠模式,默认不显示。注意在admin+django原生环境中,很多必须设置在这里才会显示。比如左右穿插等。
八、设置新窗口打开编辑
# 新窗口打开编辑 def edit_link(self, obj): return format_html('<a href="/admin/app1/customer_admin/{}/change/" target="_blank">编辑</a>', obj.id) edit_link.short_description = '操作' edit_link.allow_tags = True 可以直接在list_display中显示这个链接,打开后新窗口编辑 。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

