81、项目数据库之隐藏密码、封装logger 、环境变量设置、封装全局异常、封装Response、开启media访问、前端项目创建、调整、前端配置

120 阅读2分钟

项目数据库之隐藏密码

1.我们直接把mysql的用户名和密码,写死在了代码中--->后期可能会存在风险--->代码如果泄露--->mysql的用户密码泄露--->可以远程登录---->脱裤(拖库)---->所有数据会被黑客获取到---->卖钱
2.举例:华住:在代码中把数据库用户名和密码写死了---->源代码泄露了--->导致数据泄露
				上海随身办数据泄露:新员工写博客--->把密钥放到了往上

3.我们不把敏感信息写死在代码中
	使用从环境变量中获取
		PATH:任意路径下敲可执行文件能找到
		其它key value 是该机器的全局配置,可以直接拿到
		使用python代码拿到

python代码获取环境变量的值

1.python代码获取环境变量的值:os.environ.get('名字','没有设置返回的值')
2.配置完环境变量,重启一下pycharm
3.如果环境变量没配置,就用默认的
4.如果配置了,就用配置的(项目上线时候,运维配置环境变量--->运维配置的环境变量的值----->开发根本不知道)
5.举例:
  import os
  password = os.environ.get('MYSQL_PDW','Luffy123?')
  print('---',password)
  user = os.environ.get('MYSQL_USER','luffy')
  print('***',user)

具体操作

password = os.environ.get('MYSQL_PDW','Luffy123?')
user = os.environ.get('MYSQL_USER','luffy')
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'luffy',  # 数据库名
        'USER':user,  # luffy用户
        'PASSWORD':password,
        'HOST':'localhost',
        'PORT':3306
    }
}

封装logger

1.项目运行,会产生很多日志
2.日志作用:记录程序运行过程中,错误,警告,程序员的输出,观察项目运行情况
3.每个项目都需要记录日志
4.日志的级别:DEBUG < INFO < WARNING < ERROR < CRITICAL

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': 'DEBUG',
            '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, # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}

使用

1.把上面代码,copy到配置文件中
2.获取logger对象:utils/common_logger.py
	eg:
    # 日志对象获取,以后想用日志的地方,直接导入,使用 logger.info  error....
    import logging
    logger = logging.getLogger('django')
    
3.以后想用日志的地方直接导入使用即可
	eg:
    from utils.common_logger import logger
    def index(request):
        logger.debug('debug级别')
        logger.info('info级别')
        logger.warning('warning级别')
        logger.error('error级别')
        return HttpResponse('ok')
      
ps:以后想用print的位置,都用logger.info,以后项目上线,调高日志输出级别,虽然代码中写了日志输出,实际上并不会输出
		eg:
    from utils.common_logger import logger
    def index(request):

        logger.info('111')
        a =[1,2,3]
        logger.info('222')
        print(a[9])
        logger.info('333')

        return HttpResponse('ok')
	

补充:环境变量设置

1.为什么一定要设置默认值
  user = os.environ.get('USER', 'luffy')
  pwd = os.environ.get('PWD', 'Luffy123?')
  ps:开发人员并不知道真正数据库(正式库)的用户名,密码,项目上线的时候,才可以通过配置环境变量,来防止数据丢失、泄露。

2.这种环境变量,一般写死在系统,而临时设置的,系统重启就失效
	1.win:图形化界面的设置,通过点点点
  2.mac:.bash_profile:只在当前会话生效,当前窗口中生效,关掉窗口,再打开,就失效了,source .bash_profile
        .zshrc:当前用户永久生效
	3.linxu:文件可能名字不一样,配置方式跟mac完全一样
    
    
3.临时设置:运维上线时候,手动设置,当前会话生效
	1.win:
    set xx=lqz  # 设置环境变量
    echo %xx%
        
	2.linux ,mac: 
    export xx=lqz
    echo $xx
        
4.临时设置一般是项目部署的时候,打开一个命令窗口,设置一堆环境变量->python manage.py runserver 

封装全局异常

1.加入日志记录,只要走到这,说明程序出error了,程序的error,咱们都要记录日志,方便后期排查
2.日志记录尽量详细:ip;如果用户登录了,记录用户;请求地址是;执行那个视图类出的错

utils/common_exception.py/common_exception_handler

from rest_framework.views import exception_handler
from rest_framework.response import Response
from .common_logger import logger

def common_exception_handler(exc, context):

    print(context)  # {'view': <user.views.MyException object at 0x1048890c0>, 'args': (), 'kwargs': {}, 'request': <rest_framework.request.Request: GET '/myexception/'>}
    view = context.get('view')
    request = context.get('request')
    ip = request.META.get('REMOTE_ADDR')
    try:
        user_id = request.user.pk
    except:
        user_id='【未登陆用户】'
    path = request.get_full_path()
    view_str = str(view)

    res = exception_handler(exc, context)
    if res:
        # drf的错误
        if isinstance(res.data,dict):
            detail=res.data.get('detail')
        else:
            detail = res.data
        data = {'code':102,'error_msg':detail}
        code = data.get('code')
        logger.error('用户地址为:%s,用户的id:%s,请求地址为:%s,执行的视图函数为:%s,错误提示信息:%s,错误代码:%s'%(ip,user_id,path,view_str,detail,code))
        return Response(data)
    else:
        # django的错误
        error_msg = str(exc)
        data = {'code':'101','msg':'请联系管理员','error_msg':error_msg}
        error_msg=data.get('error_msg')
        code = data.get('code')
        logger.error('用户地址为:%s,用户的id:%s,请求地址为:%s,执行的视图函数为:%s,错误提示信息:%s,错误代码:%s' % (
        ip, user_id, path, view_str, error_msg,code ))
        return Response(data)

Dev.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'utils.common_exception.common_exception_handler',
}

user/views

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.exceptions import APIException
class MyException(APIView):
    def get(self,request):
        logger.info('11')
        # djangp的异常
        # a=[1,2,3]
        # print(a[9])
        raise Exception('错啦')
        # drf异常
        # raise APIException('drf错了')
        return Response('ok')

封装Response

1.之前使用drf提供的Response类,用它的时候,需要传很多参数,基于它做封装,方便我们的使用
	1.data=None, 
  2.status=None, 
	3.headers=None,

2.封装后达成的效果是APIResponse
	效果:
  """
  return APIResponse()  
	----->前端收到的是  {code:100,msg:成功}
    
	return APIResponse(token=12q4dfasdf,username=lqz)  
	----->前端收到的是  {code:100,msg:成功,token:12q4dfasdf,username:lqz}
    
    return APIResponse(data=[{name:红楼梦,price:33},{name:西游记,price:33}]) 
	----->前端收到的是  {code:100,msg:成功,data:[{name:红楼梦,price:33},{name:西游记,price:33}]}
    
    return APIResponse(code=101,msg='失败') 
	----->前端收到的是  {code:101,msg:失败}
    
    return APIResponse(headers={'xx':'xx'}) 
	----->前端收到的是  {code:100,msg:成功},但是相应中有xx:xx
    
    return APIResponse(name=lqz,status=201) 
	----->前端收到的是  {code:100,msg:成功,name:lqz},但是响应状态码是201
  
  """

utils/common_response

from rest_framework.response import Response

class APIResponse(Response):
    def __init__(self, code=100,msg='成功', status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None,**kwargs):
        data = {"code":code,"msg":msg}
        if kwargs:
            data.update(kwargs)
        # 调用父类(Response)的__init__完成初始化
        super().__init__(data=data, status=status,
                 template_name=template_name, headers=headers,
                 exception=exception, content_type=content_type)

Views.py

from utils.common_response import APIResponse
class MyResponse(APIView):
    def get(self,request):
        # return APIResponse()
        return APIResponse(name='nana',status=201)

开启media访问

需求:头像,课程图片,放在项目的某个目录下 (media),后期需要能够访问-->需要开启media的访问

使用

开启media访问
1.在配置文件设置:MEDIA_ROOT
MEDIA_ROOT=os.path.join(BASE_DIR,'media')   # media文件路径

2.配置路由:
  from django.conf import settings
  urlpatterns = [
  path('media/<path:path>',serve, {'document_root':settings.MEDIA_ROOT}),]

3.浏览器访问:
	http://127.0.0.1:8000/media/icon/1.jpg

前端项目创建、调整、配置

前端项目创建、调整

1.vue create luffy_city
2.创建成功,用pycharm打开
3.调整

前端配置

1.安装第三方
	1.axios:cnpm install -S axios
  2.elementui: sudo cnpm i element-ui@2.6.3 -S
  3.vue-cookies:cnpm install -S vue-cookies
  
2.在main.js引入安装的第三方配置
  1.引入axios
  import axios from "axios";
  Vue.prototype.$axios = axios  //使用:this.$axios.get('')

  2.引入elementui
  import ElementUI from 'element-ui';
  import 'element-ui/lib/theme-chalk/index.css';
  Vue.use(ElementUI);

  3.引入vue-cookies
  import cookies from 'vue-cookies';
  Vue.prototype.$cookies=cookies

3.在发送请求的时候,每次都要写一场串url,并且前面一步分的格式是一样的--->写一个全局配置settings.js 文件,里面导出BASE_URL
	1.写一个全局配置settings.js 文件:assets-->js-->settings.js
    export default {
      BASE_URL:'http://127.0.0.1:8000/api/v1/'
  }

  2.配置文件配置:main.js
    import settings from "@/assets/js/settings";
    Vue.prototype.$settings=settings
    
  3.以后再任意组件中使用:this.$settings.BASE_URL
  
4.全局样式:
	1.html的标签a ul li ,都会有默认样式,正常的前端,都会去掉所有标签的默认样式,自己写样式
  2.在assets-->css-->global.css
		"""
		  	/* 声明全局样式和项目的初始化样式 */
        body, h1, h2, h3, h4, h5, h6, p, table, tr, td, ul, li, a, form, input, select, option, textarea {
            margin: 0;
            padding: 0;
            font-size: 15px;
        }

        a {
            text-decoration: none;
            color: #333;
        }

        ul {
            list-style: none;
        }

        table {
            border-collapse: collapse; /* 合并边框 */
        }
		"""
 3.main.js 配置,样式全局生效:
  	import '@/assets/css/global.css' # 使用全局样式,取出所有标签默认样式