django admin实现动态多选框表单的示例代码

下面是“Django admin实现动态多选框表单”的攻略。

背景介绍

Django是一个流行的Python Web框架,Django Admin是Django自带的管理后台。在Django Admin中,我们可以快速构建管理后台的界面和功能,并支持对数据库进行CURD操作。

动态多选框表单的需求

在Django Admin中,有时我们需要实现动态多选框表单,也就是当用户在一个fieldset中选择了某个选项时,当前fieldset之后的一些fieldset中的多选框选项需要动态更新。比如,我们需要根据选择的商品类别,动态更新商品品牌、商品型号等多个多选框的选项。

实现思路

我们可以通过JavaScript监听当前fieldset中某个选项的改变事件,然后异步请求服务端接口获取相关信息并更新后续多选框的选项。

在Django Admin中,我们可以使用Django自带的Inline Model Admin来实现这个功能,即在当前fieldset中嵌套另外一个Model Admin的Inline Model。然后在Inline Model中重载forms里的__init__方法,在页面加载的时候增加一个空白的表单用于后续异步更新。

示范例子

例子1:商品类别和商品品牌

下面是一个示例,假设我们的模型有两个ForeignKey字段,一个是商品类别,另一个是商品品牌,我们需要根据所选类别动态更新品牌选项。

# models.py

class Category(models.Model):
    name = models.CharField(max_length=100)

class Brand(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

class Product(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE)

# admin.py

class BrandInline(admin.TabularInline):
    model = Brand
    extra = 0

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        form = formset.form
        # 给form增加一个空白的brand表单
        form.fields['name'].widget = TextInput(attrs={'class': 'vTextField', 'autocomplete': 'off', 'style': 'width:68%'})
        form.fields['category'] = ModelChoiceField(queryset=Category.objects.all())
        form.fields['category'].widget.attrs.update({'class': 'vForeignKeyRawIdAdminField', 'style': 'width: 255px'})
        form.fields['category'].widget.to_field_name = 'id'
        form.fields['category'].label = ''
        form.fields['category'].empty_label = None
        return formset

class ProductAdmin(admin.ModelAdmin):
    inlines = [BrandInline]

    class Media:
        js = ('/static/js/admin/product.js',)

其中,product.js文件如下:

// product.js

(function ($) {
    $(document).ready(function () {
        // 监听category多选框的change事件
        $("#id_category").on("change", function () {
            var categoryId = $(this).val();
            // 异步加载brand选项
            $.ajax({
                url: "/admin/get-brands/",
                type: "POST",
                data: {
                    "csrfmiddlewaretoken": $("input[name=csrfmiddlewaretoken]").val(),
                    "category_id": categoryId
                },
                dataType: "json",
                success: function (response) {
                    var options = "<option value=''>---------</option>";
                    // 构建brand多选框的选项
                    $.each(response.brands, function (i, brand) {
                        options += "<option value='" + brand.id + "'>" + brand.name + "</option>";
                    });
                    $("#brand_set-group select").html(options);
                },
                error: function (response) {
                    console.log("error: " + response);
                }
            });
        });
    });
})(django.jQuery);

在这个例子中,我们使用了Django内置的get_formset方法来修改Inline Model的表单。我们可以看到在get_formset中,我们把原来的brand表单fields中的category选项替换成ModelChoiceField,并去除了empty_label选项。这样可以在前端渲染时去掉Select中第一个空白选项。同时我们也会发现,这种方式下会出现很多的空白行,可以通过重载has_add_permission()方法来控制。

例子2:商品分类和商品型号

下面是另一个示例,假设我们的模型有两个ManyToMany字段,一个是商品分类,另一个是商品型号,我们需要根据所选分类动态更新型号选项。

# models.py

class Category(models.Model):
    name = models.CharField(max_length=100)

class Model(models.Model):
    name = models.CharField(max_length=100)
    categories = models.ManyToManyField(Category)

class Product(models.Model):
    name = models.CharField(max_length=100)
    categories = models.ManyToManyField(Category)
    models = models.ManyToManyField(Model)

# admin.py

class ModelInline(admin.TabularInline):
    model = Product.models.through
    extra = 0

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        form = formset.form
        # 给form增加一个空白的model表单
        form.fields['model'] = ModelMultipleChoiceField(queryset=Model.objects.none())
        form.fields['model'].widget.attrs.update({'class': 'vManyToManyRawIdAdminField', 'style': 'width: 255px'})
        form.fields['model'].label = ''
        return formset

    # 根据所选分类,异步加载对应的model选项
    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        if db_field.name == "category":
            def model_choices_for_category(category):
                return Model.objects.filter(categories=category)

            class ModelChoiceField(ModelChoiceField):
                def __init__(self, category, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.category = category
                    self.choices = model_choices_for_category(category)

                def queryset(self, request):
                    return model_choices_for_category(self.category)

            ModelChoiceField.category = request.POST.get('category_set-0-category')
            kwargs['queryset'] = Category.objects.none()
            return ModelChoiceField(**kwargs)
        return super().formfield_for_foreignkey(db_field, request=request, **kwargs)

class ProductAdmin(admin.ModelAdmin):
    inlines = [ModelInline]

    class Media:
        js = ('/static/js/admin/product.js',)

在这个例子中,我们重载Inline Model的formfield_for_foreignkey方法,动态改变model的选项内容。在获取分类字段(db_field.name == "category")之后,我们使用输入分类ID后动态查询Model内容的方式来更新ModelMultipleChoiceField,当显示product页面需要修改对应行(ModelTable)右侧的ModelChoiceField多选框的时候,我们会发现Ajax动态更新的选项展示在了(product.js中 $('#model_set-group select[name$="-model"]').html(options);)最末尾中的特定div名的后面。

至此,两条Django admin实现动态多选框表单的完整示例代码攻略完毕。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:django admin实现动态多选框表单的示例代码 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • Docker 部署HAProxy v2.2.29 并暴露指标接口的问题解决

    下面我将详细讲解“Docker 部署HAProxy v2.2.29 并暴露指标接口的问题解决”的完整攻略。 准备工作 首先需要安装Docker,如果已经安装可以跳过这一步。 示例一:在Ubuntu系统上安装Docker # 添加Docker GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/g…

    人工智能概览 2023年5月25日
    00
  • .net Core连接MongoDB数据库的步骤详解

    针对“ .Net Core 连接 MongoDB 数据库的步骤详解”,我将给出以下完整攻略。 1.安装MongoDB 首先需要安装并启动MongoDB数据库。可以从MongoDB官网下载安装程序,安装完成后启动MongoDB。 2.安装MongoDB.Driver 第二步是安装MongoDB.Driver,这是一个.NET的驱动程序包,用于连接MongoDB…

    人工智能概论 2023年5月25日
    00
  • 关于nginx+uWsgi配置遇到的问题的解决

    当使用 Nginx 与 uWsgi 部署 Python Web 应用时,可能会遇到一些配置问题。下面是一些常见问题及其解决方法。 问题 1:Nginx 无法将请求传递给 uWsgi 解决方案 确认 Nginx 是否正确地将请求传递给 uWsgi。检查 Nginx 配置文件 (通常是 /etc/nginx/nginx.conf) 确保它包含以下行: locat…

    人工智能概览 2023年5月25日
    00
  • 分布式医疗挂号系统EasyExcel导入导出数据字典的使用

    分布式医疗挂号系统EasyExcel导入导出数据字典的使用 简介 分布式医疗挂号系统是一款以医院挂号业务为主线,为广大患者提供线上看病、在线咨询、预约挂号、处方购买等全方位一站式服务的医疗系统。数据字典是该系统中重要的文档,用于记录系统中各种实体和字段的相关信息,方便管理和开发人员查看和使用。本文主要介绍EasyExcel导入导出数据字典的使用。 什么是Ea…

    人工智能概览 2023年5月25日
    00
  • Windows环境下配置Qt 5.8+opencv 3.1.0开发环境的方法

    下面是详细的“Windows环境下配置Qt 5.8+opencv 3.1.0开发环境的方法”的攻略: 环境要求 Windows操作系统 Qt5.8+(建议使用官方安装包,如qt-opensource-windows-x86-5.8.0.exe) opencv3.1.0+ (建议使用官方安装包,如opencv-3.1.0.exe) 步骤 1. 安装Qt5 安装…

    人工智能概览 2023年5月25日
    00
  • Laravel 5 框架入门(一)

    Laravel 5 框架入门(一) Laravel 是一款优秀的 PHP Web 框架,能够帮助开发者快速构建现代化的 Web 应用程序。本文将从安装 Laravel 开始,详细介绍 Laravel 框架的使用方法。 环境要求 要使用 Laravel 5,您需要满足以下环境要求: PHP 版本 7.2.0 或更高版本 BCMath PHP 扩展 Ctype …

    人工智能概览 2023年5月25日
    00
  • JavaCV实现读取视频信息及自动截取封面图详解

    JavaCV实现读取视频信息及自动截取封面图详解 JavaCV是Java和OpenCV的一套接口,可以轻松地在Java环境下使用OpenCV库。本文将介绍如何使用JavaCV读取视频信息以及如何自动截取封面图。 基本环境 Java 8或以上版本 Maven JavaCV 读取视频信息 通过JavaCV可以实现读取视频信息,包括视频的宽度、高度、帧率以及时长等…

    人工智能概览 2023年5月25日
    00
  • pycharm2021激活码使用教程(永久激活亲测可用)

    以下是“pycharm2021激活码使用教程(永久激活亲测可用)”的完整攻略: 前言 PyCharm是一款针对Python语言的开发环境,它提供了丰富的功能和友好的界面,因此备受许多Python开发者的青睐。而本教程将为大家详细介绍PyCharm 2021版本的激活流程。 操作步骤 步骤一:下载安装PyCharm 首先,我们需要下载并安装PyCharm。可以…

    人工智能概览 2023年5月25日
    00
合作推广
合作推广
分享本页
返回顶部