创建一个新DRF项目的步骤
创建项目目录:
在命令行中创建一个新的目录用于存放你的项目文件:
mkdir my_drf_project
cd my_drf_project
创建虚拟环境:
在项目目录内创建一个Python虚拟环境(一个项目一个虚拟环境,防止互相影响):
python -m venv venv
激活虚拟环境:
在Windows上是
venv\Scripts\activate
在Unix或MacOS系统上是
source venv/bin/activate
安装Django和DRF:
在激活的虚拟环境中,安装Django和DRF:
pip install django djangorestframework
创建新的Django项目:
使用Django命令行工具创建新项目:
django-admin startproject projectname
其中 projectname
是你的项目名。
创建新的Django应用:
在Django项目内创建一个或多个应用:
python manage.py startapp appname
其中 appname
是你的应用名。
指定应用存放路径:
python manage.py startapp users my_project/apps/users
my_project/apps/user
这个路径必须已经存在
加入DRF到Django settings:
在项目的 settings.py
文件中加入 rest_framework
到 INSTALLED_APPS
:
INSTALLED_APPS = [
# ...
'rest_framework',
]
配置你的DRF应用:
根据你的需要配置DRF。例如,设置分页,认证,权限等:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
# Other configurations...
}
创建你的模型和视图:
在你的Django应用中创建模型(models.py
)和序列化类(通常在 serializers.py
中)。然后,在 views.py
里创建视图集(ViewSets)或视图(Views)。
配置URLs:
使用DRF的路由器(router)来自动生成URL配置,这通常会在 urls.py
文件中做:
from django.urls import include, path
from rest_framework import routers
from appname import views
router = routers.DefaultRouter()
router.register(r'yourmodel', views.YourModelViewSet)
urlpatterns = [
path('', include(router.urls)),
]
设定数据库和迁移操作:
配置 settings.py
里的数据库设置,并执行迁移来为你的模型创建数据库表:
python manage.py makemigrations
python manage.py migrate
运行开发服务器:
启动Django项目:
python manage.py runserver
mysql数据库配置及驱动配置
创建数据库
-
查看已有数据库命令
SHOW DATABASES;
-
创建新数据库
CREATE DATABASE 数据库名 CHARACTER SET utf8mb4;
utf8mb4 和 utf8 的区别主要是 utf8mb4可以存储4字符的内容,而utf8只能存储3及3一下字符,一般使用utf8mb4即可,因为实际使用对若不存储4字符的内容两种格式的存储空间一样。
-
创建一个用户管理此数据库
- 创建用户:
CREATE USER '用户名' IDENTIFIED BY '密码';
- 添加权限:给予用户数据库中所有表的所有权限
GRANT ALL ON 数据库名.* TO '用户名'@'%';
- 刷新权限设置
FLUSH PRIVILEGES;
-
创建一个用户只能从指定主机连接数据库
- 创建用户:
CREATE USER '用户名'@'host' IDENTIFIED BY '密码';
host
可以是具体的IP地址、主机名、一个子网或localhost。- 指定权限
GRANT ALL ON 数据库名.* TO '用户名'@'host';
- 刷新权限
FLUSH PRIVILEGES;
-
给一个用户仅有部分管理权限
GRANT 权限类型1, 权限类型2 ON 数据库名.表名 TO '用户名'@'host'; FLUSH PRIVILEGES;
多个权限类型用户逗号隔开,权限类型包括:
查询(SELECT)
插入(INSERT)
更新(UPDATE)
删除(DELETE)
执行(EXECUTE)
显示视图(SHOW VIEW)
创建(CREATE)
修改(ALTER)
索引管理(INDEX)
删除(DROP)
创建临时表(CREATE TEMPORARY TABLES)
锁表(LOCK TABLES)
创建视图(CREATE VIEW)
事件(EVENT)
触发器(TRIGGER)
等等权限。
数据库连接配置
setting.py 中修改DATABASES:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'meiduo', # 数据库用户名
'PASSWORD': 'meiduo', # 数据库用户密码
'NAME': 'meiduo_mall' # 数据库名字
}
}
安装mysql客户端库,这里使用mysqlclient
,它包括C语音扩展,相较于纯python编写的pymysql
性能更高。
pip install mysqlclient
redis数据库配置
安装redis
pip install django-redis
会自动安装python redis客户端
配置redis
settings.py
# redis
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/0',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
},
'session': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
# 指定会话引擎
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# 指定会话缓存别名
SESSION_CACHE_ALIAS = "session"
# 根据您之前提供的配置,还可以设置会话的其他属性,例如:
# SESSION_COOKIE_AGE 用来设置cookie的过期时间,默认是两周。
# SESSION_SAVE_EVERY_REQUEST 如果设置为True,每次请求都会保存session信息,默认是False
# SESSION_EXPIRE_AT_BROWSER_CLOSE 如果设置为True,当浏览器关闭时session会结束,默认是False。
集成日志输出器
settings.py
LOGGING = {
'version': 1, # 日志配置的版本,目前必须是1。
'disable_existing_loggers': False, # 是否禁用Django默认创建的日志器。
'formatters': { # 定义日志信息的输出格式。
'verbose': { # 一个名为verbose的格式器。
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', # 输出格式。
'style': '{', # 使用新式的字符串格式化。
},
'simple': { # 一个名为simple的格式器。
'format': '{levelname} {message}', # 输出格式。
'style': '{', # 使用新式的字符串格式化。
},
},
'filters': { # 对日志进行过滤
'require_debug_true': { # django在debug模式下才输出日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 定义了如何处理日志记录。
'file': { # 一个名为file的处理器,用于将日志记录到文件。
'level': 'DEBUG', # 处理器处理的最低日志级别。
'class': 'logging.FileHandler', # 使用文件处理器类。
'filename': '/path/to/your/logs/django.log', # 日志文件的位置。
'formatter': 'verbose', # 使用上面定义的verbose格式器。
},
'console': { # 一个名为console的处理器,用于输出到控制台。
'level': 'DEBUG', # 处理器处理的最低日志级别。
'class': 'logging.StreamHandler', # 使用流处理器类。
'formatter': 'simple', # 使用上面定义的simple格式器。
'filters': ['require_debug_true'], # 用过滤器使只有在debug模式下才在控制台输出日志
},
},
'loggers': { # 定义日志记录器,指定日志的来源。
'django': { # Django自带的日志记录器。
'handlers': ['file', 'console'], # 指定该记录器使用的处理器。
'level': 'DEBUG', # 记录器记录的最低日志级别。
'propagate': True, # 是否将消息传递给更高级别(具有父子关系的)的记录器。
},
'django.request': { # Django用于捕获请求异常的记录器。
'handlers': ['file'], # 指定处理器。
'level': 'ERROR', # 记录级别。
'propagate': False, # 此记录器的日志消息不会被传递给更高级别的记录器。
},
# 为你的 DRF 应用程序添加自定义记录器的示例:
'myapp': {
'handlers': ['file', 'console'], # 同时输出到文件和控制台。
'level': 'DEBUG', # 记录的最低等级。
},
}
}
每个键的作用如下:
-
version
: 日志配置字典的版本,当前只支持版本1。 -
disable_existing_loggers
: 如果设置为True
,那么在配置LOGGING之前已经创建的日志器将会被禁用。 -
formatters
: 定义输出格式的字典。可以为每个记录器或处理器指定一个格式器。 -
filters
: 定义过滤器,可选。允许在日志记录发生前对其进行额外的处理,比如根据特定的条件判断是否要输出该条日志记录。 -
handlers
: 定义怎样处理(例如,输出、保存)日志记录的字典。每个处理器可以指定一个输出级别和一个格式器。 -
loggers
: 定义日志记录器字典,网制定哪些日志需要被记录,以及如何处理它们。
在配置日志时,可以选择不同级别的日志输出,常见等级(由低到高)如下:
-
DEBUG
: 详尽信息,通常只在诊断问题时产生。 -
INFO
: 证明事情按预期工作。 -
WARNING
: 表明发生了不期望的事或问题很快就会发生(例如‘磁盘空间低’)。该软件仍按预期工作。 -
ERROR
: 由于更严重的问题,软件无法执行某些功能。 -
CRITICAL
: 严重错误,表明程序本身可能无法继续运行。
自定义异常捕获
drf框架自带的异常捕获不包括数据库和redis,所以我们要通过自定义的方式加入mysql和redis的异常捕获。
在项目目录下创建utils文件夹,添加exceptions.py
文件
exceptions.py :
import logging
from django.db import DatabaseError
from redis.exceptions import RedisError
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
# 获取在配置文件中定义的logger, 用来记录日志
logger = logging.getLogger('django')
def exception_handler(exc, context):
"""
自定义异常处理方法
:param exc: 异常实例对象
:param context: 抛出异常的上下文(包含view、request等)
:return: Response对象
"""
# 调用drf框架原生的异常处理方法
response = drf_exception_handler(exc, context)
if response is not None:
view = context['view']
if isinstance(exc, DatabaseError):
# 数据库异常
logger.error(f"Database error in {view}: {exc}")
response = Response({'error': '数据库异常'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
elif isinstance(exc, RedisError):
# Redis异常
logger.error(f"Redis error in {view}: {exc}")
response = Response({'error': 'Redis异常'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
return response
settings.py:
REST_FRAMEWORK = {
# 异常处理
# 'EXCEPTION_HANDLER': 'your_project.your_app.module.exception_handler',
'EXCEPTION_HANDLER': 'meiduo_mall.utils.exceptions.exception_handler',
}
解决前后端跨域
跨域产生的原因-同源策略
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。
同源是指:协议相同、域名/IP相同、端口相同。
浏览器只阻止表单以及 ajax 请求,并不会阻止 src 请求,所以能访问CDN,图片等 src 请求。
使用CORS解决跨域问题
CORS,Cross-Origin Resource Sharing跨来源资源共享,是一个新的 W3C 标准,它新增的一组HTTP首部字段,允许服务端其声明哪些源站有权限访问哪些资源。换言之,它允许浏览器向声明了 CORS 的跨域服务器,发出 XMLHttpReuest 请求,从而克服 Ajax 只能同源使用的限制。在我们的django框架中就是利用CORS来解决跨域请求的问题。
安装配置django-cors-headers
安装
pip install django-cors-headers
settings.py 内进行配置
INSTALLED_APPS
INSTALLED_APPS = [
...
'corsheaders', # 跨域
...
]
MIDDLEWARE:
放到第一行,因为所有请求进行来都要先允许白名单访问,否则后面的程序都执行不到。
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 跨域
...
]
允许跨域请求追加白名单
新版本中使用CORS_ALLOWED_ORIGINS,老版本使用CORS_ORIGIN_WHITELIST ,目前两个都可以,建议选新的。
必须加http://或https://,否则会报错。
CORS_ALLOWED_ORIGINS = (
'http://127.0.0.1:8080',
'http://localhost:8080',
)
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
celery安装配置
Celery 是一个强大的分布式任务队列系统,它用于异步执行后台任务。当你有一些耗时的处理工作,比如发送电子邮件、生成报告、同步数据等,而你不想用户等待这些操作完成时,就可以使用 Celery 将这些任务放到后台异步处理。
下面是一些常见的 Celery 使用场景:
- 后台任务:长时间运行的任务,比如批量处理或计算密集型任务,可以在后台异步执行,提高前端响应时间。
- 定时任务:通过Celery的周期性任务调度,你可以设定定时任务,类似于Linux的cronjobs。
- 并行处理:可以在多个进程、线程或者机器中并行处理任务,提高效率。
- 微服务架构:在微服务架构中,可以用Celery在不同的服务间异步传递消息。
安装配置
安装celery
pip install celery
配置celery
在项目目录下创建celery_tasks python包
celery_tasks内创建config.py文件
# celery配置文件
# 指定任务队列的位置
broker_url = 'redis://127.0.0.1:6379/7'
# 启动时重试连接中间件的话
broker_connection_retry = True
broker_connection_retry_on_startup = True
celery_tasks内创建main.py文件
# celery启动文件
from celery import Celery
# 1. 创建 Celery 实例
celery_app = Celery('meiduo')
# 2.加载配置文件
celery_app.config_from_object('celery_tasks.config')
# 3.自动注册异步任务
celery_app.autodiscover_tasks(['celery_tasks.sms']) # celery_tasks.sms为自定义的任务
celery_tasks创建python包sms,这是一个发短信的任务,目录内创建tasks.py文件定义任务。
注意定义任务的文件名必须为tasks.py。
示例代码:
# 编辑异步任务代码
from celery_tasks.main import celery_app
@celery_app.task(name='sms_task')
def multiply(x, y):
return x * y
调用
#导包
from celery_tasks.sms.tasks import multiply
multiply.delay(4, 4) # 加delay()触发异步任务,multiply(4, 4)调用普通函数而已
启动任务
celery -A celery_tasks.main worker -l info # celery_tasks.main为要加载的模块
选择执行池
在Celery中,--pool
参数用于指定worker的执行池(execution pool),这决定了Celery将以何种方式处理并发任务。不同的pool类型会用不同的方式来处理并发执行任务,而这直接影响着性能和适用性。以下是一些常见的pool类型及其说明:
-
prefork(默认)
- Prefork pool使用预先分叉(fork)的工作进程来执行任务。
- 它适用于CPU密集型的任务和需要隔离的环境。
- 它是默认选项,不需要额外的配置即可使用。
- 在类Unix系统上表现良好,但不建议在Windows系统上使用,因为Windows不支持prefork模式的全功能。
-
solo
- Solo pool在主进程中直接运行任务,不创建任何子进程或线程。
- 这种方式适用于调试和开发环境,因为它能确保异常和调试信息都在同一个进程中输出,但不适合生产环境。
- 它通常不支持并发执行任务,任务会被串行处理。
-
eventlet
- Eventlet是一个基于协程的并发库,让你可以以非常轻量级的形式实现并发。
- Celery的eventlet pool通过协程来实现并发处理任务。
- 适用于I/O密集型任务,因为它利用协程在I/O等待时切换任务。
- 当使用eventlet时,任务能够以并发的方式执行,但它们实际上是在同一个进程中异步运行的。
-
gevent
- Gevent也是一个基于协程的并发库,类似于eventlet。
- 它实现了自己的高效事件循环,并且能够进行快速的上下文切换。
- gevent同样适合I/O密集型任务,并且在处理大量并发连接时性能出色。
-
threads
- 线程池利用多线程来处理并发任务。
- 对于I/O密集型的任务,线程池是一个不错的选择,特别是当与操作系统或某些库的线程支持相结合时。
在选择pool时,你需要根据你的任务类型、系统环境以及Celery版本来确定最合适的pool类型。例如,在Windows系统上由于不支持prefork
,推荐使用gevent
或eventlet
。对于生产环境,如果处理CPU密集型的任务,通常使用prefork
是更好的选择。如果是I/O密集型任务,可能会倾向于使用eventlet
或gevent
。
在命令行中指定--pool
参数来选择不同类型的pool,例如:
celery -A your_project worker -l info --pool=gevent
这个命令将启动一个使用gevent为pool的Celery worker。如果你不指定--pool
,Celery会使用默认的prefork
。
CPU密集型(CPU-bound)和I/O密集型(I/O-bound)是描述计算机程序运行特性的两个术语。它们主要反映了程序运行时资源消耗的差异,下面详细解释这两者的区别,并给出具体的例子:
CPU密集型
CPU密集型程序或任务是指需要进行大量计算,消耗大量CPU资源,且CPU计算能力通常是性能瓶颈的程序或任务。这类程序执行时CPU的利用率非常高,因为几乎所有的时间都在进行数学计算、逻辑判断等内存或CPU周期密集型的操作。
举例:
- 数字加密和解密:涉及大量的数学运算,尤其是在处理大键或复杂算法时。
- 视频编解码:转换视频格式或质量时,CPU需要对大量数据执行复杂的转换算法。
- 大数据分析:在分析大量数据时,比如进行数据挖掘或运行复杂的统计模型时。
- 科学计算:进行物理模拟、天气预测或生物信息学计算等。
I/O密集型(I/O-bound)
I/O密集型指的是程序或任务的瓶颈主要在于等待I/O操作完成,比如磁盘操作、网络请求等。这类程序执行时CPU利用率不会很高,因为CPU大部分时间都在等待数据的读写操作完成。实际上,I/O密集型程序的执行性能通常受限于系统的I/O能力,例如硬盘读写速度、网络带宽等。
举例:
- 文件处理:对磁盘上的文件进行读写操作,如日志处理、数据备份。
- 数据库操作:频繁的查询和更新数据库时,需要等待磁盘I/O和网络I/O。
- 网络应用:如Web服务器处理HTTP请求,通常需要在网络连接上进行大量数据的发送和接收。
- 客户服务系统:可能包括大量的客户端请求,涉及到对数据库的读取以及网络响应的等待。
在设计和优化系统时,我们需要根据所处理的是CPU密集型任务还是I/O密集型任务,选择合适的架构和资源配置。例如,对于CPU密集型任务,我们可能需要更强的CPU能力和适合的并行计算策略;而对于I/O密集型任务,则可能需要更快的存储设备和高效的I/O处理机制。
使用celery gevent 发送短信和邮件
步骤1: 安装所需的Python包
首先,确保你的环境中安装了celery
和gevent
。如果还未安装,可以通过pip进行安装:
pip install celery gevent
步骤2: 创建Celery实例
在你的项目中创建一个新的Python文件,例如tasks.py
,并在其中创建一个Celery实例:
from celery import Celery
app = Celery('my_tasks',
broker='你的消息代理地址,如: redis://localhost:6379/0',
backend='你的结果存储地址,如: redis://localhost:6379/0')
@app.task
def send_email(email_address, message):
# 这里模拟发送邮件的操作
print(f"发送邮件到 {email_address}: {message}")
return f"邮件已发送到 {email_address}"
步骤3: 配置Celery以使用gevent
为了让Celery使用gevent进行并发,你需要在启动worker时指定-P gevent
参数。此外,为了提高并发性能,你可以通过-c
参数指定并发worker的数量。这里的数量取决于你的具体任务和资源,可以进行适当的调整。
celery -A tasks worker -l info -P gevent -c 1000
这个命令会启动Celery worker,并将gevent作为并发池,设置并发worker数量为1000。你可以根据实际需求调整这个数量。
步骤4: 调用异步任务
现在,你可以在任何需要的地方调用定义好的异步任务了。以下是一个调用send_email
任务的例子:
from tasks import send_email
send_email.delay("example@example.com", "Hello, this is a test email.")
使用delay
方法会异步地发送任务到消息队列中,Celery的worker会捕获这个任务并使用gevent来并发执行。
注意事项
- 确保消息代理和结果存储(如Redis或RabbitMQ)已经正确设置并可以访问。
- 在高并发场景下,gevent的性能通常比较好,但是需要注意,IO操作(如访问网络或数据库)应该是非阻塞的;如果有阻塞调用,需要使用对应的gevent兼容库,否则并发性能可能会受到影响。
- 测试和调整并发worker的数量以适应你的具体应用场景。太高的并发数可能会导致资源竞争,太低则无法充分利用资源。
通过以上步骤,你就可以利用Celery和gevent实现高效的异步任务处理了。