Django - admin 表单编辑页面,增加自定义功能,前端上传视频到oss
# 背景:可以在admin编辑页面原有基础上,增加一些可定制的功能,如:在本地上传图片到oss,减少服务器的带宽压力,下面就以此为例。
示例图:
一。models.py
# video 可以直接用字符串存储,因为最终里面只有有一串oss的视频路径
class News(models.Model): OSS_URL = 'https://xxxx.aliyuncs.com'
video = models.FileField(verbose_name="视频", upload_to="news/video")
二。admin.py
@admin.register(News) class NewsAdmin(admin.ModelAdmin): list_display = ('id', 'video') # 覆盖内置的编辑页面,增加自定义页面(继承原有页面的所有内容,并增加自定义内容) # 该页面存放在 /templates/admin/ 目录下 change_form_template = 'admin/addfile.html' def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): # 可设置字段,通过模板语言显示到 addfile.html 页面中 context['accessKeyId'] = '111' context['accessKeySecret'] = '222' if obj and obj.video: context['video_url'] = News.OSS_URL+obj.video.url return super(ZhongYeGuanZhuAdmin, self).render_change_form(request, context, add, change, form_url, obj) def save_model(self, request, obj, form, change): # 拿到前端返回的oss视频地址, 并存入数据库 video = request.POST.get('video') if video: obj.video = video super().save_model(request, obj, form, change)
三。addfile.html
# 1. 页面继承了原有编辑面的内容,并加入了自己的代码进去
# 2. 请注意页面引入了 layui.css,layui.js,aliyun-oss-sdk.js,format.js 多个库
# 3. 请注意页面中的 js 代码需要引入 django.jQuery 才会生效
<link rel="stylesheet" href="xxx.aliyuncs.com/layui/css/layui.css" media="all"> {% extends 'admin/change_form.html' %} {% load static %} {% block admin_change_form_document_ready %} {{ block.super }} <style> #up_{ margin-left: 30px; display: inline-block; width: 60px; height: 30px; text-align: center; line-height: 30px; background: green; color: #fff !important; } </style> <script src="http://xxx.aliyuncs.com/layui/layui.js"></script> <script src="https://xxx.aliyuncs.com/js/aliyun-oss-sdk-6.16.0.min.js"></script> <script src="http://xxx.aliyuncs.com/js/date.format.js"></script> <script> (function($) {
{% if video_url %} $('.field-video .file-upload a')[0].href = '{{ video_url }}'; {% endif %} $("#id_video").before('<input type="hidden" name="video" id="video">'); $("#id_video").after('<a href="javascript:;" id="up_">上传视频</a>'); var loading; async function upload_to_oss(file_, mulu){ // 设置加载 loading = layer.load(2, { shade: 0.4 }); let client = new OSS({ region: "oss-cn-beijing", accessKeyId: "{{ accessKeyId }}", accessKeySecret: "{{ accessKeySecret }}", stsToken: "", bucket: "testz", }); // 将文件上传oss const options = { // 获取分片上传进度、断点和返回值。 progress: (p, cpt, res) => { console.log(p); }, // 设置并发上传的分片数量。 parallel: 4, // 设置分片大小。默认值为1 MB,最小值为100 KB。 partSize: 1024 * 1024, // headers, // 自定义元数据,通过HeadObject接口可以获取Object的元数据。 meta: { year: 2024 }, mime: "text/plain", } let lujing = mulu + Date.now()+'-'+file_.name; try { // 分片上传。 const res = await client.multipartUpload('/media'+lujing, file_, { ...options, }); return {'file_name': lujing} } catch (err) { console.log(err); layer.close(loading); return {'error': '上传失败, 请稍后再试'} } } $("#up_").click(async function () { let id_video = $("#id_video")[0].files; console.log('id_video >', id_video) if(id_video.length <= 0){ layer.msg('请选择视频文件'); return false; } let file = id_video[0]; console.log('file >', file) await upload_to_oss(file, '/{{ upload_to }}/').then(function (data) { layer.close(loading); if(data.error){ layer.msg(data.error); return false; } let f_name = data.file_name; $("#video").val(f_name); layer.msg('上传成功'); }); }) })(django.jQuery); </script> {% endblock %}