返回顶部

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)

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

posted on 2021-11-05 11:04  weilanhanf  阅读(267)  评论(0编辑  收藏  举报

导航