热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

十、Django的文件上传

一、上传文件相关1.请求头ContentTypeContentType指的是请求体的编码类型,常见的类型共有3种:1.applicationxwwwformurlencoded最常

一、上传文件相关

  1. 请求头ContentType

ContentType指的是请求体的编码类型,常见的类型共有3种:

  1. application/x-www-form-urlencoded
    最常见的 POST 提交数据的方式了
    浏览器的原生 form 表单,如果不设置?enctype?属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个
    urlencoded是一种数据格式,
    比如:
    username=yang&password=123&csrfmiddlewaretoken=.......
    # 这样的一种格式,类似get请求提交数据的格式

        # 这样在后台,就可以通过request.POST,就可以直接拿到数据了
        
  2. multipart/form-data
    专门用来传输文件的消息格式,会把文件作为片段数据发送,而不是整个文件一起发送
  3. application/json
    告诉服务端消息主体是序列化后的 JSON 字符串
    之前给ajax传递数据,就是把字典写成了一个类似json类型的数据
    def login(request):
    ...
    ret = ‘{"code":0,"redirect_url":"/index/"}‘
    return HttpResponse(ret)

    在不加content_type=‘application/json‘时,传递过去的就是一个字符串
    def login(request):
    d1 = {"code":0,"redirect_url":"/index/"}
    import json
    d1_json = json.dumps(d1)
    return HttpResponse(d1_json,)

    success:function (res) {
     console.log(res,typeof res);
        # {"code": 0, "redirect_url": "/index/"} string
        ....
     }
    
    这个时候,就不方便我们后续的使用,我们期望还是能拿到一个字典(自定义对象的类型)

    使用content_type=‘application/json‘,ajax就会调用自己内部的反序列化机制,直接调用反序列化方法
    def login(request):
    d1 = {"code":0,"redirect_url":"/index/"}
    import json
    d1_json = json.dumps(d1)
    return HttpResponse(d1_json,content_type=‘application/json‘)

    success:function (res) {
     console.log(res,typeof res);
        # {code: 0, redirect_url: "/index/"} "object"
        ....
     }
    
    此时,ajax端不需要自己序列化,也拿到了object类型的对象,这是因为内部自动调用的
  4. application/json 在ajax端发送数据,我们如何在视图函数中应用

    $.ajax({
    url:‘{% url "data" %}‘,
    type:‘post‘,
    data:JSON.stringify({k1:‘v1‘,k2:‘v2‘}), # 序列化成字符串
    contentType:‘application/json‘, # 指定类型
    ....
    })

    3 此时再
    def data(request):
        print(request.POST)   # ,拿不到数据
        print(request.body)   # b'{"k1":"v1","k2":"v2"}',要从原始的数据拿
        return HttpResponse('ok')
    
    
    
    b'{"k1":"v1","k2":"v2"}'
  5. 总之:
    • 在django内部,对于content-type是application/x-www-form-urlencoded的,可以解析,通过request.POST.get()就能取值
    • 在django内部,对于content-type是application/json类型的,是不能解析的,需要再request.body中取原始的数据,再反序列化,才能拿到数据
    • content-type就是一个数据格式,后端针对不同的数据格式进行不同的解析,默认是urlencoded的,django可以解析
      技术图片
  6. JsonResponse

JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应

此时传递数据的时候,既不需要自己做序列化,也不需要指定content_type=‘application/json‘,只需要把数据直接放在JsonResponse里,就会自动帮你转换成json字符串,并且自动拼接content_type=‘application/json‘,

from django.http import JsonResponse  # 需要先导入

def login(request):
    d1 = {"code":0,"redirect_url":"/index/"}
    return JsonResponse(d1)
    # 注意:字典类型可以直接JsonResponse(d1),若不是字典,是列表等,就要JsonResponse(d1,safe=False)
    
success:function (res) {
    console.log(res,typeof res);
    # {code: 0, redirect_url: "/index/"} "object"
    ....
    }
    
此时,也仍然拿到了object类型的数据

例子:

需求:用户输入127.0.0.1:8000/home,通过路径返回home.html文件,home.html文件中用ajax从data路径得到数据,然后在自己页面显示成一个列表显示出来

# 配置路径:
    url(r'^home/', views.home,name='home'),
    url(r'^data/', views.data,name='data'),
    
# 视图views:
    def home(request):
        return render(request,'home.html')

    def data(request):
        # l1 = ['故人西辞黄鹤楼','烟花三月下扬州','孤帆远影碧空尽','唯见长江天际流']
        l1 = [11,22,33,44]
        return JsonResponse(l1,safe=False) # 列表要加safe
    
# home.html:
    
    可见,ajax通过异步请求,在data路径拿到了数据组成了li标签,然后放在了ul标签下。 自动拼接content_type='application/json',可以从网页的Network下的XHR观察出来,XHR下的请求就是ajax请求

    技术图片

    1. form表单上传文件

    2. 配置路径 url(r‘^upload/‘, views.upload,name=‘upload‘),
    3. 写html,就一个表单提交数据,文件提交的(input属性是type="file")

      {% csrf_token %}
      头像:
      用户名:

    4. 写视图函数
      def upload(request):
      if request.method == ‘GET‘:
      return render(request,‘upload.html‘)
      else:
      print(request.POST)
      # 拿到的是post请求的数据,文件相关数据去request.FILES拿
      return HttpResponse(‘ok‘)

      打印的request.POST,数据如下:
      

      从得到的数据可以发现,request.POST得到的文件数据就是一个名字,没有任何意义

    5. 文件的数据,都在request.FILES中
      # 在form表单里,要先指定消息格式
      # 默认的请求消息格式是urlencoded,携带不了文件数据
      # 要指定multipart/form-data才可以携带数据

      ......

      def upload(request):
          if request.method == 'GET':
              return render(request,'upload.html')
          else:
              print(request.FILES)
              return HttpResponse('ok')
      
      # 如果form表单没有指定文件的消息格式,接收不到数据,就得到一个空字典:
      
      
      # 此时再打印request.FILES就拿到了上传了文件的数据:
      ]}>
    6. 把得到的文件数据读取出来,并保存到本地
      def upload(request):
      if request.method == ‘GET‘:
      return render(request,‘upload.html‘)
      else:
      file_obj = request.FILES.get(‘head_pic‘)
      file_name = file_obj.name

              with open(file_name,'wb') as f:
                  for i in file_obj:
                      f.write(i)
              return HttpResponse('ok')
    7. 以上方法上传的文件没有指定路径,就直接保存在了项目的文件夹里;此时想要把上传的文件保存在指定的文件夹中,比如项目下的statics中的img文件夹中
      from ajax_pro import settings
      import os

      def upload(request):
          if request.method == 'GET':
              return render(request,'upload.html')
          else:
      
              file_obj = request.FILES.get('head_pic')
              file_name = file_obj.name
      
              path = os.path.join(settings.BASE_DIR,'statics','img',file_name)
              # 拼接路径
              with open(path,'wb') as f:
                  for i in file_obj:
                      f.write(i) 
                      # 每次读的文件不是固定长度,每次读一行,识别符为\r,\n,,\r\n,遇到这几个符号就算是读了一行
      
              return HttpResponse('ok')
    8. 另一种保存文件的方法:
      from ajax_pro import settings
      import os

      def upload(request):
          if request.method == 'GET':
              return render(request,'upload.html')
          else:
      
              file_obj = request.FILES.get('head_pic')
              file_name = file_obj.name
      
              path = os.path.join(settings.BASE_DIR,'statics','img',file_name)
              # 拼接路径
              with open(path,'wb') as f:
                  for chunck in file_obj.chunks():
                      f.write(chunck) 
                      # 固定长度读取,默认一次读65536B,也就是64KB,2.5M,是一个生成器
      
              return HttpResponse('ok')
    9. ajax上传文件

    如何获取当前文件对象的数据:$(‘#file‘)[0].files[0]

    技术图片

    后端的读取文件并保存的代码跟form的文件上传一样

    前端的html文件,用到ajax

    ajax上传头像:
    ajax用户名:
    
    
    {% csrf_token %}
    
    
    

    根据以前写ajax代码的习惯,会这样写,但是会报错,因为文件上传要依靠FormData这个工具

    正确写法:

    ajax上传头像:
    ajax用户名:
    
    
    {% csrf_token %}
    
    
    

    注意点:

    • ajax文件上传需要借助FormData,给它填键值对的方式传输数据
    • data直接传formdata,但是后面要加processData:false和contentType:false
    1. JSON 机制
    • JSON 指的是 Javascript 对象表示法(Javascript Object Notation)
    • JSON 是轻量级的文本数据交换格式
    • JSON 独立于语言 *
    • JSON 具有自我描述性,更易理解

    技术图片

    json和python数据类型对比:

    技术图片

    但是,json在转换时间类型的时候,会出现问题:

    import datetime
    import json
    
    d = {'name':'yang','birthday':datetime.datetime.now()}
    json_str = json.dumps(d)
    
    print(json_str)
    
    # 报错,TypeError: Object of type 'datetime' is not JSON serializable,意思是'datetime'类型的是不能序列化的

    json序列化时间日期类型的数据的方法

    from datetime import date,datetime
    import json
    
    #对含有日期格式数据的json数据进行转换
    class JsonCustomEncoder(json.JSONEncoder):
        # 序列化的功能就是json.JSONEncoder这个类做的,因为它不能序列化时间,所以继承他的情况下进行拓展
        def default(self, field):
            if isinstance(field,datetime):
                # 如果是datetime类型的,返回一个datetime类型的字符串格式化输出
                return field.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(field,date):
                # 如果是date类型的,返回一个date类型的字符串格式化输出
                return field.strftime('%Y-%m-%d')
            else:
                # 如果不是date、datetime类型的,就用父类的方法
                return json.JSONEncoder.default(self,field)
    
    
    d1 = datetime.now()
    json_str = json.dumps(d1,cls=JsonCustomEncoder)
    print(json_str)  # "2019-07-29 21:08:25"

    十、Django的文件上传


    推荐阅读
    • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
    • 如何在WPS Office for Mac中调整Word文档的文字排列方向
      本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
    • 深入理解OAuth认证机制
      本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
    • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
      本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
    • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
    • 几何画板展示电场线与等势面的交互关系
      几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
    • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
    • MySQL中枚举类型的所有可能值获取方法
      本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
    • 本文介绍如何在应用程序中使用文本输入框创建密码输入框,并通过设置掩码来隐藏用户输入的内容。我们将详细解释代码实现,并提供专业的补充说明。 ... [详细]
    • 本文介绍如何通过SQL查询从JDE(JD Edwards)系统中提取所有字典数据,涵盖关键表的关联和字段选择。具体包括F0004和F0005系列表的数据提取方法。 ... [详细]
    • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
    • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
    • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
    • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
    • MATLAB实现n条线段交点计算
      本文介绍了一种通过逐对比较线段来求解交点的简单算法。此外,还提到了一种基于排序的方法,但该方法较为复杂,尚未完全理解。文中详细描述了如何根据线段端点求交点,并判断交点是否在线段上。 ... [详细]
    author-avatar
    广东庚舞飞扬
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有