couldn't import Django Django学习踩坑笔记

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

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

    couldn't import Django Django学习踩坑笔记

    文章插图

    这里的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.pyINSTALLED_APPS = [...'corsheaders', # demo'rest_framework',]MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', # 需注意与其他中间件顺序 , 这里放在最前面即可...]# 支持跨域配置开始CORS_ORIGIN_ALLOW_ALL = TrueCORS_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';//基础urlaxios.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格式
couldn't import Django Django学习踩坑笔记

文章插图

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

couldn't import Django Django学习踩坑笔记

文章插图
2、raw格式content-type为raw格式 , 则需要先将request.body中内容先进行解码为获取字段得值 。
postbody = request.bodyjson_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:
四、自定义上传图片【couldn't import Django Django学习踩坑笔记】通常数据库中可以通过两种方式定位解析到上传到后台图片:
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="https://tazarkount.com/read/上传"><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)withopen(save_path, 'wb') as f :# 获取上传文件的内容并写到创建文件中# pic.chunks():分块的返回文件for content in pic.chunks():f.write(content)只写了大概的处理 , 路由映射还需要自己配昂 。