开发功能需求文档: Django 管理后台图片字段管理
- 概述
本需求旨在详细描述在Django管理后台中实现图片字段管理功能的开发需求。该功能主要包括以下几点:
在新增数据时,上传并预览图片。
在修改已有数据时,显示当前图片及其文件名,并提供上传新图片和清除图片的选项。
验证上传图片的类型和大小,确保上传文件符合要求。
-
需求背景
在实际应用中,许多管理系统需要用户上传和管理图片。例如,在电子商务网站中,管理员需要上传和管理商品图片;在内容管理系统(CMS)中,管理员需要上传和管理媒体文件。本需求旨在提供一个可复用的Django组件,以便在管理后台中高效、可靠地管理图片字段。
-
功能需求
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。
若验证不通过,则提示用户并清空文件输入框。
- 详细实现
4.1 前端实现
4.1.1 HTML 模板
文件路径:templates/custom_clearable_file_input.html
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
python
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
python
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
python
# 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)
- 开发流程
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逻辑,处理文件选择、文件类型和大小验证、文件预览和路径及文件名显示。
测试功能: 在浏览器中测试各个功能,确保文件选择、预览、验证和异常处理逻辑正常工作。
- 测试与验证
单元测试: 编写单元测试,验证自定义表单小部件和管理界面配置的正确性。
集成测试: 在实际使用环境中进行集成测试,确保所有功能在不同浏览器和设备上均能正常运行。
用户反馈: 收集用户反馈,修复可能存在的BUG,进一步优化用户体验。
- 文档与培训
编写用户手册: 编写详细的用户手册,指导管理员如何在Django管理后台中使用图片字段管理功能。
培训课程: 设计培训课程,帮助管理员熟练掌握图片字段的上传、预览和管理技能。
- 发布与维护
发布版本: 在测试通过后,将新功能发布到生产环境中。
持续维护: 监控功能使用情况,及时修复问题,保持代码的稳定性和可靠性。