django admin 上传文件并显示文件图标

django admin 上传文件并显示文件图标

1.效果预览

文件上传效果

2.自定义文件widget

2.1 定义django模板过滤器

为了显示已经上传的文件的文件名,需要从django模板上下文变量widget.value中将文件名提取出来。在应用目录下新建templatetags文件夹,在里面新建两个python文件customfilter.py和_init_.py(__是两个下划线),编写自定义过滤器

# 自定义模板过滤器
# 从文件url中获取文件名
from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()


@register.filter
def get_file_name(value):
    # 从文件URL中获取文件名
    return str(value).split('/')[-1]

2.2 定义widget模板文件

自定义widget的模板文件来替换django admin的默认模板。

upload_file.html

{% load static %}
{% load customfilter %}

{#如果原来有上传的文件#}
{% if widget.value.url %}
	{# 原来有上传的文件,显示原来上传的文件图标#}
    <div class="selected-file"
         style="background-image: url('{% static 'myapp/file.png' %}');
                 background-repeat: no-repeat;background-position: center;background-size: 48px;">
        <i class="iconfont icon-delete" οnclick="delete_selected_file(this)"
           style="z-index: 999;background-color:rgba(255,255,255,.8);position: absolute;right: 0;top: 0;"
           title="删除文件"></i>
    </div>

    {# 原来有上传的文件,先隐藏图片上传组件#}
    <div class="upload-file-container" id="upload-file-container"
         style="background-image: url('{% static 'myapp/uploadfile.png' %}');background-repeat: no-repeat;background-size:48px;
                 background-position: center;display: none;">
        <input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %}
               value="{{ widget.value|stringformat:'s' }}"{% endif %}
               id="id_uploadGoodsDetail"
               accept="text/html,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
               οnchange="show_file(this)">
    </div>
    <div class="help" id="upload_file_help" hidden>支持上传小于2M的pdf、word和html文档</div>


    <div class="help" id="selected_file_name"><a href="{{ widget.value.url }}">{{ widget.value|get_file_name }}</a>
    </div>

{% else %}
    <div class="upload-file-container" id="upload-file-container"
         style="background-image: url('{% static 'myapp/uploadfile.png' %}');background-repeat: no-repeat;background-size:48px;
                 background-position: center;">
        <input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %}
               value="{{ widget.value|stringformat:'s' }}"{% endif %}
               id="id_uploadGoodsDetail"
               accept="text/html,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
               οnchange="show_file(this)">
    </div>
    <div class="help" id="upload_file_help">支持上传小于2M的pdf、word和html文档</div>

    <div class="help" id="selected_file_name" hidden></div>
{% endif %}

{#引入jquery#}
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

<script type="text/javascript">
    var upload_file_container = $("#upload-file-container");//选择文件上传
    var upload_help = $("#upload_file_help");//上传文件帮助文本
    var selected_file_name = $("#selected_file_name");//选中的文件名

    //将想要上传的文件显示为图标+文件名
    function show_file(e) {
        var file = e.files[0];
        //console.log("file", file);
        //检查文件拓展名
        var ext = file.name.slice(file.name.lastIndexOf(".") + 1).toLowerCase();
        var file_name = file.name;//选中的文件名
        //console.log("%%%%%%%", ext);

        if ("pdf" == ext || "html" == ext || "doc" == ext || "docx" == ext) {
            //添加文件图标
            upload_file_container.before("<div class=\"selected-file\"\n" +
                "     style=\"background-image: url('{% static 'myapp/file.png' %}');\n"+
                "             background-repeat: no-repeat;background-position: center;background-size: 48px;\">\n" +
                "    <i class=\"iconfont icon-delete\"\n" +
                "       style=\"z-index: 999;background-color:rgba(255,255,255,.8);position: absolute;right: 0px;top: 0px;\"\n" +
                "       title=\"删除文件\" οnclick=\"delete_selected_file(this)\"></i>\n" +
                "</div>");
            selected_file_name.html(file_name);//设置选中的文件名
            selected_file_name.show();
            upload_file_container.hide();//隐藏上传文件的组件
            upload_help.hide();//隐藏帮助文本

        } else {
            alert("选择的文件类型不正确,只能上传pdf、html或word文档");
            e.value = '';//清空input的值
        }
    }

    //删除选中的文件
    function delete_selected_file(e) {
        $(e).closest(".selected-file").remove();
        selected_file_name.hide();//隐藏显示文件名的组件
        upload_file_container.show();//显示文件上传组件
        upload_help.show();//显示文件上传帮助文本
    }
</script>
<style>
    .upload-file-container {
        width: 48px;
        height: 48px;
        position: relative;
        display: inline-block;
        overflow: hidden;
    }

    .upload-file-container input {
        position: absolute;
        top: 0;
        height: 100px;
        opacity: 0;
    }

    .upload-file-container:hover {
        border: solid #25adc6 1px;
    }

    /*已经选中的文件显示*/
    .selected-file {
        width: 64px;
        height: 64px;
        position: relative;
        display: inline-block;
        overflow: hidden;
    }

    //删除符号使用阿里云字体图标
    
    @font-face {
        font-family: 'iconfont';  /* project id 1361777 */
        src: url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.eot');
        src: url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.eot?#iefix') format('embedded-opentype'),
        url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.woff2') format('woff2'),
        url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.woff') format('woff'),
        url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.ttf') format('truetype'),
        url('//at.alicdn.com/t/font_1361777_ufufbwqmfpa.svg#iconfont') format('svg');
    }

    .iconfont {
        font-family: "iconfont" !important;
        font-size: 20px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    .icon-delete:before {
        content: "\e63c";
    }
</style>

2.3 定义python类

# 上传文件的组件
class UploadFileInput(FileInput):
    template_name = "myapp/upload_file.html"

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

3.定义Model和ModelFrom

在应用的models.py中定义一个实验用的模型和模型表单

class UploadFileModel(models.Model):
     file = models.FileField("上传文件", upload_to="files/")
class UploadFileModelForm(ModelForm):
   file = forms.FileField(label="上传文件", widget=UploadFileInput,help_text="",
   required=False)

    class Meta:
        model = UploadFileModel
        fields = [ 'file', ]     

4.结束语

上述定制的文件上传组件在本地选择文件时并没有上传到服务器,只有在admin表单提交时才会提交至服务器,这样能减少ajax请求,方便修改,同时也省略了垃圾文件的处理逻辑,维护更简单。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安布奇

喜欢的朋友给点支持和鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值