1. 程式人生 > >02 用戶註冊通過發送郵箱激活

02 用戶註冊通過發送郵箱激活

如何 receive set document broker rdquo 想是 css ews

配置靜態文件

在項目根目錄下創建靜態文件static目錄,用於放置靜態的文件

在settings 文件中定義靜態內容

STATIC_URL = /static/
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, static),
]

把靜態的文件如css,js,image放入static目錄中:

技術分享圖片

把當前關於註冊用到的模板放到模板文件中,

技術分享圖片

在應用users中 views視圖定義處理註冊的請求函數,返回註冊的頁面:

類視圖:http://python.usyiyi.cn/translate/django_182/topics/class-based-views/intro.html

# 導入類視圖,主要給urls
from django.views.generic import View

class RegisterView(View):
    """註冊"""
    def get(self, request):
        """對應get請求方式,提供註冊頁面"""
        return render(request, "register.html", )

在根級urls中配置到應用users的跳轉路徑

import users.urls

url(r‘^users/‘, include(users.urls, namespace="users")),

在uers.urls.py中配置請求路徑

from django.conf.urls import url
from . import views

urlpatterns = [

    url(r‘^register$‘, views.RegisterView.as_view(), name="register"),

]

 在瀏覽器地址欄中輸入:

http://127.0.0.1:8000/users/register

  返回的頁面如下所示:

技術分享圖片

註冊頁中的html代碼如下:

技術分享圖片
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title>天天生鮮-註冊</title> <link rel="stylesheet" type="text/css" href="../static/css/reset.css"> <link rel="stylesheet" type="text/css" href="../static/css/main.css"> <script type="text/javascript" src="../static/js/jquery-1.12.4.min.js"></script> <script type="text/javascript" src="../static/js/register.js"></script> </head> <body> <div class="register_con"> <div class="l_con fl"> <a class="reg_logo"><img src="../static/images/logo02.png"></a> <div class="reg_slogan">足不出戶 · 新鮮每一天</div> <div class="reg_banner"></div> </div> <div class="r_con fr"> <div class="reg_title clearfix"> <h1>用戶註冊</h1> <a href="#">登錄</a> </div> <div class="reg_form clearfix"> <form method="post"> {% csrf_token %} <ul> <li> <label>用戶名:</label> <input type="text" name="user_name" id="user_name"> <span class="error_tip">提示信息</span> </li> <li> <label>密碼:</label> <input type="password" name="pwd" id="pwd"> <span class="error_tip">提示信息</span> </li> <li> <label>確認密碼:</label> <input type="password" name="cpwd" id="cpwd"> <span class="error_tip">提示信息</span> </li> <li> <label>郵箱:</label> <input type="text" name="email" id="email"> <span class="error_tip">提示信息</span> {{ errmsg }} </li> <li class="agreement"> <input type="checkbox" name="allow" id="allow" checked="checked"> <label>同意”天天生鮮用戶使用協議“</label> <span class="error_tip2">提示信息</span> </li> <li class="reg_sub"> <input type="submit" value="註 冊" name=""> </li> </ul> </form> </div> </div> </div> <div class="footer no-mp"> <div class="foot_link"> <a href="#">關於我們</a> <span>|</span> <a href="#">聯系我們</a> <span>|</span> <a href="#">招聘人才</a> <span>|</span> <a href="#">友情鏈接</a> </div> <p>CopyRight © 2016 北京天天生鮮信息技術有限公司 All Rights Reserved</p> <p>電話:010-****888 京ICP備*******8號</p> </div> </body> </html>
View Code

用戶提交表單的時候接受發送的post請求,由於表單中action表單的地址沒寫,所以還在原來的請求地址和視圖函數中處理,只不過是post的請求而已,

在視圖函數中,添加post請求處理的函數:

技術分享圖片
from django.core.urlresolvers import reverse
from django import db
from .models import *
import re


def post(self, request):
        """對應post請求方式,接收處理用戶的註冊數據"""
        # 接收傳入的參數
        user_name = request.POST.get("user_name")
        password = request.POST.get("pwd")
        email = request.POST.get("email")
        allow = request.POST.get("allow")

        # 檢驗參數的正確性
        if not all([user_name, password, email]):
            # 重定向到註冊頁面
            return redirect(reverse("users:register"))

        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:
            # django的AbstractUser基類提供的創建用戶的方法
            user = User.objects.create_user(user_name, email, password)
        except db.IntegrityError:
            # 如果用戶名已存在,則拋出此異常信息
            return render(request, "register.html", {"errmsg": "用戶名已存在!"})

        # 將用戶的激活狀態設置為假
        user.is_active = False
        user.save()

        # 將結果返回給前端
        return redirect(reverse("goods:index"))
View Code

在根基目錄的urls中,構造商品應用的請求地址

import goods.urls
urlpatterns = [
   
    url(r^, include(goods.urls, namespace=goods)),
]

在商品的views中,構造商品主頁的請求函數

from django.shortcuts import render
from django.views.generic import View


class IndexView(View):
    def get(self,request):
        return render(request,‘index.html‘)

在應用goods中的urls中,構造商品主頁的請求地址

from django.conf.urls import url
from goods import views

urlpatterns = [
    url(r"^$", views.IndexView.as_view(), name="index"),
]

註冊成功在數據庫中的查詢狀態:

技術分享圖片

使用celery實現異步調用django的發送郵件的模塊,讓用戶激活自己的賬號.

主要思想是,先生成一個唯一的口令用來表示用戶,通過django中的(itsdangerous模塊),在使用celery服務器實現異步發送郵件.

1 根據用戶的ID生成唯一的口令:

在用戶模模型類中,創建生成唯一口令的方法:

用戶生成註冊口令文檔 http://itsdangerous.readthedocs.io/en/latest/

技術分享圖片
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer


class User(AbstractUser, BaseModel):
    """用戶"""
    class Meta:
        db_table = "df_users"

    def generate_active_token(self):
        """生成激活令牌"""
        # 構建序列化器(轉換工具)對象
        serializer = Serializer(settings.SECRET_KEY, 3600)
        # 轉換參數
        token = serializer.dumps({"confirm": self.id})  # 返回bytes類型
        return token.decode()
View Code

2 在項目根目錄下創建celery_tasks的包用來存儲用celery發送任務的模塊,在包中創建tasks.py模塊其內容為:

技術分享圖片
from celery import Celery
import os

#把jiango的配置模型放到系統的環境變量中,celery才可以調用django的模塊
os.environ["DJANGO_SETTINGS_MODULE"] = "dailyfresh_13.settings"

# 放到celery服務器上時將註釋打開
# import django
# django.setup()

from django.core.mail import send_mail
from django.conf import settings

# 創建celery應用對象
app = Celery("celery_tasks.tasks", broker="redis://10.211.55.5/2")


# 定義任務
@app.task
def send_active_email(user_name, to_email, token):
    """發送激活郵件"""
    subject = "天天生鮮用戶激活"  # 郵件標題
    body = ""  # 郵件體
    sender = settings.EMAIL_FROM  # 發件人
    receivers = [to_email]  # 接收人
    html_body = <h1>尊敬的用戶 %s, 感謝您註冊天天生鮮!</h1>                 <br/><p>請點擊此鏈接激活您的帳號<a href="http://127.0.0.1:8000/users/active/%s">                 http://127.0.0.1:8000/users/active/%s<a></p> % (user_name, token, token) # html郵件體
    send_mail(subject, body, sender, receivers, html_message=html_body)
View Code

3 調用celery任務入到broker隊列中,以便剛才我們創建的celery workder服務器能夠從隊列中取出任務並執行。如何將任務函數加入到隊列中,可使用delay()

在用戶註冊的post請求處理函數中,將發送郵件的任務函數加入到隊列中,

把下面的兩行代碼加到 class RegisterView(View):的post請求函數中

from celery_tasks.tasks import send_active_email

# 為用戶生成激活口令
        token = user.generate_active_token()

        # 使用celery異步發送郵件
        send_active_email.delay(user_name, email, token)

  技術分享圖片

4 打開項目的settings.py文件,配置Email:

# Email
EMAIL_BACKEND = ‘django.core.mail.backends.smtp.EmailBackend‘
EMAIL_HOST = ‘smtp.126.com‘
EMAIL_PORT = 25
#發送郵件的郵箱
EMAIL_HOST_USER = ‘[email protected]‘
#在郵箱中設置的客戶端授權密碼
EMAIL_HOST_PASSWORD = ‘ITCAST123‘
#收件人看到的發件人
EMAIL_FROM = ‘天天生鮮<[email protected]>‘

5 處理用戶激活的請求:

  定義用戶激活的請求的處理函數:

# 口令過期
from itsdangerous import SignatureExpired

# 定義了激活的接口
class ActiveView(View):
    """激活"""
    def get(self, request, token):
        """

        :param request:
        :param token: token是用戶攜帶的口令,唯一標識用戶
        :return:
        """
        # 解析口令token,獲取用戶身份
        # 構建序列化器
        s = Serializer(settings.SECRET_KEY)
        try:
            data = s.loads(token)
        except SignatureExpired:
            # 表示token過期
            return HttpResponse("鏈接已過期!")
        # 表示token未過期,
        user_id = data.get("confirm")

        # 查詢用戶的數據.處理bug
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            # 用戶不存在
            return HttpResponse("用戶不存在!")
        # 設置用戶的激活狀態
        user.is_active = True
        user.save()

        # 返回處理結果
        return HttpResponse("ok")
        # return redirect(reverse("users:login"))    

6 配置用戶激活請求的url:

 url(r‘^active/(?P<token>.+)‘, views.ActiveView.as_view(), name="active"),

5 .打開終端,執行命令:

celery -A celery_tasks.tasks worker --loglevel=info

技術分享圖片

用戶dsa提交表單:

技術分享圖片

celery發送郵件成功:

技術分享圖片

用戶dsa接受到郵件點擊激活後,查詢數據庫中的is_active的狀態為1,激活成功:

技術分享圖片

定義用戶登陸請求的處理函數:

Django認證系統文檔 http://python.usyiyi.cn/documents/django_182/topics/auth/default.html

from django.contrib.auth import authenticate, login


class LoginView(View):
    """登錄"""
    def get(self, request):
        """提供登錄頁面"""
        return render(request, "login.html")

    def post(self, request):
        """處理登錄的數據"""
        # 獲取參數
        user_name = request.POST.get("username")
        password = request.POST.get("pwd")

        # 參數校驗
        if not all([user_name, password]):
            # 參數不完整
            return render(request, "login.html")

        # 登錄業務邏輯處理
        # try:
        #     password = sha256(password)
        #     User.objects.get(username=user_name, password=password)
        # except User.DoesNotExist:
        #     return HttpResponse("用戶名或密碼錯誤")

        # 使用django的認證系統進行用戶密碼的校驗
        user = authenticate(username=user_name, password=password)
        if user is None:
            # 用戶的登錄信息有誤
            return render(request, "login.html", {"errmsg": "用戶名或密碼錯誤!"})

        # 判斷用戶的激活狀態
        if user.is_active is False:
            return render(request, "login.html", {"errmsg": "用戶尚未激活!"})

        # 保存用戶的登錄狀態
        # 使用django的login函數保存用戶的session數據
        login(request, user)

        # 登錄成功,跳轉到主頁
        return HttpResponse(‘登陸成功‘)
        #return redirect(reverse("goods:index"))

在瀏覽器輸入以下的網址:

http://127.0.0.1:8000/users/login

  技術分享圖片

用戶和激活的狀態判斷成功後,顯示以下的頁面:

技術分享圖片 

配置用戶登陸請求的url:

 url(r‘^login$‘, views.LoginView.as_view(), name="login"),

======================================================================================================

用戶登陸成功,返回主頁的請求處理函數,這個請求處理函數寫在goods應用中的views函數中:

技術分享圖片

from django.shortcuts import render
from django.views.generic import View

# Create your views here.


class IndexView(View):
    """主頁"""
    def get(self, request):
        return render(request, "index.html")

定義用戶登陸主頁的請求路徑:

現在根據的請求路徑urls中,定義再跳到goods應用中的urls

在根基定義跳轉的路徑:

url(r‘^/‘, include(goods.urls, namespace="goods")),

在goods應用中的urls模塊中寫請求登陸主頁的路徑:

from django.conf.urls import url
from goods import views

urlpatterns = [
    url(r"^$", views.IndexView.as_view(), name="index"),
]

在用戶登陸處理函數login中把最後的登陸成功的路徑跳轉到主頁

  # return HttpResponse(‘登陸成功‘)
 return redirect(reverse(‘goods:index‘))

  技術分享圖片

點擊登陸,認證成功後,返回以下的頁面:

技術分享圖片

============================================================

把session和緩存儲在redis數據庫中,在setings中配置代碼以下:

pip install django-redis

django-redis文檔:http://django-redis-chs.readthedocs.io/zh_CN/latest/#

django的session使用文檔:http://python.usyiyi.cn/documents/django_182/topics/http/sessions.html

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://localhost/3",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}


# Session
# http://django-redis-chs.readthedocs.io/zh_CN/latest/#session-backend

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

 用戶登陸成功後,在redis數據庫中的查詢的結果如下:

技術分享圖片 

02 用戶註冊通過發送郵箱激活