经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Django » 查看文章
【django-vue】封装logger 封装全局异常 封装response 数据库配置 用户表继承AbstractUser配置
来源:cnblogs  作者:passion2021  时间:2023/2/28 8:51:54  对本文有异议

上节回顾

这是一个django-Vue前后端分离的项目(视频网站)

  1. # 1 企业软件类型
  2. -商城类
  3. -公司内部:
  4. -业务
  5. -RBAC权限管理
  6. # 2 软件开发流程
  7. -你的工作流程
  8. # 3 pip换源 :国内镜像
  9. -命令行中
  10. -pycharm
  11. # 4 虚拟环境:
  12. -每个项目有自己的环境
  13. -虚拟环境:virtualenv
  14. -环境变量:maclinux+win
  15. -梳理一下你电脑的环境:python2python3.6python3.10 anaconda
  16. pip3 install 装在哪个解释器
  17. (luffy)
  18. -
  19. -javaMaven
  20. -gogo mod 模式 11.1加入
  21. -vuenode_models
  22. # 5 项目目录调整
  23. -1 项目启动是加载配置文件,再运行
  24. -配置文件路径一定要对
  25. -python manage.py runserver
  26. python xx.py lqz 19
  27. -配置文件有错,项目起不来
  28. -2 项目上线阶段,使用wsgi.py 运行
  29. -3 把所有app都放在apps文件夹下,后期再配置文件中注册还是只用app的名字注册
  30. -pyhton包导入的原理
  31. -import 去环境变量中找 sys.path
  32. -为什么导入系统提供的包,可以直接导入
  33. -为什么装的第三方包,可以直接导入
  34. -pycharm中,项目根路径会被加入环境变量,如果是命令行中不会
  35. -把apps路径加入环境变量,以后可以基于apps这个文件夹开始导起
  36. -把小luffy_api 加入环境变量
  37. sys.path.append(str(BASE_DIR))

python运行流程

image-20230222201311877

我们写的python脚本是怎么运行的?
首先Py文件肯定运行在操作系统之上,假设我们在操作系统上装了python3.6的解释器。python3.6实际上就是一个python.exe可执行文件。

python.exe运行在操作系统之上,会生成一个进程,这叫python进程。然后py文件就运行在这个进程里面,并且解释器需要一行一行的读,你写的python代码。读完了之后,解释器还要运行这些代码。所以一个py文件运行的进程也可以说是一个python解释器的进程。

多进程和多线程:
使用python多开一个进程,实际上就是在启动一个python解释器。
多线程是一个进程下可以有多个线程。

如果想要把我们写的代码,编译成一个可执行文件比如xx.exe,这样不需要解释器也可以在操作系统上直接运行。可以使用pyintaller库(实际上是将解释器环境和你写的代码进行打包),但是这个编译后的文件只能在win上使用,不能跨平台。go可以实现跨平台编译。

项目目录调整(重要)

查看manage.py:

image-20230222204357363

项目一启动就会去导入配置文件,此时如果你在配置文件中如果导入了项目相关的模块就会报错。原因是,项目都还没起来,就去导入项目里的东西。所以不要在setting文件中随便导入模块。

image-20230222202720789

在命令行里输入参数:

  1. # sys.argv
  2. python xx.py 参数 参数...
  3. 可以通过sys.argv获取这些参数
  4. # 示例:
  5. python test.py passion 123
  6. sys.argv终端输出:
  7. ['tests.py', 'passion', '123']

查看execute_from_command_line函数:

image-20230222203955594

查看execute类:

image-20230222204052952

项目上线时,还需要修改wsgi.py文件中的配置文件设置:

image-20230222204720651

注意:开发环境,不能使用正式上线的数据库。开发环境--> 测试环境 --> 上线环境(微盟删库事件)

关于环境变量的问题

  1. # 1 相对导入和绝对导入
  2. -相对导入必须从环境变量下开始导 sys.path
  3. -如果报包找不到的错,确认环境变量
  4. -绝对导入,以当前文件为基准导入
  5. -它不能以脚本形式运行,只能当包用
  6. # 2 导入包,pycharm提示错误,不一定真的有错,只要再环境变量中,就没有问题
  7. -想让pycharm不报错,把你加入到环境变量的路径,设为source root

新建一个python包:

image-20230222195237929

在main.py文件导入s1文件:

image-20230222195403604

在s2.py文件导入s1:

image-20230222195529896

如何使用相对导入,s2导入s1?

image-20230222195559645

使用相对导入的文件,该文件就不能以脚本形式运行了:

image-20230222195651664

会直接报错:

image-20230222195912367

在main.py中导入s2(可以将s2以导入的形式运行):

image-20230222195936494

总结:在包内部,建议使用相对导入。正常情况下,他人安装了你的包,会自动将你的包的路径导入环境变量。此时使用绝对导入不会报错。但是如果它复制你的源码直接执行,这种情况使用绝对导入会报错,而使用相对导入不会报错。

给sys.path添加环境变量:(pycharm报错,程序不一定报错)

image-20230222210242032

设置source root:

image-20230222210310286

今日内容

1 django后端配置之封装logger

  1. # 项目肯定要记录日志
  2. -日志都可以打印到控制台
  3. -日志可以写到日志文件这
  4. -日志存到某个库中
  5. -所有项目日志统一管理
  6. # sentry
  7. 使用django写的日志服务软件,收集日志,可以展示日志,兼容很多语言,是开源的。
  8. # 以后在项目中不要出现print了,以后都用日志logger.info(),以后项目上线,只需要调整日志级别,低级别的日志就不打印了,于是日志输出不用删掉
  9. # 每个项目,都需要记录日志
  10. -后期可以通过日志排查问题,分析错误
  11. -分析用户行为...
  12. # 之前学过logging模块,django就是基于原生的logging模块。
  13. -django中集成日志步骤,django使用的就是python内置的日志模块。
  14. -所以django寻找配置文件也是查找LOGGING这个名字。
  15. # 操作步骤:
  16. -第一步:在配置文件中加入 日志配置 ---大字典
  17. -详情见下面的配置文件
  18. -第二步:在utils中新建common_logger.py ,得到日志对象
  19. import logging
  20. # 通过配置问中的名字拿到logger对象,以后只需要导入,直接使用对象写日志即可
  21. logger=logging.getLogger('django')
  22. -第三步:在想用的地方,导入使用即可(注意路径)
  23. from utils.common_logger import logger
  24. logger.info('info级别的日志')
  25. logger.error('error级别的日志')

dev.py:

  1. # 真实项目上线后,日志文件打印级别不能过低,因为一次日志记录就是一次文件io操作
  2. LOGGING = {
  3. 'version': 1,
  4. 'disable_existing_loggers': False,
  5. 'formatters': {
  6. 'verbose': {
  7. 'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
  8. },
  9. 'simple': {
  10. 'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
  11. },
  12. },
  13. 'filters': {
  14. 'require_debug_true': {
  15. '()': 'django.utils.log.RequireDebugTrue',
  16. },
  17. },
  18. 'handlers': {
  19. 'console': {
  20. # 实际开发建议使用WARNING
  21. 'level': 'DEBUG',
  22. 'filters': ['require_debug_true'],
  23. 'class': 'logging.StreamHandler',
  24. 'formatter': 'simple'
  25. },
  26. 'file': {
  27. # 实际开发建议使用ERROR
  28. 'level': 'INFO',
  29. 'class': 'logging.handlers.RotatingFileHandler',
  30. # 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
  31. 'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
  32. # 日志文件的最大值,这里我们设置300M
  33. 'maxBytes': 300 * 1024 * 1024,
  34. # 日志文件的数量,设置最大日志数量为10
  35. 'backupCount': 10,
  36. # 日志格式:详细格式
  37. 'formatter': 'verbose',
  38. # 文件内容编码
  39. 'encoding': 'utf-8'
  40. },
  41. },
  42. # 日志对象
  43. 'loggers': {
  44. 'django': {
  45. 'handlers': ['console', 'file'],
  46. 'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
  47. },
  48. }
  49. }

utils/logging.py:

  1. import logging
  2. logger = logging.getLogger('django')

使用:

image-20230227093024964

注意:也可以在utils包的__init__.py进行注册,以后就直接导入util包即可。

2 后端配置之封装全局异常

  1. # 前端 要接收的格式,要统一,无论后端是否出错
  2. # 三大认证:
  3. 视图类的方法中只要出了异常,就会执行一个函数,但是这个函数只能处理drf的异常, 所以我们需要自己写个函数,既能处理drf异常,又能处理django异常,这样统一返回格式,前端看到格式都统一了
  4. # drf异常源码分析
  5. 查看APIViewdispatch方法 ---> 三大认证中抛出异常会被捕获--->异常捕获后会执行self.handle_exception(exc) ---> 省略一波源码的跳来跳去 ---> 发现会去执行views.py下的handle_exception函数,这个函数只会处理drf的异常 ---> 并且执行这个函数是在drf配置文件进行了默认配置 ---> 修改这个配置将其替换成我们的异常捕获函数
  6. # 写一个函数,封装全局异常
  7. -1 统一返回格式
  8. -2 记录日志:出了异常,程序有问题,后期排查问题
  9. # 使用步骤
  10. -第一步:在utils中新建 common_exceptions.py
  11. -第二步:写个函数
  12. -看项目代码
  13. -第三步:配置配置文件,以后只要出了异常,都会走咱们的函数
  14. REST_FRAMEWORK = {
  15. 'EXCEPTION_HANDLER': 'utils.common_exceptions.exception_handler',
  16. }
  17. -第四步:勇敢大胆写代码,即便报错,程序不会蹦,并且会记录日志,并且处理成统一格式

自定义全局异常代码:

  1. 1. exceptions.py
  2. from rest_framework.views import exception_handler as drf_exception_handler
  3. from rest_framework.response import Response
  4. from utils.common_logger import logger
  5. def exception_handler(exc, context):
  6. # 程序出了异常,会走到这,我们都要记录日志
  7. # 请求地址,请求方式,请求时间,请求哪个视图函数,如果登录了,记录一下用户id
  8. request = context.get('request')
  9. try:
  10. user_id = request.user.pk
  11. if not user_id:
  12. user_id = '匿名用户'
  13. except:
  14. user_id = '匿名用户'
  15. view = context.get('view')
  16. logger.error('用户:【%s】,使用:【%s】 请求,请求:【%s】 地址,视图函数是:【%s】,出错了,错误是:【%s】' % (
  17. user_id, request.method, request.get_full_path(), str(view), str(exc)
  18. ))
  19. # 第一步:执行一下原来的异常处理:它只处理drf的异常,django的异常没有处理
  20. # res如果有值是Response的对象,说明是drf的异常
  21. # res如果是None,说明是django的异常
  22. res = drf_exception_handler(exc, context)
  23. # 在这里,可以通过状态码,把异常分的更细一些:比如有数据的异常,除以0的异常,列表越界异常。。。。
  24. if res:
  25. # drf异常
  26. # res=Response(data={'code':999,'msg':'服务器出错,请联系系统管理员'})
  27. res = Response(data={'code': 999, 'msg': res.data.get('detail', '服务器出错,请联系系统管理员')})
  28. else:
  29. # django的异常,状态码是888,错误信息是 exc异常对象转成字符串
  30. res = Response(data={'code': 888, 'msg': str(exc)})
  31. return res
  32. 2. 在配置文件中配置
  33. REST_FRAMEWORK = {
  34. # 以后,只要出异常,就会执行exception_handler
  35. 'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler',
  36. }

补充说明

断点调试说明:

image-20220705111458073

context相关源码:

image-20230227101444082

request.get_full_path() 和request.path区别:

  1. # request.get_full_path() 和request.path区别
  2. 1.两者都是获取request请求的url路径
  3. 2.request.get_full_path() ==> 获取当前url,(包含参数)
  4.   比如发送一个请求的路径为127.0.0.1:8080/class_list/?name = 10
  5.   request.get_full_path返回的是=>/class_list/?name=10
  6.   request.path获取的是不带参数的路径=>/class_list/
  7. 3.如果遇到url中含有中文的想要正常接收返回值需要对返回值就行解码(url默认的编码格式为unicode)
  8.   request.get_full_path.encode('utf8')
  9.   request.path.encode('utf8')

如果是匿名用户,request.pk = None

image-20230227102256934

3 后端配置之二次封装response

  1. # drf提供的Response对象,不能很方便的加入code和msg字段,自己封装一个Response类,以后都用我们自己封装的,方便咱们写code和msg
  2. -{code:100,msg:提示,data:{}/[]}
  3. -{code:100,msg:提示,token:asdfasd,user:lqz}
  4. # 使用步骤
  5. 第一步:在utils下新建common_response.py
  6. 第二步:封装APIRespon
  7. 第三步:导入使用,视图函数的方法,返回时,都使用咱们自己的
  8. # 封装步骤:
  9. 1 utils/response.py
  10. from rest_framework.response import Response
  11. class APIResponse(Response):
  12. def __init__(self, code=100, msg='成功', status=None, headers=None, **kwargs):
  13. data = {'code': code, 'msg': msg}
  14. if kwargs:
  15. data.update(kwargs)
  16. super().__init__(data=data, status=status, headers=headers)
  17. 2 以后再视图类中,导入使用即可
  18. return APIResponse(token='asfdasfd') # 登录成功
  19. return APIResponse(token='asfdasfd',status=201,code=101) # 修改http响应状态码
  20. return APIResponse(code=1001,msg='请联系管理员') # 修改自己的状态码
  21. return APIResponse(headers={"Access-Control-Allow-Origin":"*"}) # 响应头添加东西
  22. return APIResponse(result=serializer.data) # 获取全部
  23. return APIResponse(result=[{id:1,'name':'金梅'},{id:2,'name':'西游记'}])

查看drf Response源码:

image-20230222215704059

重写Response类的__init__方法。

注意:我们需要保留原来的Response的功能,并且做一些扩展。

举个例子:

  1. # 希望实现如下两个效果
  2. # 后端返回格式
  3. return APIResponse(token='sadasdsaddsa')
  4. # 前端接受
  5. {code:100, msg:'成功', token'sadasdsaddsa'}
  6. # 后端返回格式
  7. return APIResponse(result=[{id:1,'name':'金梅'},{id:2,'name':'西游记'}])
  8. # 前端接受
  9. {code:100, msg:'成功', token'sadasdsaddsa', result:[{id:1,'name':'金梅'},{id:2,'name':'西游记'}]}

如果不传入code、msg等参数,则默认code=100msg='成功',这里父类还有可以传很多参数,我们这里只用一部分。image-20230222220747342

字典的updata方法:

image-20230222221004132

基于原字典进行更新。

image-20230222221050359

如果原字典没有就添加,如果有对应的键就更新。

调用父类的__init__:

image-20230222221355020

对于登录接口:

image-20230222222826229

对于获取所有接口:

image-20230222222859142

查看前端:

image-20230222222911630

4 数据库配置

  1. # luffy项目使用mysql5.7
  2. 安装参考:https://www.jb51.net/article/212626.htm
  3. # 之前使用root用户作为项目的数据库用户,权限太高了,通过root用户登录之后,可以修改所有的数据库。一般公司里,给项目单独建立一个用户,这个用户只对当前库(当前项目使用的库)有权限。
  4. 需求:
  5. 1.创建一个名为luffymysql数据库。
  6. 2.创建一个名为luffy_api的用户,该用户只能查看luffy库。
  7. # 一、在mysql中创建一个用户luffy_api,给用户授予luffy库的所有权限
  8. -1 远程链接mysql,创建一个luffy
  9. -命令行创建
  10. 1.管理员连接数据库
  11. >: mysql -uroot -proot
  12. 2.创建数据库
  13. >: create database luffy default charset=utf8;
  14. -navicate客户端创建
  15. -2 在创建之前,可以先查看有哪些用户
  16. select user,host,password from mysql.user;
  17. 现在公司主流使用5.7版本之后的mysqlmysql5.8mysql 8, msyql5.7称之为msyql 7,可以用如下命令,查看用户:
  18. select user,host,authentication_string from mysql.user;
  19. -3 创建一个luffy_api用户(之前有个root用户,权限很高)
  20. # 授权账号命令模板:
  21. grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'
  22. # 把luffy库下所有表的权限(grant all privileges)都授予luffy_api这个用户,允许远程链接
  23. grant all privileges on luffy.* to 'luffy_api'@'%' identified by 'Luffy123?';
  24. '''
  25. 注意:在mysql的不同版本上,如果只授予了用户远程连接的权限,没有授予本地连接,那么可能会出现执行本地连接时连接不上,只能远程连接的情况。所以可以使用以下命令
  26. '''
  27. # 把luffy库下所有表的权限都授予luffy_api这个用户,允许本地链接,且将本地连接密码设置的和远程连接的相同。(也可以设置密码不相同)
  28. grant all privileges on luffy.* to 'luffy_api'@'localhost' identified by 'Luffy123?';
  29. '''
  30. 建立了本地连接,又建立远程连接,mysql中会有两条记录(有两个luffy用户)
  31. '''
  32. -4 刷新一下权限
  33. -flush privileges;
  34. 说明:往数据表插入一条记录(硬盘)---》 内存中没有这个权限 ---》 flush privileges ---> 将硬盘中的权限读到内存
  35. -5 luffy_api用户登录,show databases查看,只能看到luffy
  36. -至此已经完成用户创建
  37. '''
  38. 只能操作luffy数据库的账户
  39. 账号:luffy_api
  40. 密码:Luffy123?
  41. '''
  42. # 二、在项目中配置好使用mysql数据
  43. 1 在配置中:
  44. import os
  45. user = os.environ.get('USER','luffy_api')
  46. password = os.environ.get('PASSWORD','Luffy123?')
  47. DATABASES = {
  48. 'default': {
  49. 'ENGINE': 'django.db.backends.mysql',
  50. 'NAME': 'luffy',
  51. 'USER': user,
  52. 'PASSWORD': password,
  53. 'HOST': '127.0.0.1',
  54. 'PORT': 3306
  55. }
  56. }
  57. 2 运行项目会报错:
  58. django默认使用mysqlDB操作mysqlmysqlDB这个模块,在python2可以的,在python3中不支持,于是咱们使用pymysql替换,到了django2.0.7以后,如果使用pymysql替换,需要改django的源代码,后期使用mysqlclient,替换pymysqlmysqlclientmysqlDBpython3.x版本
  59. - 如果使用pymysql,需要改源码,需要执行
  60. import pymysql
  61. pymysql.install_as_MySQLdb() # 猴子补丁的体现,这行代码把django里面所有mysqlDB的对象,都替换成pymysql
  62. - pymysql的使用演示:
  63. conn
  64. cursor.execute('select * from user')
  65. -猴子补丁是:在
  66. 程序运行过程中得动态替换技术(代码虽然没有改,但已经不是原来的代码了):https://www.liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/24-%E5%8D%8F%E7%A8%8B%E4%B9%8Bgevent%E6%A8%A1%E5%9D%97/
  67. gevent模块:
  68. 使用这个模块时,执行了monkey.patch_all()。
  69. 执行这个的作用是,因为网络请求、time.sleep这些都是同步IO,程序会等到请求得到响应返回数据才会继续执行。
  70. 只要执行了monkey patch再使用time\socket这些模块,使用的都是gevent给你提供的timesocket模块,相当于对这些模块全局做了一个替换。
  71. 你好像写的是同步代码,但实际上这些操作都变成异步了。
  72. 原本time会导致阻塞,会使CPU离开这个线程,现在使用猴子补丁,替换了原来的time模块,虽然代码还是不变,但time不会阻塞了。
  73. 阻塞time-替换--> 非阻塞time
  74. 动态语言就会具备这种功能 ---> 动态替换
  75. -以后再django中不使用pymysql了,使用mysqlclient,不需要再执行任何补丁了
  76. -winlinuxmac,这个mysqlclient模块不太好装,看人品,有时候很顺利,有时候上线装不上
  77. 3 只需要装 mysqlclient,一切都解决了
  78. # 三、目前咱们配置文件中,直接写死了mysql的用户名和密码
  79. -可能存在的风险---》如果我的源代码泄露了---》数据库用户名密码就泄露---》黑客可以远程登录---》脱库(偷库)
  80. -Bgo语言源代码泄露 营造出充会员的假象 抖音库存带货
  81. -B站开源的一套Go微服务框架 ---> go-kratos
  82. -推荐阅读:https://www.cnblogs.com/liuqingzheng/p/16271927.html
  83. -华住汉庭的酒店入住信息(开房记录)泄露,源代码泄露了,导致被脱库
  84. -上海随申办的数据泄露 ---> 使用阿里云的es服务器 ---> 阿里云服务器泄露
  85. # 补充:
  86. mysqlutf8编码和utf8mb4的区别?
  87. -utf8:一个字符,占两个字节(byte--->1byte8个比特位 10101010
  88. -utf8mb4:一个字符,占4个字节,表情符号
  89. -咱们学的utf-8:可变长可以1---4字节表示一个字符
  90. # 研究一下 以下两种登录方式的区别?第一个快
  91. mysql -uroot -p
  92. mysql -h 192.168.1.11 -P 3306 -uroot -p

mysql5.7数据库(推荐使用偶数版本):

image-20230227150205292

数据库会在哪里?
注意:mysql分为客户端和服务端。客户端可以远程链接服务端。

image-20230223223331312

mysql的utf8和utf8mb4的区别

  1. # utf8:
  2. 一个字符,占两个字节(byte--->1byte8个比特位 10101010),有些生僻字存不了
  3. # utf8mb4:
  4. 一个字符,占4个字节,可以存储表情符号(占四个字节)、生僻字
  5. # utf-8编码 和 mysql的utf8 不是一个东西:
  6. 咱们学的utf-8是可变长的,14字节表示一个字符,而mysqlutf8是固定占两个字节。
  7. # 说明
  8. 增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。
  9. 理论上讲, UTF-8 格式使用一至六个字节,最大能编码 31 位字符。最新的 UTF-8 规范只使用一到四个字节,最大能编码21位,正好能够表示所有的 17 Unicode 平面。

创建数据库是选择utf8mb4或utf8(推荐utf8mb4):

image-20230223223637044

mysql本地连接和远程连接的区别

mysql使用命令查看用户:

image-20230224210022037

可以发现有两个luffy用户。%的意思是允许所有地址访问。正常情况下应该只允许一个地址访问这个数据库。

这是因为:一个是通过本地连接,一个是远程连接。

image-20221104113811509

这二者是有区别的:
本地连接的密码和远程连接的密码是可以不一样的。可以有两个密码,对应两个luffy用户。

mysql本地连接和远程连接的区别?

  1. # 本地连接
  2. mysql -uroot -p
  3. # 远程连接
  4. mysql -h 192.168.1.11 -P 3306 -uroot -p
  5. # 本地连接比远程连接快,为什么?
  6. 远程连接需要通过网卡出去再回来,本地连接是通过socket文件直接去连接mysql的。

推荐阅读:

  1. # localhost与127.0.0.1访问区别
  2. localhot(local)是不经网卡传输,它不受网络防火墙和网卡相关的的限制。 127.0.0.1是通过网卡传输,依赖网卡,并受到网络防火墙和网卡相关的限制。一般设置程序时本地服务用localhost是最好的,localhost不会解析成ip,也不会占用网卡、网络资源。 有时候用localhost可以,但用127.0.0.1就不可以的情况就是在于此。猜想localhost访问时,系统带的本机当前用户的权限去访问,而用ip的时候,等于本机是通过网络再去访问本机,可能涉及到网络用户的权限。
  3. 转载自:https://blog.csdn.net/snow__wei/article/details/103277665

允许luffy_api用户进行本地连接和远程连接之后:

会出现两条记录:

image-20230224221224818

生产环境和测试环境,数据库连接肯定不是一个地址,该怎么处理的?

  1. 使用两套配置文件

  2. 在配置文件中数据库配置部分添加try...except代码,如果一个地址连接不上,再去连接另外一个。(有点low)

django-mysqlDB历史

  1. # 项目操作mysql,需要安装模块
  2. -pymysql
  3. -mysqlDB
  4. -mysqlclient
  5. -历史:原来py2上有个操作mysql的模块叫mysqlDB,但到py3,没有支持py3django默认使用这个模块去连接mysql,默认使用-mysqlDB连接,-mysqlDB不支持py3,运行报错
  6. -我们使用pymysql,作为连接mysql的数据库模块,但是需要加代码
  7. imprort pymysql
  8. pymysql.install_as_mysqldb() # 猴子补丁
  9. -django 2.2.2以后,还使用pymysql,需要改djagno源代码
  10. -统一使用mysqlclient来作为操作mysql的底层库
  11. -基于py2mysqldb,在py3上重新了,但是名字改成了mysqlclient
  12. -使用mysqlclient,只需要安装这个模块,不需要再写任何代码,直接用即可
  13. -但是:mysqlclient 这个模块,不好装
  14. -win 一般人品好,人品好,pip install mysqlclient
  15. -人品不好,装不了,centos部署项目,后面会讲centos上如何装
  16. # mysqlclient
  17. pip install mysqlclient

使用pymysql,需要在项目目录下或者app目录下的__init__使用猴子补丁:

image-20230227115542915

猴子补丁

  1. # 猴子补丁
  2. 是在程序运行过程中得动态替换技术(代码虽然没有改,但已经不是原来的代码了):https://www.liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/24-%E5%8D%8F%E7%A8%8B%E4%B9%8Bgevent%E6%A8%A1%E5%9D%97/
  3. # gevent模块:
  4. 使用这个模块时,执行了monkey.patch_all()。
  5. 执行这个的作用是,因为网络请求、time.sleep这些都是同步IO,程序会等到请求得到响应返回数据才会继续执行。
  6. 只要执行了monkey patch再使用time\socket这些模块,使用的都是gevent给你提供的timesocket模块,相当于对这些模块全局做了一个替换。
  7. 你好像写的是同步代码,但实际上这些操作都变成异步了。
  8. 原本time会导致阻塞,会使CPU离开这个线程,现在使用猴子补丁,替换了原来的time模块,虽然代码还是不变,但time不会阻塞了。
  9. 阻塞time-替换--> 非阻塞time
  10. 动态语言就会具备这种功能 ---> 动态替换

数据库密码保护

  1. # 目前咱们配置文件中,直接写死了mysql的用户名和密码
  2. -可能存在的风险---》如果我的源代码泄露了---》数据库用户名密码就泄露---》黑客可以远程登录---》脱库(偷库)
  3. # 用户名密码写死在代码中了,保证安全
  4. name = os.environ.get('LUFFY_NAME', 'luffy')
  5. password = os.environ.get('LUFFY_PASSWORD', 'Luffy123?')
  6. # 拓展:有的公司,直接有个配置中心---》服务--》只用来存放配置文件
  7. DATABASES = {
  8. 'default': {
  9. 'ENGINE': 'django.db.backends.mysql',
  10. 'NAME': 'luffy',
  11. 'USER': name,
  12. 'PASSWORD': password,
  13. 'HOST': '127.0.0.1',
  14. 'PORT': 3306
  15. }
  16. }

还记得我们配的环境变量吗?

image-20230225130335541

注意:在windows下配置环境变量可能不会立即生效,如果是mas\linx 可以使用source命令使环境变量立即生效。

导入os模块,通过os.environ可以获取到这个环境变量:

image-20230225130555415

查看结果,可见获取到了环境变量的变量值:

image-20230225130623536

可以利用这个模块,将数据库账号和密码,配置在电脑的环境变量中。

image-20230225130803879

数据库配置:

image-20230225131409990

这段代码的意思是,如果有PASSWORD这个环境变量,就使用PASSWORD这个变量名对应的变量值,作为密码写在配置文件。如果电脑里没有PASSWORD这个环境变量,就使用Luffy123?作为配置文件的数据库密码。

在电脑环境变量里配置用户名和密码:

image-20230225131515086

这样即使源代码泄露了,也无法从配置文件中获取到数据库密码。也就是真正的密码实际存放在你服务器的环境变量中,只有你的服务器被入侵了,才能获取到这个密码。

注意:如果报错,可能是系统环境变量中还存在PASSWORD这个环境变量,我们可以使用别的名字比如PWD

image-20230225140013180

管理配置文件

  1. # 配置中心
  2. 使用配置中心 --> 配置中心提供服务 --> 只用来存放配置文件 --> 向配置中心请求配置文件
  3. # 发展
  4. 单配置文件try...except --> 两套配置文件dev.py\prop.py --> 配置中心
  5. # ConfigMap
  6. ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
  7. 推荐阅读:https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/

5 用户表继承AbstractUser配置

  1. # 你决定使用auth表扩写,项目一定不要先迁移!!!先建好用户表再迁移
  2. 已经迁移完了,再想用authuser
  3. -删库,删迁移文件所有app
  4. -删django源码中的admin文件夹和auth文件夹的迁移文件
  5. # 使用步骤
  6. -0 用户表使用auth表扩写 需要Pillow模块的支持
  7. - pip install Pillow
  8. -1 创一个用户apppython ../../manage.py startapp user
  9. -2 user appmodels.py中扩写用户表
  10. class UserInfo(AbstractUser):
  11. mobile = models.CharField(max_length=11, unique=True)
  12. # ImageField继承了FileField,需要pillow包的支持,只用于存储图片
  13. icon = models.ImageField(upload_to='icon', default='icon/default.png')
  14. class Meta:
  15. db_table = 'luffy_user' # 指定在msyql数据库中的表名
  16. verbose_name = '用户表' # 在后台管理中显示中文
  17. verbose_name_plural = verbose_name # 在打印该类的对象时,显示用户名、
  18. def __str__(self):
  19. return self.username
  20. -3 配置文件配置,注册app,安装Pillow模块
  21. # 用户表的配置
  22. AUTH_USER_MODEL='user.UserInfo'
  23. -4 两条命令迁移

迁移出错问题

问题一:在继承AbstractUser表之前,已经执行了表迁移:

要将django/admindjango/auth目录下的迁移文件都删除掉,才能解决a迁移问题:

image-20230227123029343

image-20230227123041835

  1. # 遇到的问题,明明luffyapi/luffyapi已经加入到环境变量,程序运行没问题,但是表迁移,就报错,找不到模块
  2. -打印了看一下,确实环境变量有,但是不是个字符串,是个对象
  3. -程序运行,是没问题
  4. -迁移有问题:配置文件中转成字符串,就解决了

问题二:luffyapi/luffyapi已经加入到环境变量,程序运行没问题,但是表迁移,就报错,报错内容为"找不到模块"

确认报错位置:

image-20230227150614462

sys.path添加环境变量时,需要添加字符串:

image-20230227150635293

注意:在项目运行的时候,sys.path里是一个对象,并不会报错。而在命令行中执行命令时sys.path中必须是字符串,所以会报这个错。

6 开放media访问

后缀名影响的是用哪个软件打开,而不会影响文件本身。

  1. # 步骤
  2. 1 在配置文件中配置
  3. MEDIA_URL = '/media/'
  4. MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  5. 2 新建media文件夹,icon文件夹,放一张图片进去
  6. 3 路由中加入:
  7. from django.views.static import serve
  8. from django.conf import settings
  9. path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT}),
  10. # 以后使用djagno的配置文件都用这个
  11. from django.conf import settings
  12. 如果这样用,会先使用我们配置文件的配置,如果没有相关配置,还会去查找django默认的配置

注意这个media文件夹不是在项目的根路径,而是在小luffy目录下创建:

image-20230225145430052

配置如下:

image-20230225145856070

查看path源码:

image-20230225150128631

查看_path:

image-20230225150201366

参数route就是我们的路由后缀,也就是如下部分;

image-20230225150237772

View是视图函数的内存地址,也就是这个serve:

image-20230225150329976

name是路由的别名(反向解析)。

kwargs就是接受的我们传入的字典:

image-20230225150508566

然后这个字典会作为参数传入serve:

image-20230225150704377

会传到serve的第三个形参。

再梳理一下,把serve当成一个FBV。
请求来了之后request会传入serve的第一个参数。
然后我们使用了路由转换器media/<path:path>(示例:media/www.baidu.com/,path匹配到www.baidu.com),所以第二个参数会传入路由转换器匹配到的东西。
第三个形参document_root,需要以一个字典的形式,通过kwargs传入,这个参数用于设定media文件夹的位置。

7 路飞前台项目创建和配置

  1. # 1 创建项目
  2. # 2 删除一些不用的
  3. -App.vue中只保留
  4. <template>
  5. <div id="app">
  6. <router-view/> <!-- 可以是单标签也可以是闭合标签 -->
  7. </div>
  8. </template>
  9. # 3 HomeView.vue
  10. <template>
  11. <div class="home">
  12. <h1>首页</h1>
  13. </div>
  14. </template>
  15. <script>
  16. export default {
  17. name: 'HomeView',
  18. }
  19. </script>
  20. # 4 router/index.js
  21. const routes = [
  22. {
  23. path: '/',
  24. name: 'home',
  25. component: HomeView
  26. },
  27. ]

7.1 安装axios

  1. # 1 安装
  2. cnpm install axios
  3. # 2 配置 main.js中
  4. import axios from 'axios'
  5. Vue.prototype.$axios=axios
  6. # 3 以后再任意组件中使用
  7. this.$axios.get(...)

配置:

image-20230225155138410

还可以在插件、混入这两个地方进行配置。

7.2 elementui

  1. # vue2 使用elementui
  2. -安装:cnpm i element-ui -S
  3. -配置:main.js
  4. import ElementUI from 'element-ui';
  5. import 'element-ui/lib/theme-chalk/index.css';
  6. Vue.use(ElementUI);
  7. -使用:在任意组件中复制粘贴(templatescriptstyle
  8. #vue3 使用 element-plus

7.3 bootstrap,jquery

有需求可以使用。

  1. # 咱的项目没使用,但是引入,以后可以用
  2. # bootstrap有些事件基于jquery ---> 使用bootstrap也需要引入jquery
  3. # 使用步骤:
  4. 1 安装
  5. cnpm install jquery -S
  6. cnpm install bootstrap@3 -S
  7. 2 配置:main.js
  8. import 'bootstrap'
  9. import 'bootstrap/dist/css/bootstrap.min.css'
  10. 3 vue.config.js配置
  11. const webpack = require("webpack");
  12. module.exports = {
  13. configureWebpack: {
  14. plugins: [
  15. new webpack.ProvidePlugin({
  16. $: "jquery",
  17. jQuery: "jquery",
  18. "window.jQuery": "jquery",
  19. "window.$": "jquery",
  20. Popper: ["popper.js", "default"]
  21. })
  22. ]
  23. }
  24. };

配置vue.config.js:

方法一:直接整个覆盖这个文件就行。

方法二:在保留原来代码的基础上,添加上面的配置。

7.4 vue-cookies

  1. # 1 安装
  2. cnpm install vue-cookies -S
  3. # 2 配置:main.js中
  4. import cookies from 'vue-cookies'
  5. Vue.prototype.$cookies=cookies
  6. # 3 使用:任意组件中
  7. this.$cookies.set()

8 django配置文件说明

  1. # pathlib
  2. 这个模块是python3.6以后,处理文件路径的模块,原来是使用os模块。
  3. # 面试题,md5是对称加密还是非对称加密
  4. -对称加密:加密的秘钥和解密的秘钥是同一个
  5. -非对称加密:加密使用公钥加密,解密使用私钥解密,使用公钥是不能解密的
  6. -摘要算法:没有解密这一说
  7. 解答:md5摘要算法 无法解密 ---> 不存在对称加密还是非对称加密

配置文件相关说明:

  1. from pathlib import Path
  2. import os
  3. import sys
  4. # 项目根路径
  5. # 我们就是要让小路飞路径作为项目根路径
  6. BASE_DIR = Path(__file__).resolve().parent.parent # 项目根路径, 小路飞luffy_api路径 D:\pythonProject03\luffy_api\luffy_api
  7. # print(BASE_DIR)
  8. # 把 apps 路径加入到环境变量
  9. sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
  10. # 把BASE_DIR也加入到环境变量,以后直接从小路飞开始导起即可
  11. sys.path.insert(0, str(BASE_DIR))
  12. # print(sys.path)
  13. # 以后从大路飞开始导起,或者小路飞开始导起,或者apps开始导起都可以
  14. # 秘钥,涉及到加密的django中,都会用它
  15. SECRET_KEY = 'django-insecure-!g(8l%fw_#t$pz$x4jdf#e3$b4+c%xzqyq@3zki08vj&i)z4k-'
  16. # 项目是以debug模式运行,还是非debug模式运行
  17. # 项目上线,要改成false
  18. # debug=True 代码可以热更新
  19. # 调试模式下,对开发者更友好:可以列出所有路径.报了错,前端能看到
  20. DEBUG = False
  21. # 它搭配debug=False,它的意思是,允许我的项目部署在哪个ip地址上,* 表示允许部署在所有地址上
  22. ALLOWED_HOSTS = ['*']
  23. # django 是多个app组成的,里面配置app,默认带的app,django内置的app
  24. # django 是一个大而全的框架,有很多内置app:
  25. # admin后台管理,
  26. # auth权限管理,
  27. # contenttypes表中存app也表的关系,
  28. # sessions session表,django的session相关
  29. # messages:消息框架,flask讲闪现,是一样的东西
  30. # staticfiles:静态资源的
  31. INSTALLED_APPS = [
  32. 'django.contrib.admin',
  33. 'django.contrib.auth',
  34. 'django.contrib.contenttypes',
  35. 'django.contrib.sessions',
  36. 'django.contrib.messages',
  37. 'django.contrib.staticfiles',
  38. 'rest_framework',
  39. # 'luffy_api.apps.home', # luffy_api在环境变量,直接从这一层开始导起, 太长了,以后就想 注册 home
  40. # 'luffy_api.apps.user'
  41. 'home',
  42. 'user'
  43. ]
  44. # 中间件
  45. MIDDLEWARE = [
  46. 'django.middleware.security.SecurityMiddleware', # 安全相关中间件
  47. 'django.contrib.sessions.middleware.SessionMiddleware', # session相关中间件
  48. 'django.middleware.common.CommonMiddleware', # 带不带 / 问题
  49. 'django.middleware.csrf.CsrfViewMiddleware', # csrf 认证,生成csrf串
  50. 'django.contrib.auth.middleware.AuthenticationMiddleware', # 用户认证
  51. 'django.contrib.messages.middleware.MessageMiddleware', #消息框架相关
  52. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  53. ]
  54. # 根路由
  55. ROOT_URLCONF = 'luffy_api.urls'
  56. # 模板文件
  57. TEMPLATES = [
  58. {
  59. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  60. 'DIRS': [BASE_DIR / 'templates'], # 坑,模板路径用列表,可以有多个
  61. 'APP_DIRS': True,
  62. 'OPTIONS': {
  63. 'context_processors': [
  64. 'django.template.context_processors.debug',
  65. 'django.template.context_processors.request',
  66. 'django.contrib.auth.context_processors.auth',
  67. 'django.contrib.messages.context_processors.messages',
  68. ],
  69. },
  70. },
  71. ]
  72. # 项目运行的配置---》项目上线运行,使用uwsgi 运行 application()
  73. WSGI_APPLICATION = 'luffy_api.wsgi.application'
  74. # 用户名密码写死在代码中了,保证安全
  75. name = os.environ.get('LUFFY_NAME', 'luffy')
  76. password = os.environ.get('LUFFY_PASSWORD', 'Luffy123?')
  77. # 拓展:有的公司,直接有个配置中心---》服务--》只用来存放配置文件
  78. # 数据库配置,mysql 主从搭建完,读写分离
  79. DATABASES = {
  80. 'default': {
  81. 'ENGINE': 'django.db.backends.mysql',
  82. 'NAME': 'luffy',
  83. 'USER': name,
  84. 'PASSWORD': password,
  85. 'HOST': '127.0.0.1',
  86. 'PORT': 3306
  87. },
  88. }
  89. #忽略掉
  90. AUTH_PASSWORD_VALIDATORS = [
  91. {
  92. 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
  93. },
  94. {
  95. 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
  96. },
  97. {
  98. 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
  99. },
  100. {
  101. 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
  102. },
  103. ]
  104. # 国际化
  105. LANGUAGE_CODE = 'zh-hans'
  106. TIME_ZONE = 'Asia/Shanghai'
  107. USE_I18N = True
  108. USE_L10N = True
  109. USE_TZ = False
  110. # 静态资源
  111. STATIC_URL = '/static/'
  112. #
  113. DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

pathlib说明 :

image-20230227151303780

DEBUG说明:开发时打开,上线时关闭。

上线时配置:

image-20230227152224892

前端显示:

image-20230227152520140

DEBUG=True时,代码可以热更新,也就是可以自动重启服务。对开发更友好,可以列出所有路径,报了错,前端能看到。星号表示允许部署在所有地址上。

django 自带的APP:

  • auth app会给你创建6张表。
  • admin app注释会报错。
  • auth app和 admin app有关联。

django 自带中间件:

注释django 所以自带的app之后会导致:
drf 用不了,django-jwt用不了。所以要配置drf不使用django的认证类,并且重写jwt。

ROOT_URLCONF根路由:

根路由移动pycharm会帮你自动修改

模板文件:

image-20230227154943357

箭头这里可以选择配置两个类,这两个类对应 jinja2 或者 django模板语法。
下面的模板路径用列表,意思是可以有多个模板语法类。

项目运行的配置:
上线时使用uswgi。

数据库配置:可以配置多个数据库。数据库主从。

国际化:

中国使用 --> 东八区时间

image-20230227155535310

不仅仅可以写Shanghai写别的也行,只要满足东八区。

DEFAULT_AUTO_FIELD:
整型字段 ---> 大整型字段
这里有一段历史,django之前表迁移的时候会自动生成主键,也就是id字段,这个字段使用的是整型。后来django将其替换成立大整整型,防止数据量过大的情况出现问题。

扩展

  1. # windows安装 mysql 5.7
  2. https://zhuanlan.zhihu.com/p/571585588
  3. seo: 搜索引擎优化
  4. Search Engine Optimization, 搜索引擎优化。
  5. 利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。
  6. sem:交钱,买关键词,排到前面
  7. # 比较好的博客
  8. -cnblogs
  9. -思否
  10. -掘金
  11. -脉脉
  12. 杂谈:
  13. 多个软件可以监听同一个端口,但是一个端口只能给一个软件使用。

前后端分离rbac后台管理

  1. # 推荐学习以下项目:
  2. # 后台:https://gitee.com/liuqingzheng/rbac_manager
  3. # 前端:https://gitee.com/liuqingzheng/vue_admin
  4. # rbac后台管理项目相关
  5. -前端 ---》看人家开源的前端项目,看不懂
  6. -第一种情况,vue+java====》分析有哪些接口,drf复写出来
  7. -第二种情况: 你新建前端项目,你看到它哪个页面好看,copy你里面去只要templatestyle
  8. -js东西自己写

python位运算

  1. &:按位与:两位都为1,结果为1,否则为0
  2. |:按位或:只要有一位为1,结果就为1
  3. ^:按位异或:两对应的二进位相异时,结果为1
  4. ~: 按位取反,即把1变为0,把0变为1,相当于(-x-1
  5. <<:左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0
  6. >>:右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数
  7. a^b 按位异或:两对应的二进位相异时,结果为1
  8. a 0011 1100
  9. b 0000 1101
  10. 二进制结果 0011 0001
  11. 十进制结果 49
  12. # 推荐阅读:
  13. python位运算 https://zhuanlan.zhihu.com/p/370167569
  14. goland位运算 https://juejin.cn/post/7090884238588772383 go语言位运算:没有取反

练习

  1. 1 封装日志并测试 ok
  2. 2 封装异常处理记录日志并测试 ok
  3. 3 封装Resposne并测试 ok
  4. 4 创建路飞用户,路飞库 ok
  5. 5 创建用户表,迁移成功 ok
  6. ---------扩展------
  7. 6 搜索:utf8utf8mb4的区别 ok
  8. 7 搜索:mysql本地连接和用ip连接的区别 ok
  9. 8 学习python位运算 ok
  10. 9 重装mysql 5.7 ok

原文链接:https://www.cnblogs.com/passion2021/p/17161679.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号