Django通过celery 异步发送邮件 : django开发之天天生鲜项目知识总结【5】

这里初次学习celery,只简单讲解一下如何使用celery 异步发送邮件,在以后的总结中还会,多次提到celery,因为后面很多任务都需要用到celery执行任务,后面再专门针对celery做具体的总结:

点击这里,可以参看网上找到的文章,人家的笔记超详细

  • 这里展示一张我看视频老师的图片示例,通过图片先大致了解一下(理解很重要~~~~):
    在这里插入图片描述
  • 根据图示,我们知道,celery,是要有三部分实现的:

首先是 任务的‘发出者’, 然后接受任务的‘任务队列’作为中间人(broker), 其次是监听任务的‘处理者’(worker); 下面就具体说明到底谁来充当这几个,来完成具体任务。

  • 下面是从官网上面截取的图片,。大致了解一下什么叫做任务队列
    在这里插入图片描述
  • celery本身并没有提供 任务队列的功能,我们需要借用数据库:
    在这里插入图片描述
    这两种皆可以,我使用的是 redis数据库
  • 那么我们就用 reids数据库,作为我们的中间人,也就是broker。
  • 我们的项目代码就相当于是任务的发出者,当我们需要发送邮件时,就调用函数去往任务队列中,添加发送邮件的任务。
  • 那么处理就是我们的celery了

下面来说说每一步的具体实现过程

(1)任务的发出者

  • 首先先来在虚拟环境中下载celery
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple celery
  • 下一步,就像之前所说的,我们以后会经常使用celery来执行任务,所以,通常情况下,我们会在项目下建立一个目录,然后在里面新建文件,用来单独存放我们的任务。
    在这里插入图片描述
  • 接下来:开始完成建立的这个任务文件:直接上具体实现的代码~
from django.conf import settings
from django.core.mail import send_mail   # 导入这两个,是为了,完成发送邮件的任务,一个是需要的函数,一个是所需要从settings里面获取相关的参数
# 使用selery
from celery import Celery  

# 创建一个celery的实例对象
app = Celery('celery_tasks.tasks', broker='redis://192.168.113.132:6379/8')  # broker中间人,后面跟上数据库(redis)://ip地址端口号/使用地几个数据库  ,  ps aux | grep redis 查看开启的redis服务器, 第一个参数是任务文件的地址
# 定义任务函数(这里完成发邮件)

@app.task    # 加上这个装饰,才可以,后面讲加这个装饰的作用。
def send_register_active_email(to_eamil, username, token):
    """发送激活邮件"""

    # 组织邮件信息, 这部分上一节也讲过了,不懂可以回头看哦~
    subject = '天天生鲜欢迎信息'
    # 邮件的正文,当发出的内容中含有html标签的时候,不能在使用 message 这个参数传递,因为不会解析 标签,要使用 html_message,我上一节讲到了这个知识点
    # message = '<h1>%s, 欢迎你成为天天生鲜注册会员</h1>请点击下方链接激活你的账户<br/><a href="http://127.0.0.1/user/active/%s">http://127.0.0.1/user/active/%s</a>'%(username, token, token)
    message = ''  # 没有内容的时候可以指定为空
    html_message = '<h1>%s, 欢迎你成为天天生鲜注册会员</h1>请点击下方链接激活你的账户<br/><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>' % (
    username, token, token)

    # 发件人
    sender = settings.EMAIL_FROM
    # 收件人,是一个列表,可以发送给多人
    receiver = [to_email]

    send_mail(subject, message, sender, receiver, html_message=html_message)
  • 下面就开始设置我们views.py里面的视图,让它通过celery去发送任务
  • 导入我们的任务函数
from celery_tasks.tasks import send_register_active_email

....此处省略代码,文章结尾给出所有代码

# 使用selery,帮助发送邮件
        send_register_active_email.delay(email, username, token)   # 通过app.task 装饰,就具有这个方法,使用这个函数,把任务放入任务队列
  • 给出这个views.py里面发送 邮件类 全部代码:
from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse  # 使用反向解析
from user.models import User
from django.views.generic import View
from django.conf import settings
import re

from celery_tasks.tasks import send_register_active_email
# 导入用来实现加密的类
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired  # 异常捕获
from django.http import HttpResponse

# 导入发邮件函数
from django.core.mail import send_mail

# Create your views here.


class RegisterView(View):
    """注册类"""

    def get(self, request):
        """显示注册页面"""
        return render(request, 'register.html')

    def post(self, request):
        """进行注册处理"""
        # 进行注册请求
        # 1. 接受数据(参数)
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')  # 判断用户是否同意使用协议

        # 2.进行数据的校验(在这里验证是否传递了所需要的三个参数,校验完整性)
        if not all([username, password, email]):
            """all()方法,传递的参数是可迭代的东西,对里面的每一个元素进行判断,如果都为真的时候all()函数才会返回真"""
            # 如果不正确,就在返回登陆页面,带上错误信息。
            return render(request, 'register.html', {'errmsg': '数据不完整'})

        # 检验邮箱
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return render(request, 'register.html', {'errmsg': '邮箱格式不正确'})

        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)  #
        except User.DoesNotExist:
            # 抛出异常说明用户名不存在,
            user = None

        if user:
            # 用户名已存在
            return render(request, 'register.html', {'errmsg': '用户名已存在'})

        # 因为我们是继承使用的django 内置的认证系统,所以我们不需要向上面那样去做
        # 调用 create_user() 方法
        user = User.objects.create_user(username, email, password)
        # df_user 里面有一个字段 is_active,默认为1,表示激活,我们需要修改它为0
        user.is_active = 0
        user.save()

        # 发送激活邮件,包含激活链接:http://127.0.0.1:8000/user/active/1(1就是注册的用户id)
        # 激活链接中需要包含用户的身份信息:并且要将身份信息加密(防止某些人看穿规律,肆意伪造链接访问)

        # 加密用户的身份信息,生成激活的token
        serializer = Serializer(settings.SECRET_KEY, 3600)
        info = {'confirm': user.id}
        token = serializer.dumps(info)   # 显示的是 b'' 类型数据, 也就是 bytes类型数据,我们把它转换为字符串
        token = token.decode()   # 默认按照utf-8进行解码,变成字符串
        # 使用selery,帮助发送邮件
        send_register_active_email.delay(email, username, token)   # 通过app.task 装饰,就具有这个方法,使用这个函数,把任务放入任务队列

        # 4.返回应答,跳转到首页
        return redirect(reverse('goods:index')) 

额~~上面完成了 发送者和中间人(中间人就是配置的redis)了。。那么下面就说处理者吧。

  • 需要注意点是

  • (1)任务的发出者, 中间人, 任务的处理者,可以在同一台电脑上面启动, 也可以不在同一台电脑上。

  • (2)处理者也需要任务的代码!我们需要将项目代码复制一份。

  • 我们复制一份程序的代码到桌面(我用的是ubantu)
    在这里插入图片描述

  • 然后打开终端进入到目录里面:这里要注意:

  • 启动worker ,也是需要我们的环境中安装了celery.所以进入虚拟环境(我再次虚拟环境中安装了celery,或者直接进入项目使用的虚拟环境都行,主要是必须有celery)
    在这里插入图片描述

  • 下面就可以执行命令,启动我们的处理者(worker),监听处理任务了。

celery -A celery_tasks.tasks worker -l info
# 参数解释 
-A 后面,我们要指定,创建的任务app,在哪个文件里面
-l info 收到任务时会打印出来一些相应的信息,我们可以设置信息的级别,-l info 表示把提示信息显示出来。
  • 下面就是启动成功之后显示的一些信息:
  • 解释一下
1.app: 对应的内容就是我们创建celery类对象,写的第一部分地址参数,我这里再把它写一遍,以供参考:
app = Celery('celery_tasks.tasks', broker='redis://192.168.113.132:6379/8')  # broker中间人,后面跟上数据库(redis)://ip地址端口号/使用地几个数据库  ,  ps aux | grep redis 查看开启的redis服务器

2.transport: 对应的就是第二个参数,对应着我们的中间人

3. concurrency:  就是代表你worker进程的数量

4 [tasks]:   在启动worker时,它知道你这里面有这个 发送邮件的任务函数

5.注意下面四条带有日志时间的提示信息,很重要,他说明你成功连如监听你的中间人(redis),若没有出现就会报错:

若没有出现就会报错:
在这里插入图片描述
解决办法就是,打开你的redis服务,就好,并且连接的地址和端口设置正确

  • 我的启动 和查看启动(我之前的文章,将结果配置,启动服务器)在这里插入图片描述
  • 之后,就可以开启我们项目服务了
python manage.py runserver
  • 之后进行访问登录注册网址
    在这里插入图片描述
  • 成功进去之后就会之后,看到终端中的反映:
    在这里插入图片描述
    先不管红色字体,下面会讲,看到黄色框中的东西,就说明成功监控到任务并且执行了!!
    在这里我要特别提一下,当你的代码项目代码有问题时,这里会报错可以找到对应的问题解决,但有时候并不是你的原因!!而是对应celery版本不行,它自身的原因!!因为我使用的是 1.8.2版本的django,比较古老了,最开始下载最新的4.3版本celery表示不适配,我的django版本过低~~,然后我换了一个3.1版本的,一运行就报错。。。。找了好久,都以为是我的代码的问题,结果回头看老师的视频,老师使用的是4.1.0版本的celery!!所以,问题出在还是处在版本上面,下面就更奇怪了。。。我换了4.1.0版本的还是报错。。。但是老师也是1.8.2版本的django就可以运行。。所以我很纳闷呀。。。想了好久,还是感觉是版本的问题,坚信自己的代码没问题!!(哈哈),结果在多次尝试之后,下载了celery4.2.0版本!!!,成功运行!!!得出和老师一样的结果! 所以就是要说,遇到问题一定要思路清晰,找对角度,报错不一定都是你代码的问题,注意根据自己的django下载对应的版本~~~ 就说这些吧~~
  • 下面我们再来仔细分析红色字体的报错:注意力集中在这一句:
    在这里插入图片描述
    原因就在于,我们启动worker项目的时候,并没有启动django项目(python manage.py runserver)!!,我们的任务本身需要使用一些django本身的配置项,这些配置项它是依赖于你需要先对Django的环境变量做一些初始化,没有初始化,用不了,就会报错误了!
  • 下面就来解决这个问题:我们需要更改任务文件里面的代码,让它能够进行初始化。
    在这里插入图片描述
  • 下载我们要手动去实现它:在tasks.py文件中(上面写任务函数的文件中),加上
# 在任务处理者一端加这个
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()  # 初始化django

这样就完成了!!

  • 接下来重新启动 worker,会有警告:
    在这里插入图片描述
    意思是我们的settings.DEBUG设置为True,他可能造成内存的泄露这句不是错误,不用管他~因为我们现在就是出于来发模式,要看到运行报错,正式上架产品之后,就会关掉调试模式。

  • 下面就到了再次注册用户测试了!!
    在这里插入图片描述
    成功登陆!!并发送邮件,要注意,修改代码之后,必须重新启动worker。

好了,到此就差不多结束了!谢谢~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值