玩轉Django2.0---Django筆記建站基礎十三(第三方功能應用)

第13章  第三方功能應用css

  在前面的章節中,咱們主要講述Django框架的內置功能以及使用方法,而本章主要講述Django的第三方功能應用以及使用方法。經過本章的學習,讀者可以在網站開發過程當中快速開發網站API、生成網站驗證碼、實現搜索引擎、實現第三方用戶註冊和分佈式任務。html

13.1  快速開發網站APIpython

  網站API也成爲接口,接口其實與網站的URL地址是同一個原理。當用戶使用GET或者POST方式訪問接口時,接口以JSON或字符串的數據內容返回給用戶,這與網站的URL地址返回的數據格式有所不一樣,網站的URL地址主要返回的是HTML網頁信息。mysql

  若想快速開發網站API,可使用Django Rest Framework框架實現。使用框架開發能夠規範代碼的編寫格式,這對企業級開發來講頗有必要,畢竟每一個開發人員的編程風格存在必定的差別,開發規範化能夠方便其它開發人員查看和修改。首先安裝Django Rest Framework框架,建議使用pip完成安裝,安裝指令以下:jquery

pip install djangorestframework

  框架按照完成後,以MyDjango項目爲例,在項目應用index中建立serializers.py文件,用於定義Django Rest Framework的Serializer類。MyDjango目錄結構以下圖:git

 

  構建項目目錄後,接着在setting.py中設置相關配置信息。在settings.py中分別設置數據庫鏈接信息和Django Rest Framework框架的功能配置,配置代碼分別以下:github

#MyDjango
#Django Rest Framework框架配置信息
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'index',
    # 添加Django Rest Framework框架
    'rest_framework'
]

#數據庫鏈接方式配置信息
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydjango',
        'USER': 'root',
        'PASSWORD': '1234',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    },
}

# Django Rest Framework框架設置信息
# 分頁設置
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 每頁顯示多少條數據
    'PAGE_SIZE': 2
}

  上述代碼中,再也不對數據庫配置作詳細的講述,咱們主要分析Django Rest Framework的功能配置。ajax

    (一):在INSTALLED_APPS中添加功能配置,這樣能使Django在運行過程當中自動加載Django Rest Framework的功能。redis

    (二):配置REST_FRAMEWORK屬性,屬性值以字典的形式表示,用於設置Django Rest Framework的分頁功能。sql

  完成settings.py的配置後,下一步是定義項目的數據模型。在index的models.py中分別定義模型Type和Product,代碼以下:

#index/models.py
from django.db import models
# 產品分類表
class Type(models.Model):
    id = models.AutoField('序號', primary_key=True)
    type_name = models.CharField('產品類型', max_length=20)
    # 設置返回值
    def __str__(self):
        return self.type_name

# 產品信息表
class Product(models.Model):
    id = models.AutoField('序號', primary_key=True)
    name = models.CharField('名稱',max_length=50)
    weight = models.CharField('重量',max_length=20)
    size = models.CharField('尺寸',max_length=20)
    type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='產品類型')
    # 設置返回值
    def __str__(self):
        return self.name

  將定義好的模型執行數據遷移,在項目的數據庫中生成相應的數據表,並對數據表index_product和index_type導入數據內容,以下圖:

 

 數據表的數據信息

  上述基本配置完成後,接下來使用Django Rest Framework快速開發API。首先在項目應用index的serializers.py中分別定義Serializer類和ModelSerializer類,代碼以下:

from rest_framework import serializers
from .models import Product, Type
# 定義Serializer類
# 設置下拉內容
type_id = Type.objects.values('id').all()
TYPE_CHOICES = [item['id'] for item in type_id]
class MySerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=True, allow_blank=False, max_length=100)
    weight = serializers.CharField(required=True, allow_blank=False, max_length=100)
    size = serializers.CharField(required=True, allow_blank=False, max_length=100)
    type = serializers.ChoiceField(choices=TYPE_CHOICES, default=1)

    # 重寫create函數,將API數據保存到數據表index_product
    def create(self, validated_data):
        return Product.objects.create(**validated_data)

    # 重寫update函數,將API數據更新到數據表index_product
    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.weight = validated_data.get('weight', instance.weight)
        instance.size = validated_data.get('size', instance.size)
        instance.type = validated_data.get('type', instance.type)
        instance.save()
        return instance

# 定義ModelSerializer類
class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'
        # fields = ('id', 'name', 'weight', 'size', 'type')
index/serializers.py

  從上述代碼能夠看到,Serializer類ModelSerializer類與Django的表單Form類和ModelForm類很是類似,二者的定義能夠相互借鑑。此外,Serializer和ModelSerializer還有其餘函數方法,若想進一步瞭解,在python的安裝目錄中查看相應的源文件(\Lib\site-packages\rest_framework)。最後,在urls.py和views.py中實現API開發。以定義的ProductSerializer類爲例,API功能代碼以下:

#index/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 基於類的視圖
    path('', views.product_class.as_view()),
    # 基於函數的視圖
    path('<int:pk>', views.product_def),
]

#index/views.py
from .models import Product
from .serializers import ProductSerializer

# APIView 方式生成視圖
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.pagination import PageNumberPagination
class product_class(APIView):
    # get 請求
    def get(self, request):
        queryset = Product.objects.all()
        # 分頁查詢,須要在settings.py設置REST_FRAMEWORK屬性
        pg = PageNumberPagination()
        page_roles = pg.paginate_queryset(queryset=queryset, request=request, view=self)
        serializer = ProductSerializer(instance=page_roles, many=True)
        # serializer = ProductSerializer(instance=queryset, many=True) # 全表查詢
        # 返回對象Response由Django Rest Framework實現
        return Response(serializer.data)
    # post 請求
    def post(self, request):
        # 獲取請求數據
        serializer = ProductSerializer(data=request.data)
        # 數據驗證
        if serializer.is_valid():
            # 保存到數據庫
            serializer.save()
            # 返回對象Response由Django Rest Framework實現,status是設置響應狀態碼
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

# 普通函數方式生成視圖
from rest_framework.decorators import api_view
@api_view(['GET', 'POST'])
def product_def(request, pk):
    if request.method == 'GET':
        queryset = Product.objects.filter(id=pk).all()
        serializer = ProductSerializer(instance=queryset, many=True)
        # 返回對象Response由Django Rest Framework實現
        return Response(serializer.data)
    elif request.method == 'POST':
        # 獲取請求數據
        serializer = ProductSerializer(data=request.data)
        # 數據驗證
        if serializer.is_valid():
            # 保存到數據庫
            serializer.save()
            # 返回對象Response由Django Rest Framework實現,status是設置響應狀態碼
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
index

  在分析上述代碼以前,首先了解一下Django Rest Framework實現API開發的三種方法:

    一、基於類的視圖。

    二、基於函數的視圖。

    三、重構ViewSets類。

  其中,重構ViewSets類的實現過程過於複雜,在開發過程當中,如無必要,通常不建議採用這種實現方式。若讀者對此方法感興趣,能夠參考官方文檔。

  在views.py中定義的product_class類和函數product_def分別基於類的視圖和基於函數的視圖,二者的使用說明以下:

    一、基於類的視圖:開發者主要經過自定義類來實現視圖,自定義類能夠選擇繼承父類APIView、mixins或generics。APIView類適用於Serializer類和ModelSerializer類,mixins類和generics類只適用於ModelSerializer類。

    上述代碼的product_class類主要繼承APIView類,而且定義GET請求和POST請求的處理函數。GET函數主要將模型Product的數據進行分頁顯示,POST函數將用戶發送的數據進行驗證併入庫處理。啓動MyDjango項目,在瀏覽器上輸入192.168.10.100:800/?page=1,運行結果以下:

 

 GET請求的響應內容

  爲了進一步驗證POST函數是否正確,咱們在項目的目錄外建立test.py文件,文件代碼以下:

import requests

url = 'http://127.0.0.1:8000'
data = {
    'name': 'MyPhone', 'weight': '123G', 'size': '123*123', 'type': 1
}

r = requests.post(url, data=data)
print(r.text)

  運行test.py文件並查看數據表index_product,能夠發現數據表index_product新增一條數據信息,以下圖:

 

     二、基於函數的視圖:使用函數的方式實現API開發是三者中最爲簡單的方式,從函數product_def的定義來看,該函數與Django定義的視圖函數並沒有太大區別。惟一的區別在於函數product_def須要使用裝飾器api_view而且數據是由Django Rest Framework定義的對象進行返回的。

  上述代碼中,若用戶發送GET請求,函數參數pk做爲模型Product的查詢條件,查詢結果交給ProductSerializer類實例化對象serializer進行數據格式轉換,最後由Django Rest Framework的Response對象返回給用戶;若用戶發送POST請求,函數將用戶發送的數據進行驗證併入庫處理。在瀏覽器上輸入http://127.0.0.1:8000/2,運行結果如圖:

 

 

 GET請求的響應內容

  若想驗證POST請求的處理方式,只需將上述test.py的url變量改成http://127.0.0.1:8000/1,而後運行test.py文件並查看數據表index_product是否新增一條數據。

  Django Rest Framework框架的使用方式總結以下:

    一、在settings.py中添加Django Rest Framework功能,並對功能進行分頁配置。

    二、在App中新建serializers.py文件並定義Serializer類或ModelSerializer類。

    三、在urls.py中定義路由地址。

    四、在views.py中定義視圖函數,三種方式定義分別爲:基於類的視圖、基於函數的視圖和重構ViewSets類。

 

 

13.2  驗證碼的使用

  如今不少網站都採用驗證碼功能,這是反爬蟲經常使用的策略之一。目前經常使用的驗證碼類型以下:

    一、字符驗證碼:在圖片上隨機產生數字、英文字母或漢字,通常有4爲或者6位驗證碼字符。

    二、圖片驗證碼:圖片驗證碼採用字符驗證碼的技術,再也不是一隨機的字符,而是讓用戶識別圖片,好比12306的驗證碼。

    三、GIF動畫驗證碼:由多張圖片組合而成的動態驗證碼,使得識別器不容易辨識哪一張圖片是真正的驗證碼圖片。

    四、極驗驗證碼:在2012年推出的新型驗證碼,採用行爲式驗證技術,經過拖動滑塊完成拼圖的形式實現驗證,是目前比較有創意的驗證碼,安全性具備新的突破。

    五、手機驗證碼:經過短信的形式發送到用戶手機上面的驗證碼,通常爲6爲的數字。

    六、語音驗證碼:也屬於手機端驗證的一種方式。

    七、視頻驗證碼:視頻驗證碼是驗證碼中的新秀,在視頻驗證碼中,將隨機數字、字母和中文組合而成的驗證碼動態嵌入MP4\FLV等格式的視頻中,增大破解難度。

  若是想在Django中實現驗證碼功能,可使用PIL模塊生成圖片驗證碼,但不建議使用這種方式實現,除此以外,還能夠經過第三方應用Django Simple Captcha來實現,驗證碼的生成過程由該應用自動執行,開發者只需考慮如何應用到Django項目中。Django Simple Captcha使用pip按照,安裝指令以下:

pip install django-simple-captcha

  按照成功後,下一步講述如何在Django中使用Django Simple Captcha生成網站驗證碼。以MyDjango項目爲例,在項目中應用user建立templates文件夾和forms.py文件,最後在templates文件夾中放置user.html文件,目錄結構如圖所示:

 

MyDjango目錄結構

  項目目錄結構搭建後,接下來在settings.py中配置項目。除了項目的基本配置以外,如何要配置TEMPLATES和DATABASES,還能夠對驗證碼的生成進行配置,如設置驗證碼的內容、圖片噪點和圖片大小等。具體的配置信息以下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user',
    # 添加驗證碼功能
    'captcha'
]


# django_simple_captcha 驗證碼基本配置
# 設置驗證碼的顯示順序,一個驗證碼識別包含文本輸入框、隱藏域和驗證碼圖片,該配置是設置三者的顯示順序
CAPTCHA_OUTPUT_FORMAT = '%(text_field)s %(hidden_field)s %(image)s'
# 設置圖片噪點
CAPTCHA_NOISE_FUNCTIONS = ( # 設置樣式
                            'captcha.helpers.noise_null',
                            # 設置干擾線
                           'captcha.helpers.noise_arcs',
                            # 設置干擾點
                           'captcha.helpers.noise_dots',
                           )
# 圖片大小
CAPTCHA_IMAGE_SIZE = (100, 25)
# 設置圖片背景顏色
CAPTCHA_BACKGROUND_COLOR = '#ffffff'
# 圖片中的文字爲隨機英文字母,如 mdsh
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
# 圖片中的文字爲英文單詞
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.word_challenge'
# 圖片中的文字爲數字表達式,如1+2=</span>
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
# 設置字符個數
CAPTCHA_LENGTH = 4
# 設置超時(minutes)
CAPTCHA_TIMEOUT = 1

  首先在INSTALLED_APPS中添加captcha驗證碼功能,項目運行時會字段價值captcha功能。而後對captcha功能進行相關的配置,主要的配置有:驗證碼的顯示順序、圖片噪點、圖片大小、背景顏色和驗證碼內容,具體的配置以及配置說明能夠查看源代碼及註釋。

  完成上述配置後,下一步是執行數據遷移。在功能配置後必須執行數據遷移,由於驗證碼須要依賴數據表才能得以實現。經過python manage.py migrate指令完成數據遷移,而後查看項目所生成的數據表,發現新增數據表captcha_captchastore,以下圖:

 

項目的數據表

  接下來將驗證碼功能生成在網頁上並實現驗證碼功能。下面以實現帶驗證碼的用戶登陸爲例進行介紹,根據整個用戶登陸過程,咱們將其劃分爲多個不一樣的功能。

    一、用戶登陸界面:由表單生成,表單類在項目應用user的forms.py中定義。

    二、登陸驗證:觸發POST請求,用戶信息以及驗證功能由Django內置的Auth認證系統實現。

    三、驗證碼動態刷新:由Ajax方式向captcha功能應用發送GET請求完成動態刷新。

    四、驗證碼動態驗證:由Ajax方向向Django發送GET請求完成驗證碼驗證。

  根據上述功能進行分析,整個用戶登陸過程由MyDjango的urls.py和項目應用user的forms.py、urls.py、views.py、和user.html共同實現。首先在項目應用user的forms.py中定義用戶登陸表單類,代碼以下:

# 定義用戶登陸表單類
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
    username = forms.CharField(label='用戶名')
    password = forms.CharField(label='密碼', widget=forms.PasswordInput)
    captcha = CaptchaField()

  從表單類CaptchaTestForm能夠看到,字段captcha是由Django Simple Captcha定義的CaptchaField對象,該對象在生成HTML網頁信息時,將自動生成文本輸入框、隱藏域和驗證碼圖片。而後表單類在views.py中進行實例化並展現在網頁上,在MyDjango的urls.py和項目應用user的urls.py、views.py和user.html中分別編寫如下代碼:

#MyDjango的urls.py
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('user.urls')),
    # 導入插件URL地址信息,用於生成圖片地址
    path('captcha/', include('captcha.urls'))
]

#user/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 用戶登陸界面
    path('', views.loginView, name='login'),
    # 驗證碼驗證API接口
    path('ajax_val', views.ajax_val, name='ajax_val')
]

#user/views.py
from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib.auth import login, authenticate
from .forms import CaptchaTestForm
# 用戶登陸
def loginView(request):
    if request.method == 'POST':
        form = CaptchaTestForm(request.POST)
        # 驗證表單數據
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            if User.objects.filter(username=username):
                user = authenticate(username=username, password=password)
                if user:
                    if user.is_active:
                        login(request, user)
                        tips = '登陸成功'
                else:
                    tips = '帳號密碼錯誤,請從新輸入'
            else:
                tips = '用戶不存在,請註冊'
    else:
        form = CaptchaTestForm()
    return render(request, 'user.html', locals())

# ajax接口,實現動態驗證驗證碼
from django.http import JsonResponse
from captcha.models import CaptchaStore
def ajax_val(request):
    if request.is_ajax():
        # 用戶輸入的驗證碼結果
        response = request.GET['response']
        # 隱藏域的value值
        hashkey = request.GET['hashkey']
        cs = CaptchaStore.objects.filter(response=response, hashkey=hashkey)
        # 若存在cs,則驗證成功,不然驗證失敗
        if cs:
            json_data = {'status':1}
        else:
            json_data = {'status':0}
        return JsonResponse(json_data)
    else:
        json_data = {'status':0}
        return JsonResponse(json_data)

#項目應用user的user.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Django</title>
        <script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    </head>
    <body>
        <div class="flex-center">
            <div class="container">
            <div class="flex-center">
            <div class="unit-1-2 unit-1-on-mobile">
                <h1>MyDjango Verification</h1>
                    {% if tips %}
                <div>{{ tips }}</div>
                    {% endif %}
                <form class="form" action="" method="post">
                    {% csrf_token %}
                    <div>用戶名:{{ form.username }}</div>
                    <div>密 碼:{{ form.password }}</div>
                    <div>驗證碼:{{ form.captcha }}</div>
                    <button type="submit" class="btn btn-primary btn-block">肯定</button>
                </form>
            </div>
            </div>
            </div>
        </div>
    <script>
        $(function(){
            {# ajax 刷新驗證碼 #}
            $('.captcha').click(function(){
                console.log('click');
                    $.getJSON("/captcha/refresh/",
                function(result){
                    $('.captcha').attr('src', result['image_url']);
                    $('#id_captcha_0').val(result['key'])
            });});
            {# ajax動態驗證驗證碼 #}
            $('#id_captcha_1').blur(function(){
                // #id_captcha_1爲輸入框的id,當該輸入框失去焦點就會觸發函數
                json_data={
                    // 獲取輸入框和隱藏字段id_captcha_0的數值
                    'response':$('#id_captcha_1').val(),
                    'hashkey':$('#id_captcha_0').val()
                }
                $.getJSON('/ajax_val', json_data, function(data){
                    $('#captcha_status').remove()
                    //status返回1爲驗證碼正確, status返回0爲驗證碼錯誤, 在輸入框的後面寫入提示信息
                    if(data['status']){
                        $('#id_captcha_1').after('<span id="captcha_status">*驗證碼正確</span>')
                    }else{
                        $('#id_captcha_1').after('<span id="captcha_status">*驗證碼錯誤</span>')
                    }
                });
            });
        })
    </script>
    </body>
</html>
user

  上述代碼用於實現整個用戶登陸過程,代碼中具體實現的功能代碼說明以下。

    一、MyDjango的urls.py:引入Django Simple Captcha的urls.py和項目應用user的urls.py。前者主要爲驗證碼圖片提供URL地址以及爲Ajax動態刷新驗證碼提供API接口,後者用於設置用戶登陸界面的URL以及爲Ajax動態校驗證碼提供API接口。

    二、項目應用user的urls.py:設置用戶登陸界面的URL地址和Ajax動態驗證的API接口。

    三、views.py:函數loginView使用Django內置的Auth實現登陸功能;函數ajax_val用於獲取Ajax的GET請求參數,而後與Django Simple Captcha定義的模型進行匹配,若匹配的上,則驗證成功,不然驗證失敗。

    四、user.html:生成用戶表單以及實現Ajax的動態刷新和動態驗證功能。Ajax動態刷新是向Django Simple Captcha的urls.py所定義的URL發送GET請求,而Ajax動態驗證是向項目應用user的urls.py所定義的URL發送GET請求。

  爲了更好地驗證上述所實現的功能,首先在項目內置User的中建立用戶root並啓動MyDjango項目,而後執行如下驗證步驟:

    一、單擊驗證碼圖片,查看驗證碼圖片是否發生替換。

    二、單擊驗證碼輸入框,分別輸入正確和錯誤的驗證碼,而後單擊網頁的其餘地方,使驗證碼輸入框失去焦點,從而觸發Ajax請求,最後查看驗證碼驗證是否正確。

    三、輸入用戶的帳號、密碼和驗證碼,查看是否登陸成功。

 

13.3  站內搜索引擎

  站內搜索是網站經常使用的功能之一,其做用是方便用戶快速查找站內數據以便查閱。對於一些初學者來講,站內搜索可使用SQL搜索查詢實現,從某個角度來講,這種實現方式只是適用於我的小型網站,對於企業級的開發,站內搜索是由搜索引擎實現的。

  Django Haystack是一個專門提供搜索功能的Django第三方應用,它支持Solr、Elasticsearch、Whoosh和Xapian等多種搜索引擎,配合著名的中文天然語言處理庫jieba分詞能夠實現全文搜索系統。

  本節在Whoosh搜索引擎和jieba分詞的基礎上使用Django Haystack實現網站搜索引擎。所以,在安裝Django Haystack的過程當中,須要自行安裝Whoosh搜索引擎和jieba分詞,具體的pip安裝指令以下:

pip install django-haystack

pip install whoosh

pip install jieba

  完成上述模塊的安裝後,接着在MyDjango項目中配置相關的應用功能。在項目應用index中分別添加文件product_text.txt、search.html、search_indexes.py、whoosh_cn_backend.py和文件夾static,各個文件說明以下:

    一、product_text.txt:搜索引擎的索引模板文件,模板文件命名以及路徑有固定的設置格式,如/templates/search/indexes/項目應用的名稱/模型(小寫)_text.txt。

    二、search.html:搜索頁面的模板文件,用於生成網站的搜索頁面。

    三、search_indexes.py:定義索引類,該文件與索引模板文件是兩個不一樣的概念。

    四、whoosh_cn_backend.py:這是自定義的Whoosh搜索引擎文件。因爲Whoosh不支持中文搜索,所以須要從新定義Whoosh搜索引擎文件,將jieba分詞器添加到搜索引擎中,使得它具備中文搜索功能。

    五、static:存放網頁樣式common.css和search.css

  根據上述目錄搭建,最後MyDjango的目錄結構以下圖:

 

  MyDjango目錄你們完成後,下一步是在settings.py中配置第三方應用Django Haystack。這裏的配置主要在INSTALLED_APPS中引入Django Haystack以及設置該應用的功能配置,具體的配置信息以下:

#settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'index',
    # 配置haystack
    'haystack',
]
# 配置haystack
HAYSTACK_CONNECTIONS = {
    'default': {
        # 設置搜索引擎,文件是index的whoosh_cn_backend.py
        'ENGINE': 'index.whoosh_cn_backend.WhooshEngine',
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
        'INCLUDE_SPELLING': True,
    },
}
# 設置每頁顯示的數據量
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 4
# 當數據庫改變時,會自動更新索引,很是方便
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

  觀察上述配置能夠發現,配置屬性HAYSTACK_CONNECTIONS的ENGINE指向項目應用index的whoosh_cn_backend.py文件。該文件是自定義的Whoosh搜索引擎文件,這是根據Whoosh源文件進行修改生成的,在Python的安裝目錄中能夠找到Whoosh源文件whoosh_backend.py,以下圖:

 

   打開whoosh_backend.py文件並將內容複製到whoosh_cn_backend.py,而後將複製後的內容進行修改和保存,這樣就能夠生成自定義的Whoosh搜索引擎文件。具體修改的內容以下:

#引入jieba分詞器的模塊
from jieba.analyse import ChineseAnalyzer


#schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)
#所在位置並修改整行替代,帶入內容以下:
#schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(),field_boost=field_class.boost,sortable=True)

  完成settings.py和whoosh_cn_backend.py的配置後,接下來實現搜索引擎的開發。在功能開發以前,須要在項目應用index的models.py中從新定義數據模型Product,模型Product做爲搜索引擎的搜索對象。模型Product的定義代碼以下:

from django.db import models
# 建立產品信息表
class Product(models.Model):
    id = models.AutoField('序號', primary_key=True)
    name = models.CharField('名稱',max_length=50)
    weight = models.CharField('重量',max_length=20)
    describe = models.CharField('描述',max_length=500)
    # 設置返回值
    def __str__(self):
        return self.name

  將定義好的模型Product執行數據遷移,在數據庫中生成數據表index_product,並對數據表index_product導入數據內容,以下圖:

 

 

 數據表index_product的數據信息

  如今開始講述搜索引擎的開發過程,首先建立搜索引擎的索引。建立索引主要能使搜索引擎快速找到符合條件的數據,索引就像是書本的目錄,能夠爲讀者快讀地查找內容,在這裏也是一樣的道理。當數據量很是大的時候,要從這些數據中找出全部知足搜索條件的數據是不太可能的,而且會給服務器帶來極大的負擔,因此咱們須要爲指定的數據添加一個索引。

  索引是在search_indexes.py中定義的,而後由指令指令建立過程。咱們以模型Product爲例,在search_indexes.py中定義該模型的索引,代碼以下:

from haystack import indexes
from .models import Product
# 類名必須爲模型名+Index,好比模型Product,則索引類爲ProductIndex
class ProductIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    # 設置模型
    def get_model(self):
        return Product
    # 設置查詢範圍
    def index_queryset(self, using=None):
        return self.get_model().objects.all()

  從上述代碼來看,在定義模型的索引類時,類定義要求以及定義說明以下:

    一、定義索引類的文件名必須爲search_indexes.py,不得修改文件名,不然程序沒法建立索引。

    二、索引類的類名格式必須爲"模型+Index",每一個模型對應一個索引類,如模型Product的索引類爲ProductIndex。

    三、字段text設置document=True,表明搜索引擎將使用此字段的內容做爲索引進行檢索。

    四、use_template=True是使用索引模板創建索引文件,能夠理解爲在索引中設置模型的查詢字段,如設置Product的得desctibe字段,這樣能夠經過describe的內容檢索Product的數據。

    五、類函數get_model是將該索引類與模型Product進行綁定,類函數index_queryset用於設置索引的查詢範圍。

  從上述分析能夠知道,use_template=True是使用索引模板創建索引文件,索引模板的路徑是固定的,其格式爲/templates/search/indexes/項目應用的名稱/模型(小寫)_text.txt。以ProductIndex爲例,其索引模板路徑爲templates/search/indexes/index/product_text.txt。咱們在索引模板中設置模型Product的name和describe字段做爲索引的檢索字段,能夠在索引模板中添加如下代碼:

#templates/search/indexes/index/product_text.txt
{{  object.name  }}
{{  object.describe  }}

  上述設置是對Product.name和Product.describe兩個字段創建索引,當搜索引擎進行檢索時,系統會根據搜索條件對着兩個字段進行全文檢索匹配,而後將匹配結果排序後並返回。

  如今只定義了搜索引擎的索引類和索引模板,咱們能夠根據這二者建立索引文件,經過指令python manage.py rebuild_index便可完成索引文件的建立,在MyDjango中能夠看到whoosh_index文件夾,該文件夾中含有索引文件,以下圖:

 

   最後在Django中實現搜索功能,實現模型Product的全文檢索。在urls.py、views.py和search.html中分別定義搜索引擎的URL地址、URL的視圖以及HTML模板,具體的代碼及說明以下:

#index/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 搜索引擎
    path('search.html', views.MySearchView(), name='haystack'),
]

#index/views.py
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.conf import settings
from .models import *
from haystack.views import SearchView
# 視圖以通用視圖實現
class MySearchView(SearchView):
    # 模版文件
    template = 'search.html'
    # 重寫響應方式,若是請求參數q爲空,返回模型Product的所有數據,不然根據參數q搜索相關數據
    def create_response(self):
        if not self.request.GET.get('q', ''):
            show_all = True
            product = Product.objects.all()
            paginator = Paginator(product, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
            try:
                page = paginator.page(int(self.request.GET.get('page', 1)))
            except PageNotAnInteger:
                # 若是參數page的數據類型不是整型,則返回第一頁數據
                page = paginator.page(1)
            except EmptyPage:
                # 用戶訪問的頁數大於實際頁數,則返回最後一頁的數據
                page = paginator.page(paginator.num_pages)
            return render(self.request, self.template, locals())
        else:
            show_all = False
            qs = super(MySearchView, self).create_response()
            return qs

#index/search.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>搜索引擎</title>
    {# 導入CSS樣式文件 #}
    {% load staticfiles %}
    <link type="text/css" rel="stylesheet" href="{% static "common.css" %}">
    <link type="text/css" rel="stylesheet" href="{% static "search.css" %}">
</head>
<body>
<div class="header">
    <div class="search-box">
        <form id="searchForm" action="" method="get">
            <div class="search-keyword">
                {# 搜索輸入文本框必須命名爲q #}
                <input id="q" name="q" type="text" class="keyword" maxlength="120"/>
            </div>
            <input id="subSerch" type="submit" class="search-button" value="搜 索" />
        </form>
        <div id="suggest" class="search-suggest"></div>
    </div>
</div><!--end header-->

<div class="wrapper clearfix" id="wrapper">
<div class="mod_songlist">
    <ul class="songlist__header">
        <li class="songlist__header_name">產品名稱</li>
        <li class="songlist__header_author">重量</li>
        <li class="songlist__header_album">描述</li>
    </ul>
    <ul class="songlist__list">
        {# 列出當前分頁所對應的數據內容 #}
        {% if show_all %}
            {% for item in page.object_list %}
            <li class="js_songlist__child" mid="1425301" ix="6">
                <div class="songlist__item">
                    <div class="songlist__songname">{{ item.name }}</div>
                    <div class="songlist__artist">{{item.weight}}</div>
                    <div class="songlist__album">{{ item.describe }}</div>
                </div>
            </li>
            {% endfor %}
        {% else %}
            {# 導入自帶高亮功能 #}
            {% load highlight %}
            {% for item in page.object_list %}
            <li class="js_songlist__child" mid="1425301" ix="6">
                <div class="songlist__item">
                    <div class="songlist__songname">{% highlight item.object.name with query %}</div>
                    <div class="songlist__artist">{{item.object.weight}}</div>
                    <div class="songlist__album">{% highlight item.object.describe with query %}</div>
                </div>
            </li>
            {% endfor %}
        {% endif %}
    </ul>
    {# 分頁導航 #}
    <div class="page-box">
    <div class="pagebar" id="pageBar">
    {# 上一頁的URL地址 #}
    {% if page.has_previous %}
        {% if query %}
            <a href="{% url 'haystack'%}?q={{ query }}&amp;page={{ page.previous_page_number }}" class="prev">上一頁</a>
        {% else %}
            <a href="{% url 'haystack'%}?page={{ page.previous_page_number }}" class="prev">上一頁</a>
        {% endif %}
    {% endif %}
    {# 列出全部的URL地址 #}
    {% for num in page.paginator.page_range %}
        {% if num == page.number %}
            <span class="sel">{{ page.number }}</span>
        {% else %}
            {% if query %}
                <a href="{% url 'haystack' %}?q={{ query }}&amp;page={{ num }}" target="_self">{{num}}</a>
            {% else %}
                <a href="{% url 'haystack' %}?page={{ num }}" target="_self">{{num}}</a>
            {% endif %}
        {% endif %}
    {% endfor %}
    {# 下一頁的URL地址 #}
    {% if page.has_next %}
        {% if query %}
            <a href="{% url 'haystack' %}?q={{ query }}&amp;page={{ page.next_page_number }}" class="next">下一頁</a>
        {% else %}
            <a href="{% url 'haystack' %}?page={{ page.next_page_number }}" class="next">下一頁</a>
        {% endif %}
    {% endif %}
    </div>
    </div>
</div><!--end mod_songlist-->
</div><!--end wrapper-->
</body>
</html>
index

  上述代碼中,視圖是經過繼承SearchView類實現的,父類SearchView是由Django Haystack封裝的視圖類。若是想了解DjangoHaystack封裝的視圖類,能夠在Python按照目錄查看具體的源代碼,文件路徑爲\Lib\site-packages\haystack\views.py,也能夠查看Django Haystack官方文檔。

  在模板文件search.html中,咱們將搜索結果中的搜索條件進行高亮顯示。模板標籤highlight是Django Haystack自定義的標籤,標籤的使用方法較爲簡單,此處不作詳細介紹,具體使用方法能夠參考官方文檔http://django-haystack.readthedocs.io/en/master/templatetags.html。

  啓動MyDjango項目,在瀏覽器上輸入http://127.0.0.1:8000/search.html,並在上方輸入"移動電源"進行搜索,搜索結果以下圖:

 

 

 

13.4  第三方用戶註冊

   用戶註冊與登陸以及成爲網站必備的功能之一,Django內置的Auth認證系統能夠幫助開發人員快速實現用戶管理功能。但不少網站爲了增強社交功能,在用戶管理功能上增設了第三方用戶註冊與登陸功能,這是經過OAuth2.0認證與受權來實現的。OAuth2.0的具體實現過程相對繁瑣,咱們經過流程圖來大體瞭解OAuth2.0的實現過程,以下圖:

 

OAuth2.0的實現過程

  分析實現過程,咱們能夠簡單理解OAuth2.0認證與受權是兩個網站的服務器後臺進行通訊交流。根據實現原理,可使用requests庫或urllib標準庫實現OAuth2.0認證與受權,從而實現第三方用戶的註冊與登陸功能。若是網站涉及多個第三方網站,這種方式實現不太可取的,並且發現代碼會出現重複使用的狀況。所以,咱們可使用Django第三方功能應用Django Social Auth,它爲咱們提供了各大網站平臺的認證與受權功能。

  Django Social Auth是在Python Social Auth的基礎上進行封裝而成的,除了按照Django Social Auth以外,還須要安裝Python Social Auth。經過pip方式進行安裝,按照指令以下:

pip install python-social-auth
pip install social-auth-app-django

  功能模塊安裝成功後,以MyDjango項目爲例,講述如何在Django中使用Django Social Auth實現第三方用戶註冊功能,MyDjango的目錄結構以下圖:

 

  MyDjango的目錄結構較爲簡單,由於Django Social Auth的本質是一個Django的項目應用,能夠在Python的安裝目錄下找到Django Social Auth全部的源代碼文件,發現它具備urls.py、views.py和models.py等文件,這與Django App(項目應用)的文件架構是同樣的,以下圖:

 

Django Social Auth的源代碼文件

  瞭解Django Social Auth的本質後,在後續的使用中能夠更加清晰地知道他的實現過程。本節以微博賬號實現用戶的註冊功能。首先在瀏覽器中打開微博開放平臺(http://open.weibo.com/),登陸微博並新建應用,而後獲取應用的App Key和App Secret,如圖:

 

 

 獲取App Key和App Secret

  下一步是設置應用的OAuth2.0受權設置,單擊應用中的高級信息,編輯OAuth2.0受權設置的受權回調頁,以下圖:

 

 OAuth2.0受權設置

  受權回調頁的URL地址必須爲/complete/weibo/,由於受權回調頁是由Django Social Auth進行處理的,而它已經爲受權回調頁設置相應的地址路徑。能夠打開Django Social Auth的源代碼文件urls.py查看具體的設置內容,具體以下:

"""URLs module"""
from django.conf import settings
from django.conf.urls import url

from social_core.utils import setting_name
from . import views


extra = getattr(settings, setting_name('TRAILING_SLASH'), True) and '/' or ''

app_name = 'social'

urlpatterns = [
    # authentication / association
    url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth,
        name='begin'),
    url(r'^complete/(?P<backend>[^/]+){0}$'.format(extra), views.complete,
        name='complete'),
    # disconnection
    url(r'^disconnect/(?P<backend>[^/]+){0}$'.format(extra), views.disconnect,
        name='disconnect'),
    url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>\d+){0}$'
        .format(extra), views.disconnect, name='disconnect_individual'),
]
social_django/urls.py

  完成上述配置後,接着在settings.py中設置Django Social Auth的配置信息,主要在INSTALLED_APPS和TEMPLATES中引入功能模塊以及設置相關的功能配置,配置信息以下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user',
    # 添加第三方應用
    'social_django'
]


# 設置第三方的OAuth2.0,全部第三方的OAuth2.0能夠查看源碼目錄:\Lib\site-packages\social\backends
AUTHENTICATION_BACKENDS = (
   'social.backends.weibo.WeiboOAuth2',      # 微博的功能
   'social.backends.qq.QQOAuth2',             # QQ的功能
   'social.backends.weixin.WeixinOAuth2',    # 微信的功能
   'django.contrib.auth.backends.ModelBackend',)
# 註冊成功後跳轉頁面
SOCIAL_AUTH_LOGIN_REDIRECT_URL = 'success'
# 開放平臺應用的 APPID 和 SECRET
SOCIAL_AUTH_WEIBO_KEY = '812869040'
SOCIAL_AUTH_WEIBO_SECRET = '999f3116040e312e4ec08efd3622811f'
SOCIAL_AUTH_QQ_KEY = 'APPID'
SOCIAL_AUTH_QQ_SECRET = 'SECRET'
SOCIAL_AUTH_WEIXIN_KEY = 'APPID'
SOCIAL_AUTH_WEIXIN_SECRET = 'SECRET'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'user/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',
                #須要添加的配置信息
                'social_django.context_processors.backends',
                'social_django.context_processors.login_redirect',
            ],
        },
    },
]
settings.py

  由於Django Social Auth定義了相關的數據模型,完成settings.py的配置後,須要使用python manage.py migrate執行數據遷移,生成相關的數據表,最後在MyDjango項目中實現第三方用戶註冊功能,功能主要由MyDjango的urls.py、項目應用user的urls.py、views.py和user.html共同實現,分別編寫相關的功能代碼,代碼以下:

#MyDjango/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('user.urls')),
    # 導入social_django的URL,源碼地址\Lib\site-packages\social_django\urls.py
    url('', include('social_django.urls', namespace='social')),
]

#user/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 用戶註冊界面的URL地址,顯示微博登陸連接。
    path('', views.loginView, name='login'),
    # 註冊後回調的頁面,成功註冊後跳轉回站內地址。
    path('success', views.success, name='success')
]

#user/views.py
from django.shortcuts import render
# 用戶註冊界面
def loginView(request):
    title = '用戶註冊'
    return render(request, 'user.html', locals())

# 註冊後回調的頁面
from django.http import HttpResponse
def success(request):
    return HttpResponse('註冊成功')

#user/user.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
    <div class="flex-center">
    <div class="unit-1-2 unit-1-on-mobile">
        <h1>MyDjango Social Auth</h1>
        <div>
            {# {% url "social:begin" "weibo" %}來自Lib\site-packages\social_django\urls.py #}
            <a class="btn btn-primary btn-block" href="{% url "social:begin" "weibo" %}">微博註冊</a>
        </div>
    </div>
    </div>
    </div>
</div>
</body>
</html>

   在上述代碼中,咱們一共設置了三個URL路由地址,分別爲social、login和success,三者的做用說明以下:

    一、social:導入Django Social Auth的URL,將其添加到MyDjango項目中,主要生成受權頁面和處理受權回調請求。

    二、login:生成網站的用戶註冊頁面,爲受權頁面提供連接入口,方便用戶進入受權頁面。

    三、success:受權回調處理完成後,程序自動跳轉的頁面,由settings.py的配置屬性SOCIAL_AUTH_LOGIN_REDIRECT_URL設置。

  啓動MyDjango項目,在瀏覽器中輸入http://127.0.0.1:8000/並單擊微博"註冊"按鈕,網頁會出現微博的受權認證頁面,而後單擊"受權"按鈕,程序會字段跳轉到success的URL所生成的頁面,以下圖:

 

 

 

 

 

 

 

 微博受權認證過程

  完成微博的認證與受權後,咱們在數據庫中分別查看數據表social_auth_usersocialauth和auth_user。能夠發現兩個數據表都建立了用戶信息,前者是微博認證受權後的微博用戶信息,前者是微博認證受權後的微博用戶信息,後者是根據前者的用戶信息在網站中建立的新用戶,以下圖:

 

 

 

 數據表social_auth_usersocialauth和auth_user

  上述例子主要實現了第三方用戶註冊網站賬號的功能。除此以外,還能夠實現第三方用戶登陸網站、第三方用戶失聯已有的網站賬號以及Admin後臺管理設置等功能。因爲篇幅有限就再也不詳細講述,有興趣的能夠參考官方文檔和查閱相關資料。

 

 

13.5  分佈式任務與定時任務

  網站的併發編程主要處理網站的業務流程,根據網站請求到響應的過程分析,Django處理用戶請求主要在視圖中執行,視圖主要是一個函數,並且是單線程執行的函數。在視圖函數處理用戶請求時,若是遇到繁瑣的數據讀寫或高密度計算,每每會形成響應時間過長,在網頁上容易出現卡死的狀況,不利於用戶體驗。爲了解決這種狀況,咱們能夠在視圖中加入分佈式任務,讓他處理一些耗時的業務流程,從而縮短用戶響應時間。

  Django的分佈式主要由Celery框架實現,這是Python開發的分佈式任務隊列。它支持使用任務隊列的方式在分佈的機器、進程和線程上執行任務調度。Celery側重與實時操做,用於生成系統天天處理數以百萬計的任務。Celery自己不提供消息存儲服務,它使用第三方消息服務來傳遞任務。目前支持RabbitMQ、Redis和MongoDB等。

  本節使用第三方應用Django Celery Results、Django Celery Beat、 Celery和Redis數據庫實現Django的分佈式任務和定時任務開發。值得注意的是,定時任務是分佈式任務的一種特殊類型任務。

  首先須要安裝Redis數據庫,在Windows中安裝Redis數據庫有兩種方式:在官網下載壓縮包安裝和在GitHub下載MSI安裝程序。前者的數據庫版本是最新的,但須要經過指令安裝並設置相關的環境配置;後者是舊版本,但安裝方法是傻瓜式安裝,啓動程序後單擊安裝按鈕便可完成安裝。二者的下載地址以下:

#官網下載地址
https://redis.io/download

#github下載地址
https://github.com/MicrosoftArchive/redis/releases

  Redis數據庫的安裝過程本書就不詳細講述了,讀者能夠自行查閱相關的資料。除了安裝Redis數據庫以外,還能夠安裝Redis數據庫的可視化工具,可視化工具能夠幫助初次接觸Redis的讀者瞭解數據庫結構。本書使用Redis Desktop Manager做爲Redis的可視化工具,以下圖:

 

 Redis Desktop Manager

  下一步是按照本節所須要的功能模塊,主要的功能模塊有:celery、redis、django-celery-results、django-celery-beat和eventlet。這些功能模塊能經過pip完成安裝,安裝指令以下:

pip install celery
pip install redis
pip install django-celery-results
pip install django-celery-beat
pip install eventlet

  每一個功能模塊負責實現不一樣的功能,在此簡單講解各個功能模塊的具體做用,其說明以下:

    一、celery:安裝Celery框架,實現分佈式任務調度。

    二、redis:使Python與Redis數據庫實現鏈接。

    三、django-celery-results:基於Celery基礎上封裝的分佈式任務功能,主要適用於Django。

    四、django-celery-beat:基於Celery基礎上封裝的定時任務功能,主要適用於Django。

    五、eventlet:Python的協程併發庫,這是Celery實現分佈式的併發模式之一。

  在MyDjango項目中,分別在MyDjango文件夾建立celery.py和在項目應用index中tasks.py。前者是在Django框架中引入Celery框架,後者是建立MyDjango的分佈式任務。MyDjango目錄結構如圖:

 

  而後在celery.py和tasks.py文件中分別編寫功能代碼。celery.py的代碼基本是固定的,而tasks.py的代碼能夠根據需求自行編寫。二者代碼以下:

#celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# 獲取settings.py的配置信息
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings')
# 定義Celery對象,並將項目配置信息加載到對象中。
# Celery的參數通常覺得項目名命名
app = Celery('MyDjango')
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))

#tasks.py
from celery import shared_task
from .models import *
import time
# 帶參數的分佈式任務
@shared_task
def updateData(product_id, value):
    Product.objects.filter(id=product_id).update(weight=value)

# 該任務用於執行定時任務
@shared_task
def timing():
    now = time.strftime("%H:%M:%S")
    with open("E:\\output.txt", "a") as f:
        f.write("The time is " + now)
        f.write("\n")
        f.close()

  從celery.py的代碼得知,該文件是將Celery框架進行實例化並生成app對象。如今還須要將app對象與MyDjango項目進行鏈接,使項目能夠執行分佈式任務。在celery.py同一級目錄的__init__.py中編寫相關代碼,當MyDjango初始化時,Django會字段加載app對象。__init__.py的代碼以下:

from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
__all__ = ['celery_app']

  再分析tasks.py中的函數updateData可知,該函數是對模型Product進行讀寫操做。所以,咱們須要在models.py中定義模型Product,而後對模型Product執行數據遷移,並在對應的數據表中導入相關的數據內容。模型Product的定義以下:

from django.db import models
# 建立產品信息表
class Product(models.Model):
    id = models.AutoField('序號', primary_key=True)
    name = models.CharField('名稱',max_length=50)
    weight = models.CharField('重量',max_length=20)
    describe = models.CharField('描述',max_length=500)
    # 設置返回值
    def __str__(self):
        return self.name

  將定義好的模型Product執行數據遷移,在數據庫中生成數據表index_product,而且對數據表導入相關數據內容,數據表index_product的數據信息以下圖:

 

 數據表index_product的數據信息

  接着在MyDjango的settings.py中配置Celery的配置信息,因爲本節須要實現分佈式任務和定時任務,所以配置信息主要對二者進行配置,具體的配置內容以下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'index',
    # 添加分佈式任務功能
    'django_celery_results',
    # 添加定時任務功能
    'django_celery_beat'
]

# 設置存儲Celery任務隊列的Redis數據庫
CELERY_BROKER_URL = 'redis://192.168.10.100:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
# 設置存儲Celery任務結果的數據庫
CELERY_RESULT_BACKEND = 'django-db'

# 設置定時任務相關配置
CELERY_ENABLE_UTC = False
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

  配置完成後,須要再次執行數據遷移,由於分佈式任務和定時任務在運行過程當中須要依賴數據表才能完成任務執行。完成數據遷移後,打開項目的數據庫,能夠看到項目一共生成了17個數據表,以下圖:

 

MyDjango的數據庫結構

  最後在項目應用index的urls.py和views.py中分別編寫URL路由地址和視圖函數,當用戶訪問網頁時,MyDjango將字段執行分佈式任務。urls.py和views.py的代碼以下:

#index/urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 首頁的URL
    path('', views.index),
]

#index/views.py
from django.http import HttpResponse
from .tasks import updateData
def index(request):
    # 傳遞參數並執行異步任務
    updateData.delay(10, '140g')
    return HttpResponse("Hello Celery")

  至此,咱們已完成Django分佈式功能的代碼開發,接下來說述如何使用分佈式任務和定時任務。首先啓動MyDjango項目,而後單擊PyCharm的Terminal,並輸入如下指令啓動Celery:

#指令中的MyDjango是項目名
celery -A MyDjango worker -l info -P eventlet

  Celery啓動成功後,Celery會自動加載MyDjango定義的分佈式任務,而且顯示相關的數據庫鏈接信息,以下圖:

 

 Celery啓動消息

  在瀏覽器上輸入http://127.0.0.1:8000/,視圖函數index將會執行分佈式任務updateData,該任務是在數據表index_product卡找到ID=10的數據,而後將該數據的字段weight內容改成140g。當分佈式任務執行成功後,執行的結果會顯示在Terminal中,並以及保存到數據表django_celery_results_taskresult中,以下圖所示:

 

 分佈式任務執行結果

  下一步是使用定時任務,定時任務主要經過Admin後臺生成。首先在MyDjango中建立超級用戶root並登陸到Admin後臺,而後進入Periodic tasks而且建立定時任務,將任務設置爲每間隔3秒執行函數timing,以下圖:

 

 

   任務設置完畢後,咱們經過輸入指令來啓動定時任務。在輸入指令以前,必須保證MyDjango和Celery處於運行狀態。簡單來講,若是使用CMD模式來啓動定時任務,須要啓動三個CMD窗口,一次輸入如下指令:

#啓動MyDjango
python manage.py runserver 8000

#啓動 celery
celery -A MyDjango worker -l info -P eventlet

#啓動定時任務
celery -A MyDjango beat -l info -S django

  若是在PyCharm中啓動定時任務,能夠在Terminal下新建會話窗口,輸入相應的指令便可。定時任務啓動後,每隔三秒會執行一次程序,在Terminal和數據表django_celery_results_taskresult中均可以查看相關的執行狀況,以下圖:

 

 

 

13.6  本章小結

  本章主要講述了Django的第三方功能應用,將網站中經常使用的功能進行封裝處理,避免開發人員重複造輪子,縮減開發時間以及維護成本。在本章講述的第三方功能應用的實現過程當中,咱們總結出大體的實現過程:

    一、在settings.py的INSTALLED_APPS中添加應用功能以及設置該功能的相關配置。

    二、建立新的.py文件,主要對功能進行實例化或定義相關的對象,如Django Rest Framework的serializers.py和搜索引擎的search_indexes.py等。

    三、設置項目的URL地址以及調用第三方功能內置的URL地址,如Django Social Auth和Django Simple Captcha等。

    四、在項目的視圖函數中,調用第三方功能的對象或實例化對象,使其做用於模型或模板,在網站中生成相應的功能界面。

相關文章
相關標籤/搜索