路飞项目 - 项目前后端搭建
1 封装后台日志
1.日志的作用:
对特定的io操作进行记录,记录错误和记录操作
【日志可以用来做项目管理,记录用户行为分析,大数据分析】
开发阶段可以将print换成logger.info
这样项目上线后只需要调整日志级别,低级别的日志不在打印了,日志输出不用删掉了
2.日志显示:
① 日志可以打印到控制台
② 日志可以写到日志文件中
③ 日志可以存到数据库中
④ 所有项目统一管理【 sentry:django写的服务,收集日志可以展示】
3.操作步骤
django中集成日志步骤,django使用的是python内置的日志模块
① 第一步:在配置文件dev.py中加入,日志配置【记录日志大字典】
# 真实项目上线后,日志文件打印级别不能过低,因为一次日志记录就是一次文件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': 'ERROR',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
# 文件配置
'file': {
# 实际开发建议使用ERROR
'level': 'INFO',
'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_logger.py,封装成日志对象
common_logger.py中选择日志对象
import logging
logger = logging.getLogger('django')
③ 第三步:在任意想用日志的地方,导入封装好的日志对象使用即可
# 导入封装好的日志对象
from utils.common_logger import logger
def test_logging(request):
"""测试日志"""
logger.debug('记录【debug】级别的日志')
logger.info('记录【info】级别的日志')
logger.warning('记录【warning】级别的日志')
logger.error('记录【error】级别的日志')
logger.critical('记录【CRITICAL】级别的日志')
return HttpResponse('ok')
- debug级别的的日志并不打印在控制台中
- debug()不返回任何内容。 它生成的日志记录将发送到日志模块,并通过您配置的任何处理程序进行处理。 如果您确实想检查通过的记录,则可能需要实现自己的处理程序并将其添加到记录器中。
- 可以通过配置日志对象的记录日志的等级来控制日志输出的等级
'level': 'DEBUG',
2 封装全局异常处理
1.为什么项目中要统一对异常处理进行封装?
前端接收异常的格式要统一,所以我们对于项目中的抛出的异常应该进行统一的处理
但是因为我们是基于drf的基础上编写项目,在drf中使用了三大认证的封装。
所以我们在drf的基础上继续进行封装即可
2.处理步骤
① 在utils.py中新建py文件 - common_exceptions.py
- 1 封装处理drf的异常与非drf的异常
- 2 添加日志记录
# 封装项目的全局异常处理
# 1.导入drf的异常处理函数
from rest_framework.views import exception_handler as drf_exception_handler
# 2.导入drf封装的Response对象
from rest_framework.response import Response
# 3.导入日志对象
from utils.common_logger import logger
def luffy_exception_handler(exc, context):
# 对drf的异常捕获以及非drf的异常捕获后,需要把抛出的异常加入到日志文件中
# 0、记录日志:哪个ip地址、用户id是多少、访问哪个路径、执行哪个视图函数、出了什么错
request = context.get('request')
view = context.get('view')
# 获取ip地址
ip = request.META.get('REMOTE_ADDR')
# 获取user_id,通过获取用户对象来获取用户的id
user_id = request.user.pk
# 获取用户访问的地址
path = request.get_full_path()
# 1. 通过drf的异常处理函数,判断是否是drf的异常
drf_request = drf_exception_handler(exc, context)
# 2. 判断是否是drf的异常,如果是drf_request有值则是drf抛出了异常
if drf_request:
# 添加记录用户日志信息
logger.warning('drf出现异常,异常是【%s】' % str(exc))
res = Response({'code': 888, 'msg': drf_request.data.get('detail', '请联系系统管理员')})
else:
# 添加日志
logger.warning('用户【%s】:ip地址为【%s】,访问地址【%s】时,执行了函数【%s】,出现了异常【%s】' % (user_id, ip, path, view, str(exc)))
res = Response({'code': 999, 'msg': '请联系系统管理员'})
return res
② 配置文件中配置
配置使用自己封装的异常处理
# 全局异常处理
REST_FRAMEWORK = {
'EXCEPTION_HANDLER':'utils.common_exceptions.luffy_exception_handler'
}
③ 写代码后报错会统一处理返回给前端,并且会记录日志
3 封装Response
1.为什么要封装Response
drf已经封装了Response对象,但是公司规定前端收到的格式都是固定的,并且携带一定的数据
例如:
# 携带数据
{code:100,msg:提示,data:{}/[]}
# 携带token或者用户
{code:100,msg:提示,token:xxx,user:xxx}
2.使用步骤:
① 在utils下新建common_response.py
② 封装MyResponse
自己编写响应类继承Response,来定制返回格式
from rest_framework.response import Response
class MyResponse(Response):
# 1 派生 __init__ 方法,给code 与 msg设定默认值,
# status=None, headers=None默认可以不传
# 其他的参数用**kwargs统一接收
def __init__(self, code=100, msg='成功', status=None, headers=None, **kwargs):
# 2 设置返回格式 data
data = {'code': code, 'msg': msg}
# 3 判断kwargs是否传值,如果传了则说明处理四个默认的之外有新的参数
if kwargs:
# 4 使用字典的update方法,如果有新的键值对则新增,如果没有原有的键值对有更改则更新
data.update(kwargs)
# 5 派生继承原有的__init__方法,这样就在drf的Response类基础上 对返回能传递的数据进行了修改
super().__init__(data=data, status=status, headers=headers)
③ 导入使用
视图函数的方法,返回时Response对象时,使用自己封装的
4 luffy数据库创建
1.项目数据库用户为什么不用root
之前项目操作数据库都是root用户,root权限过于高,如果开发人员都是root权限,那么每个开发人员都能对任意的数据库进行操作,数据的安全性较低
因此,应该专门创建一个数据库用户,并且只对当前项目的数据库有操作权限
2.创建luffy数据库操作步骤
① 以管理员身份,连接数据库
mysql -uroot -p
② 创建数据库luffy
create databases luffy default charset=utf8;
③ 创建luffy用户,配置任意ip都可以连入数据库的账户
# 设置权限账号密码:授权账号命令:
grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'
grant all privileges on luffy.* to 'luffy'@'%' identified by 'luffy123';
④ 由于数据库版本的问题,可能本地还连接不上,就给本地用户单独配置
grant all privileges on luffy.* to 'luffy'@'localhost' identified by 'luffy123';
⑤ 刷新权限
flush privileges;
3.在项目中配置数据库
(1)配置文件中配置数据库连接
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'luffy',
'PASSWORD': 'luffy123'
}
}
(2)在项目下的主模块的__init__.py
配置
import pymysql
pymysql.install_as_MySQLdb()
pip3 install mysqlclient -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/
- 关于pymysql、mysqldb、mysqlclient的选择问题
-历史:原来py2上有个操作mysql的模块叫mysqlDB,但到py3,没有支持py3,django默认使用这个模块去连接mysql,默认使用-mysqlDB连接,-mysqlDB不支持py3,运行报错
-我们使用pymysql,作为连接mysql的数据库模块,但是需要加代码
imprort pymysql
pymysql.install_as_mysqldb() # 猴子补丁
-django 2.2.2以后,还使用pymysql,需要改djagno源代码
-统一使用mysqlclient来作为操作mysql的底层库
-基于py2的mysqldb,在py3上重新了,但是名字改成了mysqlclient
-使用mysqlclient,只需要安装这个模块,不需要再写任何代码,直接用即可
-但是:mysqlclient 这个模块,不好装
-win 一般人品好,人品好,pip install mysqlclient
-人品不好,装不了,centos部署项目,后面会讲centos上如何装
5 软件开发模式
1.瀑布模式
需求分析---》设计--》创建数据库 所有都创建---》开发(3个月)---》交给测试--》测试通过---》上线
2.敏捷开发
需求分析---》设计---》只设计一个板块---》开发(2周)---》交给测试---》运维上线(测试环境)
-设计---》只设计一个板块---》开发(2周)---》交给测试---》运维上线(测试环境)
6 User模块用户表
1.分析
- 用户表使用Auth表扩写
使用auth表扩写,项目一定不要先迁移
2.用户表使用auth表扩写
class User(AbstractUser):
# 扩写手机号和头像字段
mobile = models.CharField(max_length=11, unique=True)
# 需要pillow包的支持
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
7 开启media访问
1 在配置文件中配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
2 配置路由
# 以后使用djagno的配置文件都用这个
from django.conf import settings
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT})
# 访问
http://127.0.0.1:8000/media/icon/default.png
以后使用配置文件settings 都使用django内置的