zoukankan      html  css  js  c++  java
  • Django 自定义存储上传文件的文件名

    一、需求:

    Django实现自定义文件名存储文件
    	使文件名看起来统一
    	避免收到中文文件导致传输、存储等问题
    	相同的文件也需要使用不同的文件名
    

    二、实现思路:

    思路:
    	生成14位随机字母加数字、后10位采用时间戳。从而实现相同文件不同文件名
    
    1.view版:
    	在view接收到文件名之后进行重命名,不修改Django默认的文件存储逻辑。从而实现需求
    2.upload_to版
    	参考链接:https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.FileField.upload_to
    	官方原文:
    	upload_to may also be a callable, such as a function. This will be called to obtain the upload path, including the filename. 
    	upload_to也可以是可调用的,例如函数。这将被调用以获得上载路径,包括文件名。
    3.自定义存储系统:
    	暂时没那个必要:只是单纯的修改个文件名而已
    4.forms版(20210206补充):
    	使用clean方法对文件格式验证并修改文件名
    

    三、具体实现:

    1. views版:

      涉及views.py 、utils.py(自定义)

      • views.py:

        class UploadIdentImageView(APIView):
            def get(self, request, *args, **kwargs):
                return Response({"msg":"ident", "status_code": True})
        
            def post(self, request, *args, **kwargs):
                # from somewhere import handle_uploaded_file
                file_name = request.FILES.get("file", None)
                if not file_name:
                    return Response({"msg": "ident", "status_code": False})
        
                from test_app.utils import custom_file_name
                file_name.name = custom_file_name(file_name)
        
                models_object = models.IdCardImage(image_path=file_name)
                models_object.save()
                print(models_object)
                return Response({"msg":"ident", "status_code": True})
        
      • test_apputils.py

        def random_str():
            import random
            import time
        
            num_set = [chr(i) for i in range(48, 58)]
            char_set = [chr(i) for i in range(97, 123)]
            total_set = num_set + char_set
            bits = 14
            value_set = "".join(random.sample(total_set, bits))
            return value_set + str(int(time.time()))
        
        def custom_file_name(file_name):
            file_type = str(file_name).split(".")[-1]
            new_file_name = random_str().upper()
        
            return ".".join([new_file_name,file_type])
        
    2. upload_to版:

      涉及models.py。test_apputils.py沿用上面内容

      • models.py

        def user_directory_path(upload_to):
            def wrapper(instance, filename):
                import datetime
                import os
                from mini_programe.utils import custom_file_name
        
                filename = custom_file_name(filename)
        
                dirname = datetime.datetime.now().strftime(upload_to)
                new_upload_to = os.path.join(dirname,filename)
                return new_upload_to
            return wrapper
        
        
        class IdCardImage(models.Model):
            f_id = models.ForeignKey(Users, on_delete=models.SET_NULL,null=True,verbose_name="用户",related_name="user_id_card_img")
            # image_path = models.FileField(upload_to='media/id_card_img/%Y/%m/')
            image_path = models.FileField(upload_to=user_directory_path('media/id_card_img/%Y/%m/'))
        
        

    4.forms版

    • forms.py
    class IdCardImageForm(forms.ModelForm):
        class Meta:
            model = models.IdCardImage
            fields = "__all__"
    
        def clean_image_path(self):   #clean_字段名
            file = self.cleaned_data["image_path"]
            ext = file.name.split(".")[-1].lower()
            
            if ext != "png":
                raise forms.ValidationError("仅允许上传png文件")
            new_file_name = random.randint(111111111,9999999999)
            file.name = "%d.png"%new_file_name
            
            return file
    
    • models.py
    class IdCardImage(models.Model):
        f_id = models.ForeignKey(Users, on_delete=models.SET_NULL,null=True,verbose_name="用户",related_name="user_id_card_img")
        image_path = models.FileField(upload_to='media/id_card_img/%Y/%m/')
    
    • views.py
    class UploadIdentImageView(TemplateView):
        def get(self,....)
            ....
        def post(self,request,*args,**kwargs):
            check_form = forms.IdCardImageForm(request.POST,request.FILES)
            if not check_form.is_valid():
                return JsonResponse({'message': check_form.errors, "code": 400})
            instance = check_form.save()
            return JsonResponse({'message': instance.name + ",保存成功","code":200})
    
    • upload.html
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    
    function upload_pdf() {
        const csrftoken = getCookie('csrftoken');
        
        var form = new FormData();
        form.append("f_id", $("#f_id").val());
        form.append("image_path", $("#image_path")[0].files[0]);
        $.ajax({
            headers: {'X-CSRFToken': csrftoken},
            url: "{% url 'add_data' %}",
            type: "POST",
            data: form,
            
            processData: false,
            contentType: false,
            cache: false,
            
            success: function (result) {
                if (result.code === 200) {
                    alert_message(JSON.stringify(result.message));
                        } else {
                            console.log("success", result);
                            alert_message(JSON.stringify(result.message));
                        }
                    },
                    fail: function (result) {
                        console.log("fail",);
                        alert_message(result.info);
                    },
                    error: function (result) {
                        alert_message(result.status + ": " + result.statusText);
                    }
                });
    
            }
    

    四、最终效果:

    • 图片:

    五、效果对比:

    ​ 个人更倾向于方案二或方案四,理由是:views.py文件中的处理函数的处理逻辑应该看起来简单一些。例如采用方案二整理后的view.py看起来像这样:

    class UploadIdentImageView(APIView):
        def get(self, request, *args, **kwargs):
            return Response({"msg":"ident", "status_code": True})
    
        def post(self, request, *args, **kwargs):
            file_name = request.FILES.get("file", None)
            if not file_name:
                return Response({"msg": "ident", "status_code": False})
    
            models_object = models.IdCardImage(image_path=file_name)
            models_object.save()
            return Response({"msg":"ident", "status_code": True})
    

    生成随机字母加数字的逻辑参考链接:https://blog.csdn.net/u010039418/article/details/86013620

  • 相关阅读:
    BZOJ 1630/2023 Ant Counting 数蚂蚁
    BZOJ 3997 组合数学
    BZOJ 2200 道路与航线
    BZOJ 3181 BROJ
    BZOJ 4011 落忆枫音
    BZOJ 4027 兔子与樱花
    vijos 1741 观光公交
    vijos 1776 关押罪犯
    vijos 1780 开车旅行
    5、异步通知机制
  • 原文地址:https://www.cnblogs.com/lisicn/p/14031615.html
Copyright © 2011-2022 走看看