• Django学习踩坑笔记


    主要记录自己的使用Django过程中的一些踩坑,具体分类请看右侧目录

    一、使用Pycharm调试Django项目

    • 1、在当前项目下打开Run->Edit Configurations
    • 2、点击+,选择新增python 脚本,如图,填好name,script,script parameter

      这里的Parameter为runserver,也就是manange.py运行的时候需要追加的参数,完整命令为
      python manage.py runserver (127.0.0.1:8000 可选)
      所以对于一些执行时候需要使用parser解析命令的脚本同样可以使用相同的方式配置调试。
    • 3、在项目需要的调试代码行打上断点,当有请求到达的时候就会开启调试,一般为路由中。

    二、CORS跨域配置

    1、跨域问题简介

    跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,协议,域名,端口都要相同,其中有一个不同都会产生跨域;
    跨域主要有应用在前后端分离的时候,比如Vue+Django。Vue本身由于node的支持,在本地运行的时候会占用localhost:8080,Django后端有自己的服务器占用localhost:8000。前端后端想要联调,就会有跨域问题产生。可以使用CORS(Cross-Origin Resource Sharing),跨域资源共享解决。
    大概原理:当使用XMLHttpRequest发送请求时,如果浏览器发现违反了同源策略就会自动加上一个请求头 origin;后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin;浏览器判断响应中的 Access-Control-Allow-Origin 值是否和当前的地址相同,匹配成功后才继续响应处理,否则报错。
    CORS解释

    2、前后联调的配置

    Django需要项目环境下安装对应模块

    pip install django-cors-headers
    

    项目setting.py配置文件添加配置

    # settings.py
    INSTALLED_APPS = [
        ...
        'corsheaders', # demo
        'rest_framework',
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware', # 需注意与其他中间件顺序,这里放在最前面即可
        ...
    ]
    
    # 支持跨域配置开始
    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_CREDENTIALS = True
    
    • INSTALLED_APPS中要注意添加的模块'corsheaders', 后面不要少逗号,否则项目初始化加载settings.py的时候会做字符串拼接为corsheaderrest_frame因找不到模块从而报错。
    • MIDDLEWARE中添加的中间件corsheaders.middleware.CorsMiddleware要放到第一个位置,因为在请求经过中间件的时候,是按照MIDDLEWARE中的顺序,如果不符合某一个中间件定义则直接终止。

    前端Vue需要安装axios模块

    cnpm install axios
    

    然后Vue需要对请求做统一管理,可以再vue项目下/src/创建一个/api/api.js,请求头和请求路径配置,比如超时时间,Content-Type响应头,封装get或者post方法等。

    //前端同学写的
    import axios from 'axios';
    axios.defaults.timeout = 5000;  //超市时间是5秒
    axios.defaults.withCredentials = true;  //允许跨域
    //Content-Type 响应头
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
    //基础url
    axios.defaults.baseURL = "http://localhost:8000";
    /**
     * 封装get方法
     */
     export function get(url,params={}){
        return new Promise((resolve,reject) => {
            axios.get(url,{params:params})
            .then(response =>{
                resolve(response.data);
            })
            .catch(err =>{
                reject(err);
            })
        });
    }
    
    

    具体Vue与Django前后端联调参考demo:传送门

    三、Django中request针对不同Content-Type的解析

    后端使用一般要拿到http封装的request做路由处理,但是不同的request的body内容格式也不同,要个请求header中定义的Content-Type进行解析。路由函数中可以根据requet.META获取到http请求的请求头。
    请求头中的内容长度与内容类型:

    • CONTENT_LENGTH – The length of the request body (as a string).
    • CONTENT_TYPE – The MIME type of the request body.

    Content-Type两种重要的格式:

    • x-www-form-urlencoded:表单内的数据转化内键值对,也只能上传键值对,并且键值对都是间隔分开的。
    • raw:可以上传任意格式的文本,可以上传text、json、xml、html等,其实主要的还是传递json格式的数据,当后端要求json数据格式的时候,就要使用此种格式来测试。

    1、x-www-form-urlencoded格式


    当content-type为x-www-form-urlencoded的时候,直接使用request.POST.get('username')的方式可以获取对应字段的值

    2、raw格式

    content-type为raw格式,则需要先将request.body中内容先进行解码为获取字段得值。

    postbody = request.body
    json_param = json.loads(postbody.decode())
    username = json_param.get('username','')
    password = json_param.get('password','')
    

    :如果使用JsonResponse返回Json数据给前端的时候,可以先定义一个context字典保存参数和值,JsonResponse会将context字典通过json.dumps(data)编码为Json格式数据。但是但是,在Python中写字典时有习惯这种格式如下

    context = {
        "key1": "value1",
        "key2": "value2",
        ...
        "key n": "value n",
    }
    

    考虑到易读性(或者是linux下操作单行查看???)的问题,通常习惯最后一行字典键值对"key n": "value n",会习惯带一个,或者键值对以单引号格式书写'key n': 'value n',,这两种写法都不符合json文件格式。会爆如下错误
    json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes:

    四、自定义上传图片

    通常数据库中可以通过两种方式定位解析到上传到后台图片:
    1、数据库保存图片存储路径
    2、数据库存储图像的实际编码
    Django也可以定义上传MEDIA_ROOT路径之后,通过自定义模型类,保存上传图片的路径,图片保存在MEDIA_ROOT之下。

    以下是自定义上传文件,而不是使用模型类。

    配置:
    全局settings.py配置,添加上传图片的保存路径:
    MEDIA_ROOT = os.path.join(BASE_DIR,"static/media")

    前端:
    前端写一个任意的表单,但是需要注意的是,上传文件时必须是post上传,编码方式:enctype必须是:multipart/form-data这个类型。

    <form method="post" enctype="multipart/form-data" action="/uploal_action/" >
        <input type="file" name="pic"><br/>
        <input type="submit" value="上传"><br/>
    </form>
    

    后台可以获取:
    pic = request.FILES['pic']:上传文件类的对象,
    pic.name:获取文件的名字,
    pic.chunks():每次返回这个文件的一块内容。

    后端路由:
    先获取文件对象,然后写入。另外:这最好使用os.makedirs,如果保存文件所在路径中,有的父目录不存在,会提前创建。

    def upload_file(request):
        """保存上传文件"""
        # 1.获取上传的文件
        pic = request.FILES['pic']
        # 2.创建文件
        save_path = '%s/test/%s'%(MEDIA_ROOT,pic.name)
        os.makedirs(os.path.dirname(save_path), exist_ok=True)
        with  open(save_path, 'wb') as f :
            # 获取上传文件的内容并写到创建文件中
            # pic.chunks():分块的返回文件
            for content in pic.chunks():
                f.write(content)
    

    只写了大概的处理,路由映射还需要自己配昂。

  • 相关阅读:
    Linux中./configure、make、make install详解
    VMware虚拟CentOS 6.5在NAT模式下配置静态IP地址及Xshell远程控制配置
    VMWare中Linux虚拟机设置静态IP上网的设置方法
    Linux下SSH远程连接断开后让程序继续运行解决办法
    弱网测试(一)
    算法的测试
    前端图片加载优化
    jpg/jpeg/png格式的区别与应用场景
    测试分类标准
    Mysql 日期与时间戳的相互转化
  • 原文地址:https://www.cnblogs.com/welan/p/15512231.html
Copyright © 2020-2023  润新知