后台日志封装,全局异常处理封装, 封装Response,luffy数据库创建,软件开发模式,User模块用户表,djagno的配置文件,开启media访问

后台日志封装

# 每个项目都要记录日志
    -所有项目日志统一管理---->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,  # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}

image

全局异常处理封装

前戏:在三大认证的学习中,视图类的方法只要出了异常,就会执行一个函数
# 我们写一个函数,封装全局异常
	-统一返回格式
    -记录日志:方便后续出了异常,程序有问题进行排查
# 使用步骤
	-第一步:在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()),

image

封装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()),

image

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库

image

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
    },
}

image

软件开发模式

无论是瀑布式开发、敏捷开发还是DevOps,整个流程都分为设计、开发、测试和部署四个部分,只不过各个部分的开始和结束时间节点不同而已!
# 瀑布开发
瀑布式开发是早期被广泛采用的软件开发模型,要求有明确的需求,大家按照需求一步步做好规划,每一阶段工作的完成是下一阶段工作开始的前提,每一阶段都要进行严格的评审,保证各阶段的工作做得足够好时才允许进入下一阶段,它适用于需求明确的项目。其最大的风险是,当产品研发完成后, 到了产品测试阶段如果发现了问题 ,或者发现其无法满足市场需求, 那么就需要重新开发,甚至需要重新规划产品。

# 敏捷开发
敏捷开发是一种以用户需求进化为核心、迭代、循序渐进的开发方法。首先把用户最关注的软件原型做出来并交付给用户,用户在实际场景中发现问题并给予反馈,研发人员快速修改弥补需求中的不足。上述过程不断迭代,直到用户满意。敏捷适用于需求不明确、创新性或者需要抢占市场的项目,特别适合互联网项目。

# DevOps
DevOps是一种软件开发实践,它将人员、流程和技术结合在一起,以交付持续的价值。该方法分为计划和跟踪、开发、生成和测试、交付以及监视和操作。DevOps 的独特之处在于开发、IT 运营、质量工程和安全团队协同工作,在发布新产品、版本或更新所涉及的所有任务中创造效率。

# DevOps和敏捷
关于 DevOps 和敏捷,最重要的一点是它们不是互斥的。DevOps 是一种文化,促进所有参与软件开发和维护的参与者之间的协作。敏捷可以被描述为一种开发方法,旨在需求不断变化的现实中维护工作效率和驱动发布。尽管 DevOps 和敏捷是不同的,但是如果将这两种方法结合使用,将会带来更高的效率和更可靠的结果。DevOps是敏捷的有效补充,是将运维纳入产品开发过程的思维方式,是敏捷开发方法论的升级,更强调自动化工具的实现与应用,以帮助实现软件的快速迭代。

详细参考:https://zhuanlan.zhihu.com/p/444741981

-软件开发模式
	-瀑布开发:bbs项目
    -敏捷开发:路飞,管理软件

img

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访问

# 配置文件加入
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

image

零碎的面试题

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')

执行结果如下:

img

如果想更简洁,可用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!')

在这里插入图片描述