本文讲举一个用户注册发邮件用于激活的例子

1.django默认支持邮件发送

django中django.core.mail模块中有send_mail方法是用来发送邮件使用的,但是不是简单的调用方法就可以发送的,需要借助于第三方的邮件代理服务器,例如126,163等,登上163邮件,在设置里面找到SMTP服务器: smtp.163.com,并生成授权登陆客户端的密码,然后在settings文件中配置

# Email配置

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'  # 发送邮件的程序
EMAIL_HOST = 'smtp.163.com'  # 邮件代理服务器地址
EMAIL_PORT = 25  # 代理服务器端口号 应用层协议 端口号25 固定
EMAIL_HOST_USER = '你的163账号'  # 发送人 发送邮件的账号
EMAIL_HOST_PASSWORD = '客户端授权码,不是登陆密码"  # 生成的客户端授权密码 开启,163邮箱设置选项中
EMAIL_FROM = '用户激活<你的163账号>'  # 显示的发送人信息

2.注册流程和celery异步任务处理流程简述

先来看下用户注册流程,用户提交表单数据,保存数据到数据库,这个时候is_active字典是0,表示邮件没有激活,之后,应该发送邮件,让用户点击激活,但是邮件发送默认是阻塞行为,也就是没有发送成功,程序不会继续往下执行,什么时候推送到代理邮件服务器,什么时候才会有返回值,可能因为网络延迟等问题,让程序停下来,一来用户体验不好,二来这也不是我们想要的,我们想要让发送邮件和下面程序不互相干扰,即我只管发送,成功不成功我不管,继续往下执行,那么我们就需要引入一个异步任务处理的的工具来帮我处理,celery就是一个非常常用和好用,强大,灵活的异步任务处理工具,我们只需要把这个发送邮件的任务交给celery来处理,celery是一个独立的工具,跟Python没有什么关系,跟任何语言都可以结合。

完成异步任务,从角色进行考虑 ,首先是客户端,发布任务,谁提出来的任务谁就是客户端,执行任务的人叫worker。

客户端和celery进行任务传输的中间,celery要求要找一个中间人,你把任务信息交给中间人(broker),celery从中间人这里,取出任务来完成要处理的任务

客户端把任务的名字交给broker,继续执行下面的代码,celery有一个看管的人,去任务队列里面去取任务,celery中也需要任务代码,注意,客户端和celery不一定在一台机器

celery在worker进行设置,默认支持多进程,进程池也可以,协程,gevent,greenletbroker也不是celery实现的,但是官方有推荐,扮演这个角色有哪些,RabbitMQ message queue 消息队列,redis 内存型数据库,存取非常快

客户端发送一个任务,到broker里面,worker去brokder里面去取任务,发送任务的一方并不会关心

什么时候可以完成任务,这是最简单的一个模型

但是有些时候,我现在不需要处理结果但是后面的程序会的到,这个时候我如何在想知道结果的时候还能拿到结果呢 所以现在需要第四方,第四方叫backend
可配置可不配置,backend专门用来存放结果,这个时候需要数据库,对于性能没有要求,celery对backend没有具体推荐,加了backend,celery把处理结果保存到backend里面,如果客户端需要,就去
backend里面去取.

客户端发送任务开启:from tasks import my_task,my_task.delay() 发送任务

worker端开启的方式:celery -A【代表应用app对象】 tasks【任务】 worker --level=info [提示,错误信息以什么样的,级别来显示

celery机制就像生产者消费者模型一样,生产者消费者是一个广义的模型

3.项目代码结构

4.代码,关于itsdangerous生成签名的使用请看上一篇博客

项目下的urls.py 

from django.conf.urls import url,include
from django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^', include("test_app.urls")),
]

应用下的urls.py

from django.conf.urls import url
from . import viewsurlpatterns = [url(r'^register$', views.RegisterView.as_view()),url(r'^$', views.IndexView.as_view()),url(r'^active/(?P<token>.+)$', views.ActiveView.as_view()),
]

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.views.generic import View
from celery_tasks.tasks import send_active_mail
from .models import User
from django import db
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, SignatureExpired
from django.conf import settingsclass IndexView(View):def get(self, request):return render(request, "index.html")class RegisterView(View):"""用户注册"""def get(self, request):"""处理get请求, 提供注册页面"""return render(request, "register.html")def post(self, request):"""处理post请求,处理注册数据"""# 获取前端发送的数据/参数name = request.POST.get("name")password = request.POST.get("pass")email = request.POST.get("email")# 使用django的认证系统创建用户try:user = User.objects.create_user(name, email, password)except db.IntegrityError:# 如果抛出此异常,表示用户已经注册return render(request, "register.html", {"errmsg": "用户已注册!"})# 将用户的激活状态设置为假
user.is_active = Falseuser.save()# 生成激活tokentoken = user.generate_active_token()# 使用celery发送邮件
        send_active_mail.delay(email, name, token)# 返回给前端结果return render(request, "index.html")
# 激活用户
class ActiveView(View):def get(self, request, token):# 根据token 解析,获取用户的id# 创建转换工具(序列化器)s = Serializer(settings.SECRET_KEY, 3600)# 解析try:ret = s.loads(token)except SignatureExpired:# 如果出现异常,表示token过期,返回信息给用户return HttpResponse("激活链接已过期")# 更新用户在数据库中的激活状态user_id = ret.get("confirm")# 查询数据库try:user = User.objects.get(id=user_id)except User.DoesNotExist:# 用户不存在return HttpResponse("用户不存在")user.is_active = True  # 更改用户激活状态
        user.save()# 返回信息给用户return render(request, "actived.html")

models.py itsdangerous序列化的使用,请看上篇博文

注册数据 保存数据库 生成token 发送邮件
激活:获取token 设置用户的激活状态

把id放入token中 叫签名 因为还可以反推回去

每建立一个django项目,会生成一个很复杂的混淆字符串叫SECRET_KEY

django进行密码加密的时候,除了盐值,通常把这个混淆字符串也加进入了,
盐值+SECRET_KEY+SHA256 才生成一个密码

(,有效期)秒为单位,过期时间

生成token方法和用户对象紧密关联,放入User模型类中

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from utils.models import BaseModelclass User(AbstractUser, BaseModel):"""用户"""class Meta:db_table = "users"def generate_active_token(self):"""生成激活令牌"""serializer = Serializer(settings.SECRET_KEY, 3600)token = serializer.dumps({"confirm": self.id})  # 返回bytes类型return token.decode()

celery_tasks下面的tasks.py

注意:

# os.environ["DJANGO_SETTINGS_MODULE"] = "active_mail.settings"

# import django

# django.setup()

celery在启动的时候没有和Django挂钩,虽然这个项目在django目录中的,但是它是用celery启动的,所以他不知道django中的详细配置信息,
因为celery在运行的时候离不开django的环境,所以在celery运行的时候要补充上Django的环境,在celery运行的文件里补充,即任务的文件,

我们希望在启动这个任务的时候把django的所有环境搭建完成,
我们需要给celery运行的机器中设置环境变量,celery寻找信息的时候,按照固定的模式去询问,
os.environ["DJANGO_SETTINGS_MODULE"]="active_mail.settings" 只是在操作系统的环境变量中设置进去了
django,要想运行,需要import django
djagno.setup() 就会去os.environ中找到配置文件,加载所依赖的环境什么是环境变量,操作系统也是一段程序,他运行的时候保存的一些数据就叫环境变量

# coding=utf-8
import osos.environ["DJANGO_SETTINGS_MODULE"] = "active_mail.settings"
# import django
# django.setup()
from django.core.mail import send_mail
from celery import Celery
from django.conf import settings# 1,创建一个celery对象应用
app = Celery("celery_tasks.tasks", broker="redis://127.0.0.1/6")# 通过使用装饰器,让celery对这个任务进行管理
@app.task
def send_active_mail(to_email, user_name, token):subject = "用户激活" # 主题sender = settings.EMAIL_FROM  # 发件人receiver = [to_email]  # 接收人html_body = '<h1>尊敬的用户 %s, 感谢您注册xx科技!</h1>' \'<br/><p>请点击此链接激活您的帐号<a href="http://127.0.0.1:8000/active/%s">' \'http://127.0.0.1:8000/active/%s<a></p>' % (user_name, token, token)send_mail(subject, "", sender, receiver, html_message=html_body)

utils下面的models.py

from django.db import modelsclass BaseModel(models.Model):"""为模型类补充字段"""create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")class Meta:abstract = True  # 说明是抽象模型类

settings.py

"""
Django settings for test11 project.Generated by 'django-admin startproject' using Django 1.11.7.For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""import os# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '%m3xt+#4+m1e@#+fmbuk9*38#=s@u0cy0ub&)12x^z*21rhe$t'# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = TrueALLOWED_HOSTS = []# Application definition

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','test_app',
]MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]ROOT_URLCONF = 'test11.urls'TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR, 'templates')],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]WSGI_APPLICATION = 'test11.wsgi.application'# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','HOST': '127.0.0.1','PORT': 3306,'USER': 'root','PASSWORD': 'mysql','NAME': 'mail'}
}# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
]AUTH_USER_MODEL = "test_app.User"
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'TIME_ZONE = 'UTC'USE_I18N = TrueUSE_L10N = TrueUSE_TZ = True# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
#
# Email配置

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'  # 发送邮件的程序
EMAIL_HOST = 'smtp.163.com'  # 邮件代理服务器地址
EMAIL_PORT = 25  # 代理服务器端口号
EMAIL_HOST_USER = '你的163邮箱账号'  # 发送人
EMAIL_HOST_PASSWORD = '生成的客户端授权码'  # 生成的客户端授权密码
EMAIL_FROM = '用户激活<你的163账号>'  # 显示的发送人信息

 index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>这是index</h1>
</body>
</html>

register.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="register" method="post">{% csrf_token %}<input type="text" name="name"><input type="password" name="pass"><input type="text" name="email"><input type="submit" value="注册">
</form>
</body>
</html>

actived.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>已经激活</h1>
</body>
</html>

5.测试

启动django项目,启动celery,拷贝一份项目代码,在本机其他地方,当然可以是其他机器,cd test11中,使用 celery -A celery_tasks.tasks worker -l info启动

在浏览器中输入http://127.0.0.1:8000/register,填写信息注册,这个时候,mysql数据库中用户表中刚注册的用户is_active字段是0,即False,并且,你注册的邮箱会收到邮件,点击网址,用户激活,再看mysql,发现is_active

变为1,即激活

django发送邮件结合itsdangerous+celery+redis相关推荐

  1. Django项目实战——8—(判断用户是否登录并返回JSON、Django发送邮件的配置、生成邮箱验证链接、验证邮箱后端逻辑)

    1.判断用户是否登录并返回JSON 重要提示: 只有用户登录时才能让其绑定邮箱. 此时前后端交互的数据类型是JSON,所以需要判断用户是否登录并返回JSON给用户. 方案一: 使用Django用户认证 ...

  2. Django 发送邮件

    Django 发送邮件 在settings.py中设置 EMAIL_USE_SSL = True EMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.c ...

  3. celery mysql 异步_celery配合rabbitmq任务队列实现任务的异步调度执行[celery redis]

    前言: 51cto的文章已经不再补充更新了,另外celery rabbitmq详细的使用方法请到这里浏览. http://xiaorui.cc/2014/11/16/celery-rabbitmq%E ...

  4. Django使用supervisor管理celery和uwsgi实践记录 uwsgi BACKOFF Exited too quickly (process log may have details)

    Django使用supervisor管理celery和uwsgi实践记录 安装下载supervisor不用多说. 直接上配置文件: vir_path标识虚拟环境路径 pro_path标识项目路径 全部 ...

  5. Celery Redis未授权访问命令执行利用

    首发补天社区:https://forum.butian.net/share/224←走过路过帮点一下~ 前言 Celery 是一个简单.灵活且可靠的分布式系统,用于处理大量消息,同时为操作提供维护此类 ...

  6. Django - 发送邮件

    在Python中已经内置了一个smtp邮件发送模块,Django在此基础上进行了简单地封装,让我们在Django环境中可以更方便更灵活的发送邮件. 所有的功能都在django.core.mail中. ...

  7. Django完成异步工具——celery

    情景:用户发起request,并等待response返回.在本些views中,可能需要执行一段耗时的程序,那么用户就会等待很长时间,造成不好的用户体验,比如发送邮件.手机验证码等 使用celery后, ...

  8. redis将散裂中某个值自增_0基础掌握Django框架(49)Redis

    为了更好的学习效果,请搭配视频教程一起学习: Django零基础到项目实战 - 网易云课堂​study.163.com redis教程: 概述 redis是一种nosql数据库,他的数据是保存在内存中 ...

  9. django 1.11.6—— Celery

    https://segmentfault.com/a/1190000008022050 1. 环境 python==3.6djang==1.11.6 # 1.8, 1.9, 1.10应该都没问题cel ...

  10. 手机异步发送短信验证码解决方案-Celery+redis

    Celery介绍和使用 一.Celery介绍: 一个简单.灵活且可靠.处理大量消息的分布式系统,可以在一台或者多台机器上运行. Celery是一个功能完备即插即用的任务队列 单个 Celery 进程每 ...

最新文章

  1. Qt之JSON生成与解析
  2. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一1.17 如何选择合适的拍摄地点...
  3. 卡通角色表情驱动系列一
  4. 弹体飞行姿态仿真软件程序代写
  5. 论文浅尝 | 利用知识图谱嵌入和图卷积网络进行长尾关系抽取
  6. 智能投影:下一个传统投影的颠覆者
  7. MORAN文本识别算法开源,刷新多个OCR数据集state-of-the-art
  8. 十五、static关键字
  9. appium使用教程python_appium使用教程(一 环境搭建)-------------2.安装部署
  10. eclipse svn同步代码缓慢、未响应
  11. 鉴相,鉴频以及环路跟踪算法的理解:
  12. QCC3040---earbud init module
  13. android+设置运行内存大小,怎样增大安卓手机的虚拟运行内存RAM ,手机的ram太小....
  14. 统计|如何理解多元回归下的多重可决系数
  15. 国内的智能家居品牌有哪些
  16. docker中容器与容器之间通讯
  17. 全球首个5G R16 Ready:紫光展锐的新征程
  18. 国内主要的广告联盟背景
  19. 数据库中用户登录注册用户信息表怎么设计如何设计
  20. 基于招聘广告的岗位人才需求分析框架构建与实证研究

热门文章

  1. 视图状态机制下的IStateManager接口
  2. 中文分词:正向最大匹配与逆向最大匹配
  3. sql语法、特殊符号及正则表达式的使用
  4. mmap函数_Linux中的mmap映射 [二]
  5. 举例HTML的图像标记,教案html之css滤镜及练习层div块及span标记举例窗口内例题演示功能的实现总结.pdf...
  6. Matlab中数组的常见用法
  7. 蓝桥杯2015年第六届C/C++省赛B组第二题-星系炸弹
  8. PTA 程序设计天梯赛(101~120题)
  9. 023-数据结构与算法系列
  10. 【LeetCode 剑指offer刷题】数组题11:228. Summary Ranges