自定义 Django 管理界面中的多对多内联模型

1. 问题背景

在 Django 管理界面中,用户可以使用内联模型来管理一对多的关系。但是,当一对多关系是多对多时,Django 提供的默认内联模型可能并不适合。例如,如果存在一个产品模型和一个发票模型,并且产品和发票之间是多对多的关系,那么在发票的管理界面中,Django 会显示一个表格,其中包含所有产品及其对应的复选框。这种形式的内联模型对于管理少量产品还可以接受,但是如果产品数量很多,那么这种内联模型就会非常不美观和难以使用。

2. 解决方案

为了解决这个问题,我们可以自定义多对多内联模型的显示方式。具体步骤如下:

  1. 创建一个新的内联模型类。这个类继承自 admin.TabularInline 或 admin.StackedInline。

  2. 在新的内联模型类中,重写 get_formset() 方法。这个方法负责返回一个表单集,表单集中的每个表单对应于内联模型中的一个对象。

  3. 在 get_formset() 方法中,使用 formset_factory() 函数创建表单集。在 formset_factory() 函数中,指定 model 参数为内联模型的模型类,并指定 fields 参数为内联模型中需要显示的字段。

  4. 在新的内联模型类中,重写 has_add_permission() 和 has_change_permission() 方法。这两个方法分别负责判断用户是否有添加和修改内联模型对象

  5. 将新的内联模型类添加到 ModelAdmin 类中。在 ModelAdmin 类的 inlines 属性中,添加新的内联模型类。

下面是一个示例代码,演示了如何自定义多对多内联模型的显示方式:

python 复制代码
from django.contrib import admin
from django.contrib.admin.utils import NestedObjects

class Product(models.Model):
    name = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)

class Invoice(models.Model):
    company = models.ForeignKey(Company)
    customer = models.ForeignKey(Customer)
    products = models.ManyToManyField(Product)

class InvoiceAdmin(admin.ModelAdmin):

    # 使用 formset_factory() 函数创建表单集
    def get_formset(self, request, obj=None, **kwargs):
        formset_class = super().get_formset(request, obj, **kwargs)
        formset_class = formset_factory(InvoiceProductFormset, extra=0,
                                        fields=('product',))
        return formset_class

    # 重写 has_add_permission() 和 has_change_permission() 方法
    def has_add_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None):
        return False

class InvoiceProductFormset(admin.BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        NestedObjects(self)

    # 重写 get_queryset() 方法
    def get_queryset(self):
        qs = super().get_queryset()
        # 过滤掉已经被删除的对象
        return qs.filter(is_deleted=False)

# 将自定义的内联模型类添加到 ModelAdmin 类中
admin.site.register(Invoice, InvoiceAdmin)

在上面的代码中,我们首先创建了一个新的内联模型类 InvoiceProductFormset。这个类继承自 admin.BaseInlineFormSet。然后,我们在 InvoiceProductFormset 类中重写了 get_formset() 方法、has_add_permission() 方法和 has_change_permission() 方法。最后,我们将 InvoiceProductFormset 类添加到 InvoiceAdmin 类中。

相关推荐
WikiLeake1 分钟前
一个健壮且灵活的大语言模型(LLM)API 配置加载器
数据库·人工智能
我的xiaodoujiao10 分钟前
Django 权限系统项目实战详细图文教程 2--环境搭建
后端·python·django
瑞克-桑切斯2 小时前
企业生产环境:https部署+nginx高可用(业务不中断)
linux·服务器·数据库
zyseo810 小时前
谷歌SEO 准首页词挖掘脚本:找出排在第 8-20 名的隐藏流量
大数据·数据库·人工智能
马良神笔10 小时前
2026 年Rag最近技术前沿总结
后端·python·django
xiaogai_gai12 小时前
仅查询策略实战:从金蝶云·星空旗舰版定时拉取收料通知单
大数据·数据库·python
数据工匠老o12 小时前
异构数据库DDL同步:260条链路的结构变更自动适配方案
数据库·架构
这个DBA有点耶13 小时前
银行业市占率最高的国产数据库是谁?先搞清楚“市占率”的四种口径
数据库·程序员·架构
用户62799471826214 小时前
南大通用GBase 8a之基于审计日志的冷温热数据分析
数据库
数据库小学妹14 小时前
数据库运维五级成熟度:监控、备份、高可用怎么串起来
运维·数据库·监控