后台日志封装
# 每个项目都要记录日志
-所有项目日志统一管理---->sentry:django写的服务,收集日志的,实时日志管理平台
-后期可以通过日志排查问题,分析错误
# 之前学过logging模块,Django就是原生的logging模块
#在项目中集成日志
-第一步:在配置文件中加入日志配置,复制代码放到配置文件中
-详情见项目配置文件
-第二步:在utils中新建common_logger.py
import logging
# 通过配置中的名字拿到logger对象,以后只需要导入,直接使用对象写日志即可
logger = logging.getLogger('django')
-第三步:在任意想用日志的地方,导入即可
# 日志的配置
# 真实项目上线后,日志文件打印级别不能过低,因为一次日志记录就是一次文件io操作
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
},
},
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
# 实际开发建议使用WARNING
'level': 'INFO',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': {
# 实际开发建议使用ERROR
'level': 'WARNING',
'class': 'logging.handlers.RotatingFileHandler',
# 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
# 日志文件的最大值,这里我们设置300M
'maxBytes': 300 * 1024 * 1024,
# 日志文件的数量,设置最大日志数量为10
'backupCount': 10,
# 日志格式:详细格式
'formatter': 'verbose',
# 文件内容编码
'encoding': 'utf-8'
},
},
# 日志对象
'loggers': {
'django': {
'handlers': ['console', 'file'],
'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
},
}
}
全局异常处理封装
前戏:在三大认证的学习中,视图类的方法只要出了异常,就会执行一个函数
# 我们写一个函数,封装全局异常
-统一返回格式
-记录日志:方便后续出了异常,程序有问题进行排查
# 使用步骤
-第一步:在utils中新建 common_exceptions.py
-第二步:写view和url代码
-第三步:配置配置文件,以后只要出了异常,都会走咱们的函数
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'utils.common_exceptions.exception_handler',
}
-第四步:勇敢大胆写代码,即便报错,程序不会蹦,并且会记录日志,并且处理成统一格式
common_exceptions.py:
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.common_logger import logger
# 只要走到这个函数就是出异常了,一定要记录日志
def exception_handler(exc, context):
# 请求地址,请求方式,请求时间,请求哪个视图函数,登录了记录一下用户id
request = context.get('request')
view = context.get('view')
ip = request.META.get('REMOTE_ADDR')
user_id = request.user.pk
path = request.get_full_path()
response = drf_exception_handler(exc, context)
if response:
logger.warning('drf出了异常,异常是%s' % str(exc))
res = Response({'code': 999, 'msg': response.data.get('detail', '服务器异常,请联系系统管理员')})
else:
# django的异常
logger.error('用户【%s】,ip地址为【%s】,执行函数为【%s】,出错的是【%s】' % (user_id, ip, path, str(view), str(exc)))
res = Response({'code':888,'msg':'服务器异常,请联系系统管理员'})
return res
view.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import APIException
class TestException(APIView):
def get(self,request):
# drf 异常
# raise APIException('drf抛出异常')
return Response('ok')
url.py:
path('test_exception',views.TestException.as_view()),
封装Response
# drf提供的Response对象,不能很方便的加入code和msg中,自己封装一个Response类,以后都用我们自己封装的,方便咱们写code和msg
# 使用步骤
第一步:在utils下新建common_response.py
第二步:封装APIRespon
第三步:导入使用,视图函数的方法,返回时,都使用咱们自己的
common_response.py:
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self,code=100,msg='成功',status=None,headers=None,**kwargs):
data = {'code':code,'msg':msg}
if kwargs:
data.update(kwargs)
super().__init__(data=data,status=status,headers=headers)
view.py
from utils.common_response import APIResponse
class TestAPIResponse(APIView):
def get(self,request):
# return APIResponse(token='jhdghhdh',username = 'xin')
# return APIResponse(code=101, msg='错误')
return APIResponse(data=[{'name':'忽有故人心上过,回首山河已入冬','price':666},{'name':'朝若是同淋雪,此生也算共白头','price':666}])
url.py:
path('test_response',views.TestAPIResponse.as_view()),
luffy数据库创建
1)数据库使用mysql,配置mysql
2)之前使用root用户作为项目的数据库用户,权限太高了,一般公司里,给项目单独建立一个用户,这个用户只对当前库有权限
3)在mysql中创建一个用户luffy_api,给用户授予luffy库的所有权限
1 链接mysql,创建一个luffy库
-命令行创建
-navicate客户端创建
2 查看有哪些用户:
select user,host from mysql.user;
3 创建一个luffy_api用户(之前有个root用户,权限很高)
授权账号命令:grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'
把luffy库下所有表的权限都授予luffy_api这个用户,允许远程链接
grant all privileges on luffy.* to 'luffy_api'@'%' identified by 'Luffy123?';
把luffy库下所有表的权限都授予luffy_api这个用户,允许本地链接
grant all privileges on luffy.* to 'luffy_api'@'localhost' identified by 'Luffy123?';
4 以luffy_api用户登录,查看,只能看到luffy库
luffy_api的连接有两条的:一条通过本地连接,一条通过远程连接
本地连接:mysql -uroot -p 密码
远程连接:mysql -h ip地址 -p端口号 -u用户名 -p密码
使用项目连接库
1.运行项目会报错,django默认使用mysqlDB操作mysql,mysqlDB这个模块,在python2可以的,在python3中不支持,于是咱们使用pymysql替换,到了django2.0.7以后,如果使用pymysql替换,需要改django的源代码,后期使用mysqlclient,替换pymysql,mysqlclient是mysqlDB的python3.x版本
-如果使用pymysql,需要改源码,需要执行
import pymysql
pymysql.install_as_MySQLdb() # 猴子补丁,把里面所有mysqlDB的对象,都替换成pymysql
-猴子补丁是:在程序运行过程中得动态替换技术: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/
-以后再django中不使用pymysql了,使用mysqlclient,不需要再执行任何补丁了
-win,linux,mac,这个模块不太好装,看人品,有时候很顺利,有时候装不上
2 只需要装 mysqlclient,一切都解决了
# 目前咱们配置文件中,直接写死了mysql的用户名和密码
-可能存在的风险---》如果我的源代码泄露了---》数据库用户名密码就泄露---》黑客可以远程登录---》脱库
-华住汉庭的酒店入住信息泄露,源代码泄露了,导致被脱库
-上海随身办的数据泄露
# 补充:
mysql的utf8编码和utf8mb4的区别?
-utf8:一个字符,占两个字节(byte--->1个byte是8个比特位 10101010)
-utf8mb4:一个字符,占4个字节,表情符号
-咱们学的utf-8:可变长可以1---4字节表示一个字符
# 用户名密码写死在代码中了,保证安全
name = os.environ.get('LUFFY_NAME', 'luffy')
password = os.environ.get('LUFFY_PASSWORD', 'Luffy123?')
# 数据库配置,mysql 主从搭建完,读写分离
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER':name,
'PASSWORD':password,
'HOST':'127.0.0.1',
'PORT':3306
},
}
软件开发模式
无论是瀑布式开发、敏捷开发还是DevOps,整个流程都分为设计、开发、测试和部署四个部分,只不过各个部分的开始和结束时间节点不同而已!
# 瀑布开发
瀑布式开发是早期被广泛采用的软件开发模型,要求有明确的需求,大家按照需求一步步做好规划,每一阶段工作的完成是下一阶段工作开始的前提,每一阶段都要进行严格的评审,保证各阶段的工作做得足够好时才允许进入下一阶段,它适用于需求明确的项目。其最大的风险是,当产品研发完成后, 到了产品测试阶段如果发现了问题 ,或者发现其无法满足市场需求, 那么就需要重新开发,甚至需要重新规划产品。
# 敏捷开发
敏捷开发是一种以用户需求进化为核心、迭代、循序渐进的开发方法。首先把用户最关注的软件原型做出来并交付给用户,用户在实际场景中发现问题并给予反馈,研发人员快速修改弥补需求中的不足。上述过程不断迭代,直到用户满意。敏捷适用于需求不明确、创新性或者需要抢占市场的项目,特别适合互联网项目。
# DevOps
DevOps是一种软件开发实践,它将人员、流程和技术结合在一起,以交付持续的价值。该方法分为计划和跟踪、开发、生成和测试、交付以及监视和操作。DevOps 的独特之处在于开发、IT 运营、质量工程和安全团队协同工作,在发布新产品、版本或更新所涉及的所有任务中创造效率。
# DevOps和敏捷
关于 DevOps 和敏捷,最重要的一点是它们不是互斥的。DevOps 是一种文化,促进所有参与软件开发和维护的参与者之间的协作。敏捷可以被描述为一种开发方法,旨在需求不断变化的现实中维护工作效率和驱动发布。尽管 DevOps 和敏捷是不同的,但是如果将这两种方法结合使用,将会带来更高的效率和更可靠的结果。DevOps是敏捷的有效补充,是将运维纳入产品开发过程的思维方式,是敏捷开发方法论的升级,更强调自动化工具的实现与应用,以帮助实现软件的快速迭代。
详细参考:https://zhuanlan.zhihu.com/p/444741981
-软件开发模式
-瀑布开发:bbs项目
-敏捷开发:路飞,管理软件
User模块用户表
# 配置好mysql了,咱们项目的用户表是,会用Auth的User表,扩写字段
# 使用步骤
-1 创一个用户app:python ../../manage.py startapp user
-2 user 的app的models.py中扩写用户表
class UserInfo(AbstractUser):
mobile = models.CharField(max_length=11, unique=True)
# 需要pillow包的支持 ImageField继承了 FileField只存储图片
icon = models.ImageField(upload_to='icon', default='icon/default.png')
class Meta:
db_table = 'luffy_user' # 指定表明
verbose_name = '用户表' # 后台管理中显示中文
verbose_name_plural = verbose_name
def __str__(self):
return self.username
-3 配置文件配置,注册app,安装pillow模块
# 用户表的配置
AUTH_USER_MODEL='user.UserInfo'
-4 两条命令迁移
>python manage.py makemigrations
>python manage.py migrate
# 配置文件加入
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 总路由中设置
# re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT})
# 访问
http://127.0.0.1:8000/media/icon/default.png
# 以后使用djagno的配置文件都用这个
from django.conf import settings
零碎的面试题
1.md5是对称加密还是非对称加密
-对称加密:加密的秘钥和解密的秘钥是同一个
-非对称加密:加密使用公钥加密,解密使用私钥解密,公钥是不能解密的
-MD5是摘要算法---->没有解密算法这一说
2.utf8和utf8mb4的区别
-是针对Unicode的一种可变长度字符编码。由于对可以用Ascll表示的字符,使用Unicode并不高效,因为Unicode比Ascll占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(Unicode Transformation Format)
-所以utf8是utf8mb4的子集,除了将编码改为utf8mb4外不需要做其他转换。
# utf8mb4比utf8多了什么的呢?
1、多了emoji编码支持.
如果实际用途上来看,可以给要用到emoji的库或者说表,设置utf8mb4.比如评论要支持emoji可以用到.建议普通表使用utf8 如果这个表需要支持emoji就使用utf8mb4
2、新建mysql库或者表的时候还有一个排序规则
utf8_unicode_ci比较准确,utf8_general_ci速度比较快。通常情况下utf8_general_ci的准确性就够我们用的了,所以新建数据 库时一般选用utf8_general_ci就可以了
3.mysql本地连接和用ip连接的区别
localhost 代表了本主机,通过使用localhost可以访问自己主机的网络服务,http://localhost,将会显示运行这个浏览器的计算机上所服务的网站的主页。使用localhost的时候,使用的是回环网络接口,这会绕过本地网络接口硬件,独立于任何网络配置(不受网络防火墙和网卡相关的的限制)
IP地址是由网络地址与主机地址两部分所组成
如果有使用-h指定主机的都是使用远程登录的方式,如果没有就是使用socket的方式
mysql -h 127.0.0.1 的时候,使用TCP/IP连接, mysql server 认为该连接来自于127.0.0.1或者是 localhost.localdomain
mysql -h localhost 的时候,是不使用TCP/IP连接的,而使用 Unix socket。此时,mysqlserver则认为该 client 是来自 localhost
mysql权限管理中的"localhost"有特定含义:
注意:虽然两者连接方式有区别,但当localhost为默认的127.0.0.1时,两种连接方式使用的权限记录都是以下的1.row的记录(因为记录在前,先被匹配)
4.python3中超级好用的日志模块-loguru模块
详解见博客:https://blog.csdn.net/cui_yonghua/article/details/107498535
用python写代码时,logging模块最基本的几行配置,如下:
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info('this is another debug message')
logger.warning('this is another debug message')
logger.error('this is another debug message')
logger.info('this is another debug message')
执行结果如下:
如果想更简洁,可用loguru库,python3安装:pip3 install loguru。
loguru默认的输出格式是上面的内容,有时间、级别、模块名、行号以及日志信息,不需要手动创建 logger,直接使用即可,另外其输出还是彩色的,看起来会更加友好。
用法如下:
from loguru import logger
logger.debug('this is a debug message')
logger.info('this is another debug message')
logger.warning('this is another debug message')
logger.error('this is another debug message')
logger.info('this is another debug message')
logger.success('this is success message!')
logger.critical('this is critical message!')