luffy后台

发布时间 2023-06-15 21:23:31作者: 星空看海

一 luffy后台创建

# 创建django项目,两种方式
	-命令行
        前提:进入目标目录
        cd python project
    	django-admin startproject 项目名
    	
    -pycharm创建

命令行

1 workon luffy
2 pip install django==3.2.12
3 django-admin startproject luffy_api  # 切换到你想要创建项目的目录下

pycharm 创建项目

-要选中咱们的虚拟环境---> 如果虚拟环境不在,要新增进去
    
# 打开的项目没有使用虚拟环境,在pycharm中如何配置
	

二 调整目录结构

├── luffyapi
    ├── logs/				# 项目运行时/开发时日志目录 - 包
    ├── manage.py			# 脚本文件
    ├── luffyapi/      		# 项目主应用,开发时的代码保存 - 包
     	├── apps/      		# 开发者的代码保存目录,以模块[子应用]为目录保存 - 包
        ├── libs/      		# 第三方类库的保存目录[第三方组件、模块] - 包
    	├── settings/  		# 配置目录 - 包
			├── dev.py   	# 项目开发时的本地配置
			└── prod.py  	# 项目上线时的运行配置
		├── urls.py    		# 总路由
		└── utils/     		# 多个模块[子应用]的公共函数类库[自己开发的组件]
    └── scripts/       		# 保存开发项目的脚本文件 - 文件夹

步骤

# 1、调整目录后,以后app全都放在apps文件夹下
	-创建app,进入到apps的路径
    -python ../../manage.py startapp user  # 在apps目录下创建出一个userapp  # ***********

    -注册到配置文件中
    	- 全路径  (咱们不用,太长了)
        	luffy_api.apps.应用名
        - 把apps所在路径加入到环境变量后,直接写app名字即可
        
# 2、设置两套配置文件
#### 所有项目,都会有多套配置文件###
	-开发阶段配置:dev.py 
    -上线阶段配置:prod.py
    
    
    
# 3、django项目运行,优先运行settings.py 配置文件
	命令运行  python manage.py runserver--->所以,manage中的配置文件路径要正确
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
    
    一旦把dev.py 移动到settings文件夹下后,配置文件中BASE_DIR路径变了,apps拼接的路径也变了,要相应的修改


# 4、把小luffy_api和apps加入环境变量
    sys.path.insert(0, str(BASE_DIR))  # 要str一下,以后导入模块,路径短一些
    apps = os.path.join(BASE_DIR, 'apps')
    sys.path.insert(1, apps)
    
    
# 5、重要:项目上线,不适用manage.py 运行---> 使用uwsgi运行wsgi.py 文件----> 修改这个文件的配置
	-asgi.py
    -wsgi.py 
   	配置文件指定  prod.py  以后上线使用这个配置文件

三 开发阶段本地配置文件dev.py

from pathlib import Path
import os
import sys

# 以后就是小luffy_api 作为项目根路径
BASE_DIR = Path(__file__).resolve().parent.parent   # 因为dev被移动到了更深一层,所以 BASE_DIR 变成了小luffy_api
# print(BASE_DIR)  # E:\python project\luffy_api\luffy_api 变成了小路飞
# print(type(BASE_DIR))  # <class 'pathlib.WindowsPath'>

# 1. 把小luffy_api加入环境变量中,以后修改项目基本是修改小luffy中的文件,这样以后导入模块的路径短一些
sys.path.insert(0, str(BASE_DIR))  # 要str一下

# 2.把apps所在路径,加入到环境变量,以后引入app直接写app名字即可
APPS_DIR = os.path.join(BASE_DIR, 'apps')
sys.path.insert(1, APPS_DIR)

修改目录结构,不能启动

  • 我们把所有的目录结构都修改好后,点击绿色箭头不能顺利启动

  • 先进入编辑配置中,删除掉Django Server,再重新加入进去。

  • 如果还不能启动,进入到settings中
    • ---> Languages&Framework ---> Django中,
    • 把配置文件路径跟启动文件路径选择好,再重新启动

四 数据库配置

软件开发模式

-学bbs,设计创建出所有表,直接迁移,后期没改过  -->瀑布开发模式
-学路飞,先设计,开发一点,测试上线一点-----> 敏捷开发

创建表模型

如果用户表想用 auth的user表扩写,在一开始就要定好

# 1. 使用mysql 数据库,创建一个库,navicate创建即可

# 2. 新建一个user app,基于auth的user表扩写用户表

from django.db import models
from django.contrib.auth.models import AbstractUser

# 扩写auth的user表,新增两个字段
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

3. 迁移数据(mysql-->配置文件配置)

链接数据库和创建luffy用户

-项目的数据库用户,不使用root用,新建一个mysql用户给项目用
-因为root用户权限太大了,新建用户权限小一些
-创建一个luffy用户,授权,只授予luffy库的权限

cmd链接数据库

# 管理员连接数据库
mysql -uroot -proot

# 查看当前数据库有哪些用户
select user,host,password  from mysql.user;

# 5.7往后的版本
select user,host,authentication_string from mysql.user;

为指定数据库配置指定账户

设置权限账号密码
# 授权账号命令:grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'


# 创建luffy用户

# 创建一个用户叫luffy,密码是:Luffy123?,可以本地链接,对luffy库所有表有权限
grant all privileges on luffy.* to 'luffy'@'localhost' identified by 'Luffy123?';

# 创建一个用户叫luffy,密码是:Luffy123?,可以远程地链接,对luffy库所有表有权限
grant all privileges on luffy.* to 'luffy'@'%' identified by 'Luffy123?';

项目配置文件配置

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'luffy',  # 数据库名字
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'luffy',
        'PASSWORD': 'Luffy123?',
        'CHARSET': 'utf8',
    }
}

链接mysql的第三方模块

1、pymysql模块

# django项目如果使用pymsql链接mysql,需要加两句话,加在哪不重要,重要的是它一定要执行

import pymysql
pymysql.install_as_MySQLdb()


django 2 高一点的版本就会报错,需要改源码,麻烦

2、mysqlclient模块

# 咱们以后,使用mysqlclient 操作mysql   pip install mysqlclient,不需要任何配置,就可以操作mysql
		-win:看人品,也有解决方案
    	-mac:很难装,也有,比较麻烦
        -linux:有解决方案

其他配置

dev.py中 注册user表

# 自定义User表
AUTH_USER_MODEL = 'user.User'

Terminal 中执行命令

# 安装pillow包
	pip install pillow
# 执行迁移文件
	python manage.py makemigrations
    python manage.py migrate

项目数据库之隐藏密码

# 我们直接把mysql的用户名和密码 写死在了代码中----> 后期可能会存在风险----> 代码如果泄露----> mysql的用户密码泄露----> 可以远程登录----> 脱裤(拖库)----> 所有数据会被黑客获取到----> 卖钱

# 华住--->在代码中把数据库用户名和密码写死了----> 源代码泄露了---> 导致数据泄露
# 上海随身办数据泄露----> 新员工写博客---> 把密钥放到了往上


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

python代码获取环境变量的值

# 配置完环境变量,重启一下pycharm
# 如果环境变量没配置,就用默认的
# 如果配置了,就用配置的(项目上线时候,运维配置环境变量--->运维配置的环境变量的值---->开发根本不知道)
import os
res=os.environ.get('PWD','Luffy123?')
print(res)
res=os.environ.get('USER','luffy')
print(res)

具体操作

# python代码获取环境变量的值
# res = os.environ.get('WORKON_HOME')
# print(res)  # E:\Virtualenvs
user = os.environ.get('USER', 'luffy')
pwd = os.environ.get('PWD', 'Luffy123?')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'luffy',  # 数据库名字
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': user,
        'PASSWORD': pwd,
        'CHARSET': 'utf8',
    }
}

五 封装logger

  • 项目运行,会产生很多日志
  • 日志作用:记录程序运行过程中 错误,警告,程序员的输出,观察项目运行情况
  • 每个项目都需要记录日志
  • django中加入记录日志的功能

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': {
            # 实际开发建议使用WARNING
            'level': 'WARNING',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            # 实际开发建议使用ERROR
            'level': 'ERROR',
            '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,  # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}

2.utils/common_logger.py

  • 获取logger对象:
# 日志对象获取,以后想用日志的地方,直接导入,使用 logger.info  error....
import logging
logger=logging.getLogger('django')

3. 日志使用

  • 以后想用日志的地方,直接导入使用即可
# DEBUG < INFO < WARNING < ERROR < CRITICAL
logger.debug('debug级别')
logger.info('info级别')
logger.warning('warning级别')
logger.error('error级别')
logger.critical('CRITICAL级别')
  
# 以后想用print的位置,都用logger.info,以后项目上线,调高日志输出级别,虽然代码中写了日志输出,实际上并不会输出

在写项目直接导入utils文件夹也不''错误提示''

img

日志测试

# 应用的views.py
from django.shortcuts import render, HttpResponse

# 小luffy_api已经加入到环境变量中了,就可以直接导入utils文件夹,但是有错误提示
# 想要取消错误提示,右击小luffy_api ---> Mark Diectory as ---> Sources Root
from utils.common_logger import logger


### 日志测试
def index(request):
    # DEBUG < INFO < WARNING < ERROR < CRITICAL
    logger.debug('debug级别')
    logger.info('info级别')
    logger.warning('warning级别')
    logger.error('error级别')
    logger.critical('critical级别')

    logger.info('1111')
    a = [1, 23, 3]
    logger.info('2222')
    # print(a[9])
    logger.info('333')  # 控制台没有输出333的info日志,说明是这个日志和上个日志中间出了问题

    # 以后想用print的位置,都用logger.info,以后项目上线,调高日志输出级别,虽然代码中写了日志输出,实际上并不会输出
    return HttpResponse('ok')

六 封装全局异常处理

安装

pip install djangorestframework==3.14.0

utils/common_exceptions.py

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


#### 加入日志记录,只要走到这,说明程序出error了,程序的error,咱们都要记录日志,方便后期排查
### 日志记录尽量详细:ip;如果用户登录了,记录用户;请求地址是;执行那个视图类出的错
def common_exception_handler(exc, context):
    # print(exc)  # 错误信息
    # print(context)  # {'view': <user.views.ExceptionTestView object at 0x00000174CC0E0C40>, 'args': (), 'kwargs': {}, 'request': <rest_framework.request.Request: GET '/exception/'>}

    request = context.get('request')
    view = context.get('view')
    view_str = str(view)
    ip = request.META.get('REMOTE_ADDR')
    try:
        user_id = request.user.pk
    except:
        user_id = '[未登录用户]'  # 匿名用户的id是None
    path = request.get_full_path()
    res = exception_handler(exc, context)

    # 记录日志
    # logger.info('用户地址为:%s,用户id号为:%s,请求地址为:%s,执行的视图函数为:%s' % (ip, user_id, path, view_str))
    if res:
        # drf的异常,一种是从res.data这个字典的detail中取,一种是  直接取data
        if isinstance(res.data, dict):
            data = {'code': 999, 'msg': res.data.get('detail', '系统错误,请联系系统管理员')}
        else:
            data = {'code': 998, 'msg': res.data}
    else:
        # django的异常
        data = {'code': 888, 'msg': str(exc)}
    # 记录日志
    logger.error('用户地址为:%s,用户id号为:%s,请求地址为:%s,执行的视图函数为:%s,错误详细是:%s。' % (ip, user_id, path, view_str, exc))
    return Response(data)

配置文件配置

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

全局异常测试

### view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import APIException, ValidationError
class ExceptionTestView(APIView):
    def get(self, request):
        ## django 异常
        # raise Exception('django的异常')
        # a = [9, 4, 2]
        # print(a[9])

        ## drf 异常
        # raise APIException('drf异常')
        # raise ValidationError('认证失败')  # 列表套字典形式,
        return Response('ok')

七 封装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:  # kwargs中有值
            data.update(kwargs)
        # 调用父类(Response)的__init__完成初始化
        super().__init__(data=data, status=status, headers=headers)

测试响应对象

#### 测试自己封装的响应对象
from rest_framework.views import APIView
from utils.common_response import APIResponse


class MyResponseView(APIView):
    def get(self, request):
        return APIResponse()
        # return APIResponse(code=101, msg='请求失败')
        # return APIResponse(result=[{'name': 'lqz', 'price': 19}])
        # return APIResponse(name='lqz', status=201, headers={'xx': 'xx'})

八 开启media访问

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

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('media/<path:path>', serve,{'document_root':settings.MEDIA_ROOT}),
]

dev.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')