开发功能需求文档: Django 管理后台图片字段管理

news/2024/12/23 20:18:20 标签: django, 数据库, sqlite

开发功能需求文档: Django 管理后台图片字段管理

在这里插入图片描述

  1. 概述
    本需求旨在详细描述在Django管理后台中实现图片字段管理功能的开发需求。该功能主要包括以下几点:

在新增数据时,上传并预览图片。

在修改已有数据时,显示当前图片及其文件名,并提供上传新图片和清除图片的选项。

验证上传图片的类型和大小,确保上传文件符合要求。

  1. 需求背景
    在实际应用中,许多管理系统需要用户上传和管理图片。例如,在电子商务网站中,管理员需要上传和管理商品图片;在内容管理系统(CMS)中,管理员需要上传和管理媒体文件。本需求旨在提供一个可复用的Django组件,以便在管理后台中高效、可靠地管理图片字段。

  2. 功能需求
    3.1 新增数据
    3.1.1 功能描述
    在新增数据页面,用户可以通过文件输入框上传新图片,并实时预览新上传的图片。同时,显示待上传图片的路径和文件名。

3.1.2 界面展示
文件输入框,用于选择并上传新图片。

图片预览框,初始状态为隐藏,选择图片后显示预览。

文件路径和文件名的显示区域,初始状态为空。

3.1.3 业务逻辑
用户通过文件输入框选择图片。

使用JavaScript读取文件内容,并将其显示在预览框中。

显示待上传图片的路径和文件名。

3.1.4 异常处理
验证文件类型是否为JPEG、PNG或GIF格式。

验证文件大小是否不超过2MB。

若验证不通过,则提示用户并清空文件输入框。

3.2 修改已有数据
3.2.1 功能描述
在修改已有数据页面,用户可以查看当前图片及其文件名,并提供上传新图片和清除图片的选项。

3.2.2 界面展示
当前图片的显示区域,包括图片预览和文件名。

文件输入框,用于选择并上传新图片。

图片预览框,初始状态为隐藏,选择图片后显示预览。

文件路径和文件名的显示区域,初始状态为空。

清除已上传图片的选项,非必填项时显示。

3.2.3 业务逻辑
检查当前数据是否有初始图片。

若有初始图片,则显示当前图片及其文件名,并提供清除选项。

用户通过文件输入框选择新图片,实时预览并显示新图片的路径和文件名。

3.2.4 异常处理
验证文件类型是否为JPEG、PNG或GIF格式。

验证文件大小是否不超过2MB。

若验证不通过,则提示用户并清空文件输入框。

  1. 详细实现
    4.1 前端实现
    4.1.1 HTML 模板
    文件路径:templates/custom_clearable_file_input.html
<!-- 新图片上传部分 -->
<div class="new-image">
    <p>上传新图片:</p>
    <input type="file" name="{{ widget.name }}" accept="image/*" id="{{ widget.attrs.id }}">
    <img class="newImgPreview" src="#" alt="请选择替换的图片" style="max-width: 200px; max-height: 200px; display:none;" />
</div>

<!-- 若有初始值,显示当前图片及文件名 -->
{% if widget.is_initial %}
    <div class="current-image">
        <p>当前图片:</p>
        <img src="{{ widget.value.url }}" style="max-width: 200px; max-height: 200px;" alt="现有使用中的图片" />
        <p>文件名: <span>{{ widget.value.name }}</span></p>
        {% if not widget.is_required %}
            <span class="clearable-file-input">
                <input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}">
                <label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>
            </span>
        {% endif %}
    </div>
{% endif %}

<!-- 待上传图片的预览路径和文件名 -->
<div class="preview-details">
    <p>待上传图片路径: <span id="file-path-{{ widget.attrs.id }}"></span></p>
    <p>图片文件名: <span id="file-name-{{ widget.attrs.id }}"></span></p>
</div>

<!-- JavaScript 处理逻辑 -->
<script>
document.addEventListener("DOMContentLoaded", function() {
    // 查找所有文件输入框,处理多个图片字段的情况
    document.querySelectorAll('input[type="file"]').forEach(function(fileInput) {
        // 获取对应的文件路径和文件名显示区域,以及预览图片元素
        var filePathSpan = document.getElementById("file-path-" + fileInput.id);
        var fileNameSpan = document.getElementById("file-name-" + fileInput.id);
        var previewImage = fileInput.nextElementSibling;

        // 文件选择事件监听器
        fileInput.addEventListener("change", async function(event) {
            var file = event.target.files[0];
            if (!file) return;

            // 文件类型和大小验证
            var validTypes = ["image/jpeg", "image/png", "image/gif"];
            var maxSize = 2 * 1024 * 1024; // 2MB
            if (!validTypes.includes(file.type)) {
                alert("仅支持 JPEG, PNG 和 GIF 格式的图片。请上传正确的文件类型。");
                fileInput.value = "";
                return;
            }
            if (file.size > maxSize) {
                alert("图片大小不能超过 2MB。请压缩图片或选择更小的文件。");
                fileInput.value = "";
                return;
            }

            try {
                var reader = new FileReader();
                reader.onload = function(e) {
                    // 显示文件预览
                    previewImage.src = e.target.result;
                    previewImage.style.display = 'block';
                }
                reader.readAsDataURL(file);

                // 显示文件路径和文件名
                var filePath = fileInput.value.split('\\').pop(); // 修正路径显示问题
                var fileName = file.name;
                filePathSpan.textContent = filePath;
                fileNameSpan.textContent = fileName;
            } catch (error) {
                console.error("文件处理过程中发生错误:", error);
                alert("文件处理失败,请重试。");
            }
        });
    });
});
</script>

4.2 后端实现
4.2.1 自定义表单小部件
文件路径:custom_widgets.py

from django import forms
from django.utils.safestring import mark_safe
from django.template.loader import render_to_string

class CustomClearableFileInput(forms.ClearableFileInput):
    template_name = 'custom_clearable_file_input.html'

    def render(self, name, value, attrs=None, renderer=None):
        context = self.get_context(name, value, attrs)
        return mark_safe(render_to_string(self.template_name, context))

4.2.2 管理界面配置
子应用 kiki 中的管理界面配置

文件路径:kiki/admin.py

from django.contrib import admin
from django import forms
from .models import KikiModel
from custom_widgets import CustomClearableFileInput

class KikiModelAdminForm(forms.ModelForm):
    class Meta:
        model = KikiModel
        fields = '__all__'
        widgets = {
            'image_field': CustomClearableFileInput(),
        }

class KikiModelAdmin(admin.ModelAdmin):
    form = KikiModelAdminForm

admin.site.register(KikiModel, KikiModelAdmin)

子应用 wenzhang 中的管理界面配置
文件路径:wenzhang/admin.py

# wenzhang/admin.py
from django import forms
from django.contrib import admin
from .models import Article
from custom_widgets import CustomClearableFileInput

class ArticleAdminForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = '__all__'
        widgets = {
            'image_1': CustomClearableFileInput(),
            'image_2': CustomClearableFileInput(),
            'image_3': CustomClearableFileInput(),
            'image_4': CustomClearableFileInput(),
            'image_5': CustomClearableFileInput(),
        }

class ArticleAdmin(admin.ModelAdmin):
    form = ArticleAdminForm
    list_display = ('title_cn', 'title_en', 'summary_cn', 'summary_en', 'recommended_products_count', 'created_at', 'updated_at', 'change_count')
    search_fields = ('title_cn', 'title_en')
    fieldsets = (
        ('标题', {
            'fields': (('title_cn', 'title_en'),)
        }),
        ('概括', {
            'fields': (('summary_cn', 'summary_en'),)
        }),
        ('内容', {
            'fields': (('content_cn', 'content_en'),)
        }),
    )
    for i in range(1, 6):
        fieldsets += (
            (f'推荐商品{i}', {
                'fields': (
                    f'product_{i}', f'product_{i}_title_cn', f'product_{i}_title_en', 
                    f'product_{i}_summary_cn', f'product_{i}_summary_en', 
                    f'product_{i}_link_cn', f'product_{i}_link_en',
                    f'image_{i}', f'tag_choice_{i}'
                )
            }),
        )
    readonly_fields = ('created_at', 'updated_at', 'change_count', 'modification_times')

    def recommended_products_count(self, obj):
        count = sum([getattr(obj, f'product_{i}') for i in range(1, 6)])
        if count:
            return format_html('<span>✔</span> {}', count)
        else:
            return format_html('<span>✖</span> {}', count)
    recommended_products_count.short_description = '推荐商品数量'

admin.site.register(Article, ArticleAdmin)

  1. 开发流程
    5.1 准备工作
    安装 Django: 确保在开发环境中安装了Django,并创建一个新的Django项目和应用。

数据库迁移: 创建和应用数据库迁移,确保所有模型和字段在数据库中存在。

5.2 实现自定义表单小部件
创建 custom_widgets.py 文件: 在项目根目录下创建 custom_widgets.py 文件。

定义自定义表单小部件: 在 custom_widgets.py 文件中定义 CustomClearableFileInput 类,继承自 forms.ClearableFileInput,并指定模板文件。

5.3 配置模板文件
创建模板目录: 在项目目录下创建 templates 目录,并在其中创建 custom_clearable_file_input.html 文件。

编写模板文件: 按照需求书中的HTML模板编写模板文件,确保包括上传新图片、显示当前图片及文件名、预览路径和文件名的功能。

5.4 更新子应用中的管理界面配置
修改 admin.py 文件: 在每个需要使用图片字段的子应用中,修改 admin.py 文件。

使用自定义表单小部件: 在 ModelForm 中指定图片字段使用自定义表单小部件 CustomClearableFileInput。

5.5 编写和测试 JavaScript 逻辑
编写 JavaScript 逻辑: 在模板文件中编写JavaScript逻辑,处理文件选择、文件类型和大小验证、文件预览和路径及文件名显示。

测试功能: 在浏览器中测试各个功能,确保文件选择、预览、验证和异常处理逻辑正常工作。

  1. 测试与验证
    单元测试: 编写单元测试,验证自定义表单小部件和管理界面配置的正确性。

集成测试: 在实际使用环境中进行集成测试,确保所有功能在不同浏览器和设备上均能正常运行。

用户反馈: 收集用户反馈,修复可能存在的BUG,进一步优化用户体验。

  1. 文档与培训
    编写用户手册: 编写详细的用户手册,指导管理员如何在Django管理后台中使用图片字段管理功能。

培训课程: 设计培训课程,帮助管理员熟练掌握图片字段的上传、预览和管理技能。

  1. 发布与维护
    发布版本: 在测试通过后,将新功能发布到生产环境中。

持续维护: 监控功能使用情况,及时修复问题,保持代码的稳定性和可靠性。


http://www.niftyadmin.cn/n/5796950.html

相关文章

Android -- 双屏异显之方法二

Android – 双屏异显之方法二: DisplayManager PS: 1. 使用改方法主板需连接至少两个输出显示屏&#xff1b; 2. 副屏内部实现与MediaRouter下一样&#xff1b;使用方法 # 主屏activity内&#xff1a; private SecondDisplay secondDisplay;private void dualScreen3288() {D…

第二十六周学习周报

目录 摘要Abstract1 FOMM(一阶运动模型)1.1 基本框架1.2 实验1.3 代码分析 2 LSTM复习2.1 LSTM原理1.2 LSTM反向传播的数学推导 总结 摘要 本周的主要学习内容是FOMM模型&#xff0c;FOMM一种用于图像动画的技术&#xff0c;它能够通过给定的源图像和驱动视频生成逼真的动画序…

ARM 处理器平台 Ethernet Compliance 测试流程示例

By Toradex秦海 1). 简介 为了保证基于IEEE 802.3 协议设计的以太网设备接口可以互相兼容互联互通&#xff0c;需要进行 Ethernet Compliance 一致性测试&#xff0c;相关的技术原理说明请参考如下文章&#xff0c;本文就不赘述&#xff0c;主要展示基于 NXP i.MX8M Mini ARM…

【java 正则表达式 笔记】

文章目录 快速入门匹配中文或数字或大小写字母(一个或多个) 正则表达式底层实现(重要)mather.find() 完成的任务mather.group(0) 分析 正则表达式基本语法元字符转义字符区分大小写限定字符选择匹配符特殊字符字符匹配符定位符 分组、捕获和反向引用捕获特别分组反向引用经典结…

行数据转换为list的小工具

遇到email 邮件&#xff0c;收件人多的时候要以 ; 进行分隔 数据库 select 的条件 in &#xff08;xxxxx,xxx&#xff09;要用逗号分隔 python list 则是[xxxx,xxxx] 逗号分隔&#xff0c;而且还要添加 " " 整理这个数据实在麻烦 希望效果如下&#xff1a;这样以…

2024多模态大模型综述最新总结

摘要 随着人工智能技术的快速发展&#xff0c;多模态大模型&#xff08;MLLM&#xff09;已成为研究的新热点。这些模型以强大的大型语言模型&#xff08;LLM&#xff09;为基础&#xff0c;能够处理和理解多种模态信息&#xff0c;如文本、图像、视频和音频。本文综述了MLLM的…

详细ECharts图例3添加鼠标单击事件的柱状图

<!DOCTYPE html><html><head><meta charset"UTF-8"><script src"js/echarts.js"></script> <!-- 确保路径正确 --><title>添加鼠标单击事件的柱状图</title></head><body><div id&q…

【机器人】机械臂位置、轨迹和转矩控制概要

仍旧以 RRR&#xff08;三连杆&#xff09;为例&#xff0c;实现控制&#xff0c;可以采用以下步骤。这里的控制包括 位置控制轨迹控制 轨迹跟踪控制&#xff0c; 具体根据应用需求选择。以下是实现 RRR 机械臂控制的完整过程&#xff1a; 1. 定义机器人模型 通过 Denavit-H…