大家好,这是皮爷给大家带来的最新的学习Python能干啥?之Django教程的进阶版。
在之前《用Django全栈开发》系列专辑里面,皮爷详细的阐述了如何编写一个完整的网站,具体效果可以在代码中获取到。
从进阶篇开始,每一篇文章都是干货满满,干的不行。这一节,我们来说:如何使用Django + Celery + Flower来实现耗时操作编程异步,并且能够在线实时监控。
不吹不黑,这篇文章是全网写的最详细的Celery+Django+Flower的文章。
获取整套教程源码唯一途径,关注『皮爷撸码』,回复『peekpa.com』
皮爷的每一篇文章,都配置相对应的代码。这篇文章的代码对应的Tag是“Advanced_06”。
可能有同学会问,啥是耗时操作?这么的打个比方:
比如,我们每天访问Peekpa网站的数据中心,看到很多漂亮的小姐姐。突然有一天,皮爷给大家推出了一个『一键发送种子』功能。这个发送邮件的功能,其实对于后台来说就是一个耗时操作。
我们这里就拿Github线上的Peekpa代码给大家做一下例子。我们要实现的操作就是要把日本最近的10条地震信息发送给指定的邮箱。
那么在准备耗时操作之前,我们需要准备一下如何让Django发送邮件。
首先,如果要发送邮件,我们需要注册一个邮箱账号,126,163和QQ邮箱都可以,我们主要使用的是邮箱的SMTP服务。
我们这里以126邮箱为例。
首先注册一个126邮箱账户,请记住邮箱账号和密码。然后登陆到邮箱里面,我们找到设置
选项:
看到关于POP3/SMTP/IMAP
这个选项,其实我们的主要目标就是SMTP
服务。所以打开这个选项,去页面选择开启SMTP服务:
在这里,不同的邮件系统可能开通流程不太一样,126的开通流程就是需要用手机APP扫描开通,不管怎么样,开通了SMTP服务就可以了。像上图一样,显示的是开通了服务。
接下来,我们就要确认各个邮件商的SMTP服务地址了,这里皮爷给大家稍微整理了一下,如果没有你注册的邮件的SMTP服务器地址,那就需要自己百度:
SMTP服务器 | 端口 |
---|---|
smtp.126.com | 465 |
smtp.qq.com | 465/587 |
smtp.163.com | 465/994 |
这样准备工作就做完了。我以126邮箱为例,到目前需要记住的有以下内容:
接下来,我们要做的就是在Django中配置发邮件的内容了。
Django框架默认是集成了发送邮件功能的。路径是django.core.mail
,我们可以直接导入这个路径下的send_mail()
方法,直接调动即可完成发送功能。
我们进入源码里面可以看一下send_mail()
方法:
def send_mail(subject, message, from_email, recipient_list,
fail_silently=False, auth_user=None, auth_password=None,
connection=None, html_message=None):
"""
Easy wrapper for sending a single message to a recipient list. All members
of the recipient list will see the other recipients in the 'To' field.
If auth_user is None, use the EMAIL_HOST_USER setting.
If auth_password is None, use the EMAIL_HOST_PASSWORD setting.
Note: The API for this method is frozen. New code wanting to extend the
functionality should use the EmailMessage class directly.
"""
可以看到,这里传入的参数有一个recipient_list
,当Django调用这个方法发送完邮件之后,收件人是能看到其他收件人的邮箱,相当于是一起发送的。这个方法是封装好的方法,如果要使用自定义的,这里说应该直接使用EmailMessage
类就好,这个EmailMessage
类的路径是django.core.mail
里。
这里我们就方便讲解,直接给大家调用send_mail()
方法来说。
在发送邮件之前,我们可以简单的在peekpa/settings.py
里面这是这么几个参数:
EMAIL_HOST = "smtp.126.com" # 发送邮件的smtp服务器(从QQ邮箱中取得)
EMAIL_HOST_USER = "[email protected]" # 用于登录smtp服务器的用户名,也就是发送者的邮箱
EMAIL_HOST_PASSWORD = "xxxxxxxx" # 授权码,和用户名user一起,用于登录smtp, 非邮箱密码
EMAIL_PORT = 465 # smtp服务器SSL端口号,默认是465
EMAIL_USE_SSL = True
这几个参数对应的意思:
EMAIL_HOST
:这个就是之前上文提到的那个表格中的SMTP服务器地址,可以填写对应邮箱的地址;EMAIL_HOST_USER
:这个是刚才申请的开通SMTP服务的邮箱地址;EMAIL_HOST_PASSWORD
:在126这里,这个是登录密码,但是在QQ那里,在开通SMTP服务的时候,会让你再输入一个授权密码;EMAIL_PORT
:这个端口号一般填写SMTP服务的SSL端口号,因为非SSL服务,可能会在服务器上面跑不通,所以,加上SSL没错,值在上文提到的表格找对应的邮箱服务SSL端口号就可以;EMAIL_USE_SSL
:填写True,表示开启SSL服务;当你配置好之后,我们简单的在网页上面实现一下,将每个地震信息下面都配置一个按钮,点击按钮就会发送地震的详细信息到指定的邮箱:
每个按钮给配置一个URL,负责点击事件并且发送邮件。这里就不具体的展开如何写一个URL的视图函数了,只是给大家简单的罗列几点内容:
url的格式为:jpearth/Send/
。
我们这里打算发送的邮件为HTML格式的邮件,发送Email的函数如下:
def send_jpearch_email(self, item):
title = "这是一封来自Peekpa.com的邮件"
bodyhtml = '' + \
'日本实时地震报告: '
+ \
'地点:+ item['jp_url'] + '">' + item['jp_location'] + '' + \
'震级:+ item['jp_url'] + '">' + item['jp_level'] + '' + \
'' + \
'ID:'
+ item['jp_id'] + '' + \
'位置:
+
item['jp_location_image_url'] + '"/>' + \
'时间:+
item['jp_url'] + '">' + item['jp_title'] + '' + \
'强度:+
item['jp_url'] + '">' + item['jp_max_level'] + '' + \
' 点击上面的任意链接即可跳转到『日本气象厅』网站查看详情
' + \
''
send_mail(
title,
"this is message", # 如果没有HTML的内容,只是纯文字的,这里就是邮件的内容
'[email protected]', # settings.py 中设置的发件人邮箱
['[email protected]'], # 收件人邮箱
fail_silently=False,
html_message=bodyhtml # 如果是HTML格式,这里填写html格式的邮件内容
)
当发送完邮件之后,我们还会返回到JpEarth的list页面。
这里我们来直接测试一下,看看发送一个邮件需要多久的网页访问时间:
看到耗时大概1.4秒左右。这只是个很简单的发送邮件,就要耗时这么久。我们再到邮箱里检查一下:
我们的HTML邮件长这个样子,看着还可以。
这样,我们的耗时操作就产生了,发送邮件这么耗时。接下来,我们讲解如何使用Celery来让耗时操作异步处理。
首先通过pip安装Celery:
pip3 install celery==4.4.4
接着我们配置Celery。首先需要在Peekpa/settings.py
文件同级的文件夹,创建一个celery.py
文件:
这个文件里面如下配置:
from __future__ import absolute_import
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Peekpa.settings')
app = Celery('peekpa')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
然后,需要在Peekpa/__init__.py
文件中填入一下内容:
from __future__ import absolute_import, unicode_literals
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ['celery_app']
Celery还需要设置一个Brokers的东西,这个东西其实就起到一个队列的作用,一般Celery支持的Brokers有这么几种:
可以看到,这里有我们上篇文章说到的Redis!Redis!快速的Redis。
所以,我们直接拿Redis来作为我们的Borkers。但是需要设置。设置方法需要在Peekpa/settings.py
文件里配置:
# CELERY
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
# CELERY_BEAT_SCHEDULE = {}
接着,我们在datacenter
目录下,创建一个tasks.py
文件
我们把之前的发送Email的方法搬到这个文件里面,并且加一个@task()
注释:
from __future__ import absolute_import, unicode_literals
from celery import task
from django.core.mail import send_mail
@task()
def send_peekpa_email(item):
title = "这是一封来自Peekpa.com的邮件"
bodyhtml = 'xxxxx'
send_mail(
title,
"this is message",
'[email protected]',
['[email protected]'],
fail_silently=False,
html_message=bodyhtml
)
只有加了@task()
注释的方法,才会被Celery发现,运行的时候才会被扔到Borker里面。
所以,这个时候我们修改一下之前的发送视图函数,用send_peekpa_email.delay(jp_item)
替换掉之前的发送邮件方法。
注意,这里需要加delay,否则还是同步方法。
这样,我们的Celery就准备好了。
如果要Celery,需要同时启动celery beat
和celery worker
这两个。我们这里对应上面配置的项目,启动命令分别如下:
# 启动celery worker
$ celery worker -A Peekpa --loglevel=INFO
# 启动celery beat
$ celery beat -A Peekpa --loglevel=INFO
我们分别用两个Terminal启动这个两个命令。注意一下前提:需要提前启动好本地的Redis,需要提前启动好本地的Redis,需要提前启动好本地的Redis。启动完之后是这个样子:
这个时候,我们再去页面里面发送邮件,看看这回用时多少:
看到只用时85毫秒,而且之后邮箱里面也收到了邮件。是不是非常的爽??
至此,我们就把如何使用Celery异步的处理费事操作说完了。
当然,Celery还可以用来做定时器,就是让Django在一定规律的时间之内执行一段代码,比如每天晚上7点来执行检查任务,将今天爬虫爬下来多少数据统计一下,然后发送到自己的邮箱里。具体的做法很简单。
首先,在tasks.py
文件里面,还是写好方法,用@task()
来给方法加注解。
然后需要在settings.py
文件里面,我们之前提到有个变量CELERY_BEAT_SCHEDULE = {}
, 这里面的写法,可以参考以下:
from datetime import timedelta
CELERY_BEAT_SCHEDULE = {
'webspider_start_jp_earch': {
'task': 'apps.basefunction.tasks.webspider_start_hot_movie',
'schedule': timedelta(hours=1)
},
'send_peekpa_email': {
'task': 'apps.basefunction.tasks.send_peekpa_email',
'schedule': crontab(hour="0-23/6")
},
}
这里面,hot movie的爬虫
,是每一个小时运行一次,发送邮件
,则是每6个小时运行一次。启动方式还是和之前的启动一样,同时运行celery worker
和celer beat
。
既然我们的异步任务能够用Celery执行,我们可以试用Flower来实现在线监控我们的Celery任务。
首先,安装Flower:
pip3 install flower==0.9.5
然后,启动Flower之前,首先启动Redis,Celery,然后才启动Flower。
启动方法是,在项目目录下:
$ flower -A Peekpa --port=5555
中间的是项目名,和Celery中的一样,然后端口号我们随便设置,这里是5555,接着我们去浏览器里面看一下效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ltQCFH9H-1595953995562)(https://upload-images.jianshu.io/upload_images/19310624-70bd895219607144.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
可以看到,我这里在本地是每10秒打印一句“『皮爷撸码』这个号太干了”:
可以看到上面在Flower的控制台里面,能够看到每一个Celery的执行情况。是不是非常的方便???
真的,说一句心里话,这篇文章,是真的太干了。
项目写到这里,越来越复杂,光启动项目,就得一句这个命令,一句那个命令,今天启动两个东西,就得要三条命令。这么多命令,部署上线了记不住咋整,别慌,这些东西,其实都可以交给supervisor来做。我们这里就将启动celery两条命令,写到peekpa_supervisor.conf
文件中:
[program:ScheduleWork]
command = celery worker -A Peekpa --loglevel=INFO
directory = /home/centos/PeekpaCom
startsecs=5
stopwaitsecs = 60
autostart=true
autorestart = true
[program:ScheduleWorkBeat]
command = celery beat -A Peekpa --loglevel=INFO
directory = /home/centos/PeekpaCom
startsecs=15
stopwaitsecs = 60
autostart=true
autorestart = true
成功启动Supervisor之后,我们看到的控制界面就是这样:
具体的这个配置文件怎么写的,我都在整套教程的代码里面有,获取方式见文章最后。
最后总结一下,
在Django + Celery + Flower实现异步在线管理:
Peekpa/settings.py
文件同级的目录,创建celery.py
文件,然后在同级的__init__.py
文件中,填写一下配置信息;Peekpa/settings.py
文件中配置相关参数;tasks.py
文件,然后将方法写进去,同时,方法需要@task()
注解;delay()
方法;获取整套教程源码唯一途径,关注『皮爷撸码』,回复『peekpa.com』
长按下图二维码关注,如文章对你有启发或者能够帮助到你,欢迎点赞,在看,转发三连走一发,这是对我原创内容输出的最大肯定。