最近用django一个网上商城项目的时候用两个扩展,感觉还不错,所以在此记录一下。
首先来说下celery,celery是一个处理异步任务的框架,需要下载celery包,一般在项目需要进行耗时操作的时候(如使用第三方工具给用户发送短信验证码),可以交给celery来处理,这样后端可以直接返回成功,增加用户体验。由于celery跟业务逻辑没有什么关联,一般选择建立一个独立的包进行存放。
先来说一下celery的标准操作流程。首先在对应的包下建立一个main.py作为启动文件,在该文件内导入Celery对象,由于celery是独立的,如果需要引用django的配置,需要自己设置(一般可能会用到django的日志配置)。接着说celery,首先建立一个celery对象,然后通过对象的config_from_object()方法导入celery的配置,参数为文件名或类名的字符串,可以写一个类,也可以写一个py文件来存放配置,配置只需填写broker_url = "redis//127.0.0.1/14",通过redis数据库储存celery的相应配置,配置部分我未深入研究,只求能使用即可。由于main.py只是启动文件,所以任务不会放在该文件夹,而要让celery找到任务,需要使用celery对象autodiscover_tasks()方法,参数为一个列表,列表内元素为任务名的字符串,而对应的任务,我们一般会建立一个包,在包下的tasks.py文件下存放,而tasks一般不需要填。而要让具体的任务和celery关联起来,只需要任务函数上加上一个celery对象.task()装饰器即可,参数为name,一般为函数名的字符串。好了,接下来讲讲怎么在业务逻辑中去使用,celery是一个框架,所以你需要启动它,让他来监听任务,启动命令为celery -A main文件路径 worker -l info,在视图中需要使用celery时,直接导入对应的任务,调用任务的delay()方法即可,而任务函数需要填写的函数填写导delay中即可。
实例代码如下,main.py
from celery import Celery # 为celery使用django配置文件进行设置 import os if not os.getenv('DJANGO_SETTINGS_MODULE'): os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev' # 创建celery应用 app = Celery('meiduo') # 导入celery配置 app.config_from_object('celery_tasks.config') # 自动注册celery任务 app.autodiscover_tasks(['celery_tasks.sms'])
对应的任务包下的tasks.py
import logging from celery_tasks.main import app from .yuntongxun.sms import CCP logger = logging.getLogger("django") # 验证码短信模板 SMS_CODE_TEMP_ID = 1 @app.task(name='send_sms_code') def send_sms_code(mobile, code, expires): """ 发送短信验证码 :param mobile: 手机号 :param code: 验证码 :param expires: 有效期 :return: None """ try: ccp = CCP() result = ccp.send_template_sms(mobile, [code, expires], SMS_CODE_TEMP_ID) except Exception as e: logger.error("发送验证码短信[异常][ mobile: %s, message: %s ]" % (mobile, e)) else: if result == 0: logger.info("发送验证码短信[正常][ mobile: %s ]" % mobile) else: logger.warning("发送验证码短信[失败][ mobile: %s ]" % mobile)
对应的视图函数
from celery_tasks.sms import tasks as sms_tasks class SMSCodeView(GenericAPIView): ... # 发送短信验证码 sms_code_expires = str(constants.SMS_CODE_REDIS_EXPIRES // 60) sms_tasks.send_sms_code.delay(mobile, sms_code, sms_code_expires) return Response({"message": "OK"})