一、封装logger
| |
| |
| |
| |
| |
| |
| |
| 1 把如下代码,copy到配置文件中 |
| 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': { |
| |
| 'level': 'WARNING', |
| 'filters': ['require_debug_true'], |
| 'class': 'logging.StreamHandler', |
| 'formatter': 'simple' |
| }, |
| 'file': { |
| |
| 'level': 'ERROR', |
| 'class': 'logging.handlers.RotatingFileHandler', |
| |
| 'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"), |
| |
| 'maxBytes': 300 * 1024 * 1024, |
| |
| 'backupCount': 10, |
| |
| 'formatter': 'verbose', |
| |
| 'encoding': 'utf-8' |
| }, |
| }, |
| |
| 'loggers': { |
| 'django': { |
| 'handlers': ['console', 'file'], |
| 'propagate': True, |
| }, |
| } |
| } |
| 2 获取logger对象:utils/common_logger.py |
| |
| import logging |
| logger=logging.getLogger('django') |
| |
| 3 以后想用日志的地方,直接导入使用即可 |
| |
| logger.debug('debug级别') |
| logger.info('info级别') |
| logger.warning('warning级别') |
| logger.error('error级别') |
| logger.critical('CRITICAL级别') |
| |
| 4 以后想用print的位置,都用logger.info,以后项目上线,调高日志输出级别,虽然代码中写了日志输出,实际上并不会输出 |
二、环境变量设置
| |
| user = os.environ.get('USER', 'luffy') |
| pwd = os.environ.get('PWD', 'Luffy123?') |
| |
| |
| win:图形化界面的设置 |
| mac: |
| .bash_profile:只在当前会话生效,当前窗口中生效,关掉窗口,再打开,就失效了,source .bash_profile |
| .zshrc:当前用户永久生效 |
| |
| linxu: 文件可能名字不一样,配置方式跟mac完全一样 |
| |
| |
| |
| win: |
| set xx=lqz |
| echo %xx% |
| |
| linux ,mac: |
| export xx=lqz |
| echo $xx |
| |
| 项目部署:打开一个命令窗口 |
| 设置一堆环境变量 |
| python manage.py runserver |
三、封装全局异常
| |
| from rest_framework.views import exception_handler |
| from rest_framework.response import Response |
| from utils.common_logger import logger |
| |
| |
| |
| |
| def common_exception_handler(exc, context): |
| request = context.get('request') |
| view = context.get('view') |
| 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) |
| logger.error('用户地址为:%s,用户id号为:%s,请求地址为:%s,执行的视图函数为:%s' % (ip, user_id, path, view_str)) |
| |
| |
| if res: |
| |
| if isinstance(res.data, dict): |
| data = {'code': 999, 'msg': res.data.get('detail', '系统错误,请联系系统管理员')} |
| else: |
| data = {'code': 998, 'msg': res.data} |
| |
| else: |
| |
| data = {'code': 888, 'msg': str(exc)} |
| return Response(data) |
| |
| |
| |
| REST_FRAMEWORK = { |
| 'EXCEPTION_HANDLER': 'utils.common_exceptions.common_exception_handler', |
| } |
四、封装Response
| # 咱们之前使用drf提供的Response类,用它的时候,需要传很多参数,基于它做封装,方便我们的使用 |
| data=None, |
| status=None, |
| headers=None, |
| |
| # 封装后达成的效果是 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.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} |
| # kwargs 有可能是 {token:asdfad,name:lqz} |
| if kwargs: |
| data.update(kwargs) |
| # 调用父类(Response)的__init__完成初始化 |
| super().__init__(data=data, status=status, headers=headers) |
| # 头像,课程图片,放在项目的某个目录下 (media),后期需要能够访问 |
| # 需要开启media的访问 |
| from django.views.static import serve |
| from django.conf import settings |
| urlpatterns = [ |
| path('admin/', admin.site.urls), |
| path('media/<path:path>', serve,{'document_root':settings.MEDIA_ROOT}), |
| |
| ] |
| ##配置文件 |
| # 开启media访问 |
| MEDIA_ROOT=os.path.join(BASE_DIR,'media') |
| |
六、前端配置
| |
| -axios |
| -elementui |
| -vue-cookies |
| |
| |
| |
| |
| cnpm install -S axios |
| cnpm install -S vue-cookies |
| cnpm i element-ui@2.9.2 -S |
| |
| |
| |
| |
| import ElementUI from 'element-ui'; |
| import 'element-ui/lib/theme-chalk/index.css'; |
| Vue.use(ElementUI); |
| |
| |
| import axios from "axios"; |
| Vue.prototype.$axios=axios |
| |
| |
| import cookies from 'vue-cookies' |
| Vue.prototype.$cookies=cookies |
| |
| |
| |
| |
| export default { |
| BASE_URL: 'http://127.0.0.1:8000/api/v1/' |
| } |
| |
| import settings from '@/assets/js/settings' |
| Vue.prototype.$settings=settings |
| |
| this.$settings.BASE_URL |
| |
| |
| |
| |
| html的标签a ul li ,都会有默认样式,正常的前端,都会去掉所有标签的默认样式, 自己写样式 |
| |
| |
| |
| 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: |
| } |
| |
| ul { |
| list-style: none; |
| } |
| |
| table { |
| border-collapse: collapse; |
| } |
| |
| |
| |
| import '@/assets/css/global.css' |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构