django中使用RabbitMQ


 

在MQ之前,我一直使用的redis作為中間人broker然后用celery執行耗時任務。從未在python項目中使用過MQ。所以今天就在django中用RabbitMQ取代redis+celery。

 

django中使用RabbitMQ

本次使用RabbitMQ完成點擊注冊后給用戶發送激活郵件的場景,如果不使用MQ,或者不使用異步的方式,后端就會一直等待smtp服務器把郵件發到用戶郵箱后才往下走(我們用time.sleep(5)來模擬一下發郵件的耗時)。由於就這一個消息類型,我們就用個簡單模式,請看上一期RabbitMQ的六種模式:

1、django中的發送郵件配置

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 固定寫法
EMAIL_HOST = 'smtp.qq.com' # QQ的SMTP地址,是163郵箱則換為smtp.163.com
EMAIL_PORT = 25 # SMTP端口
EMAIL_HOST_USER = 'aaaaaa@qq.com' #發送郵件的郵箱
EMAIL_HOST_PASSWORD = 'aaaaaaaaaaaaa'  # 授權碼,qq郵箱中發短信后獲取到的
# 發件人,<>里面的東西必須和EMAIL_HOST_USER(目的郵箱地址一摸一樣,不能隨便寫,不然郵件發不出去)
EMAIL_FROM = '買了佛冷<aaaaaa@qq.com>'

 

2、在項目中定義一個類,把email塞進MQ的操作放在構造方法中,到時只需RabbitMQ(email)即可

import pika

class RabbitMQ():
    def __init__(self,email):
        # 1、連接rabbitmq服務器
        connection = pika.BlockingConnection(pika.ConnectionParameters('x.x.x.x'))
        channel = connection.channel()

        # 2、創建一個名為hello的隊列
        channel.queue_declare(queue='hello')
        # 3、簡單模式,向名為hello隊列中插入用戶郵箱地址email
        channel.basic_publish(exchange='',
                              routing_key='hello',
                              body=email,
                              )


        print("發送用戶郵箱:‘{}’ 到MQ成功".format(email))
        connection.close()

 

3、定義一個base.py文件用於導入django環境,離線腳本初始化用戶數據的時候就需要導入django環境,我們的消費者端要使用django的send_mail函數,所以也要導入django環境。

import os
import sys
import django

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "你的項目名.settings")
django.setup()  # os.environ['DJANGO_SETTINGS_MODULE']

 

4、編寫消費者端代碼
消費者端監聽hello隊列,在接收到用戶的email后,執行回調callback(發郵件操作),回調中模擬了發郵件的等待時間time.sleep(5)。稍后前端點擊注冊的時候,觀察是否為立即跳轉,如果立即跳轉就說明MQ是異步,只管塞消息不管處理和處理結果。

# base.py文件用於導入django環境,離線腳本初始化用戶數據的時候就需要導入django環境
import base
import pika
import time
from django.core.mail import send_mail
from django_MQ_demo import settings

# 1、連接rabbitmq服務器
connection = pika.BlockingConnection(pika.ConnectionParameters(host='x.x.x.x'))
channel = connection.channel()
# 2、創建隊列,可以只讓一方創建,主要是分不清哪邊先跑起來,所以這兒也要創建同樣的隊列
channel.queue_declare(queue='hello')

# 3、構建回調函數
def callback(ch,method,properties,email):
    print("消費者端收到用戶郵箱  ‘{}’  成功".format(email))
    
    subject = 'lanyc注冊'
    message = ''
    sender = settings.EMAIL_FROM
    receiver = [email]
    # 講道理還應該來一個html_message,內容為一個激活鏈接的a標簽
    # send_mail是django內置的發郵件函數,這四個是必須參數
    send_mail(subject, message, sender, receiver)
    time.sleep(5)
    print('向目的郵箱{}發送郵件成功'.format(email))

    # 發送應答信號,表明數據已經處理完成,可以刪除,和auto_ack=False套起來用
    ch.basic_ack(delivery_tag=method.delivery_tag)

# 確定監聽隊列:hello,一旦有值出現,則觸發回調函數:callback
channel.basic_consume(queue='hello',
                      auto_ack=False,
                      on_message_callback=callback,
                      )

print('當前MQ簡單模式正在等待生產者往消息隊列塞消息.......要退出請按 CTRL+C.......')
channel.start_consuming()

 

5、前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注 冊</title>
</head>
<body>
<form id="registerForm">
{% csrf_token %}
{% for field in form %}
    {{ field.label }}:{{ field }}<br>
{% endfor %}
<input type="button" id='regForm' value="注 冊">
</form>
</body>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
    $(function () {
        registerFunc();
    });

    function registerFunc() {
    	//注冊按鈕綁定
        $('#regForm').click(function () {
            $.ajax({
                url:'/email',
                method:'post',
                dataType:'json',
                //帶上用戶提交的所有表單信息
                data:$('#registerForm').serialize(),
                success: function (res) {
                    if (res.status){
                        alert('注冊成功!點擊確定跳轉到郵箱登錄頁面,請點擊您的郵件完成激活');
                        location.href=res.data;
                    }else{
                        alert("注冊失敗")
                    }
                }
            })
        })
    }
</script>
</html>

  

6、django后端代碼(還要配路由):

# 路由:/email
class UserModelForm(ModelForm):
    class Meta:
        model = UserInfo
        fields = "__all__"
        
def register_email(request):
    if request.method == "GET":
        # 要寫個form類
        form = UserModelForm()
        return render(request,'register.html',{'form':form})
    if request.method == "POST":
        email = request.POST.get('email')
        # 實例化上面定義的生產者方的類,自動執行其構造方法,塞email進隊列
        RabbitMQ(email)  # 1、將用戶提交的郵箱地址傳入RabbitMQ隊列------->2、消費端一直等待,就直接取過該隊列消息,處理,給用戶發送消息
return JsonResponse({'status':True,'data':'https://mail.163.com/'}) return JsonResponse({'status':False})

 

先運行消費者端代碼:

后端的form類中這兩個字段我都沒寫校驗鈎子只用來生成表單。所以不填用戶名沒報錯,這不是重點。重點是我點擊注冊后,ajax的post請求會走到后端的RabbitMQ(email)這行代碼,執行類中自定義的構造方法塞email進消息隊列,塞完email馬上返回JsonResponse,不會去等消費者中回調函數的time.sleep(5)模擬時間以及真實發郵件花費的時間。所以頁面效果是馬上彈出模態框。

 

 163郵箱收到郵件:

 

 

消費者端控制台 :

 

這就是整個django中使用rabbitmq,整個過程就是實現了異步,解耦。后端發郵件只需塞email進MQ,然后就return。如果在后端中直接調用發郵件函數send_mail,就要等着郵件發出去才會return。

 

文章來源:https://blog.csdn.net/qq_37623764/article/details/105825554

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM