1. 程式人生 > >Python全棧開發之Django進階

Python全棧開發之Django進階

targe 全棧 連接 驗證 views pid ddr 提示 cti

No.1 靜態文件處理

項目中CSS、JS、圖片都屬於靜態文件,一般會將靜態文件存到一個單獨目錄中,便於管理,在HTML頁面調用時,需要指定靜態文件的路徑,Django提供了一種解析靜態文件的機制,文件可以放在項目目錄下,也可以放在應用目錄下

在mysite/setting.py設置文件的物理路徑

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

在static目錄下創建css、js、img目錄

No.2 中間件

Django的中間件是一個輕量級的插件系統,可以介入請求和響應的過程,修改輸入與輸出,中間件的設計為開發者提供了一種無侵入式的開發方式,增加了框架的健壯性,Django在中間價中內置了5個方法,區別在於不同的階段執行,用來幹預請求和響應

初始化,不需要參數,服務器響應第一個請求的時候調用一次,用於確定是否啟用中間件

def __init__(self):
    pass

處理請求前 每個請求上,生成request對象後,配置url前調用,返回None或HttpResponse對象

def process_request(self, request):
    pass

處理視圖前 在每個請求上,url匹配後,視圖函數調用之前調用,返回None或HttpResponse對象

def process_view(self, request, view_func, *view_args, **view_kwargs):
    pass

處理響應後 視圖函數調用之後,所有響應返回瀏覽器之前調用,返回一個HttpResponse對象

def process_response(self, request, response):
    pass

異常處理:當視圖拋出異常時調用,在每個請求上調用,返回一個HttpResponse對象

def process_exception(self, request,exception):
    pass

栗子

# app01/middware.py
class my_mid:
    def __init__(self):
        print(‘--------------init‘)

    def process_request(self,request):
        print(‘--------------request‘)

    def process_view(self,request, view_func, *view_args, **view_kwargs):
        print(‘--------------view‘)

    def process_response(self,request, response):
        print(‘--------------response‘)
        return response

class exp1:
    def process_exception(self,request,exception):
        print(‘--------------exp1‘)

class exp2:
    def process_exception(self,request,exception):
        print(‘--------------exp2‘)

# mysite/setting.py
MIDDLEWARE_CLASSES = [
    ‘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‘,
    ‘app01.middleware.my_mid‘,
]

No.3 分頁

Django提供了數據分頁的類,這些類被定義在django/core/paginator.py中, 類Paginator用於對列進行一頁n條數據的分頁運算,類Page用於表示第m頁的數據

Paginator類實例對象

  • 方法init(列表,int):返回分頁對象,第一個參數為列表數據,第二個參數為每頁數據的條數
  • 屬性count:返回對象總數
  • 屬性num_pages:返回頁面總數
  • 屬性page_range:返回頁碼列表,從1開始,例如[1, 2, 3, 4]
  • 方法page(m):返回Page類實例對象,表示第m頁的數據,下標以1開始

Page類實例對象

  • 調用Paginator對象的page()方法返回Page對象,不需要手動構造。
  • 屬性object_list:返回當前頁對象的列表。
  • 屬性number:返回當前是第幾頁,從1開始。
  • 屬性paginator:當前頁對應的Paginator對象。
  • 方法has_next():如果有下一頁返回True。
  • 方法has_previous():如果有上一頁返回True。
  • 方法len():返回當前頁面對象的個數。

栗子

from django.core.paginator import Paginator
from app01.models import AreaInfo

# 參數pIndex表示:當前要顯示的頁碼
def page_test(request,pIndex=1):
    #查詢所有的地區信息
    list_address = AreaInfo.objects.filter(aParent__isnull=True)
    #將地區信息按一頁10條進行分頁
    p = Paginator(list_address, 10)
    # 通過url匹配的參數都是字符串類型,轉換成int類型
    pIndex = int(pIndex)
    # 獲取第pIndex頁的數據
    page_list = p.page(pIndex)
    #獲取所有的頁碼信息
    plist = p.page_range
    #將當前頁碼、當前頁的數據、頁碼信息傳遞到模板中
    return render(request, ‘app01/page_test.html‘, {‘list‘: list2, ‘plist‘: plist, ‘pIndex‘: pIndex})
 # app01/urls.py
 url(r‘^page(?P<pIndex>[0-9]*)/$‘, views.page_test),
 # app01/views.py
<html>
    <head>
        <title>分頁</title>
    </head>
    <body>
        顯示當前頁的地區信息:<br>
        <ul>
            {%for area in list%}
                <li>{{area.id}}--{{area.atitle}}</li>
            {%endfor%}
        </ul>
        <hr>
        顯示頁碼信息:當前頁碼沒有鏈接,其它頁碼有鏈接<br>
        {%for pindex in plist%}
            {%if pIndex == pindex%}
                {{pindex}}??
            {%else%}
                <a href="/page{{pindex}}/">{{pindex}}</a>??
            {%endif%}
        {%endfor%}
    </body>
</html>

No.4 富文本編輯器

借助富文本編輯器,網站的編輯人員能夠像使用offfice一樣編寫出漂亮的、所見即所得的頁面

富文本編輯器

安裝

pip3 install django-tinymce

栗子

在mysite/setting.py添加應用
INSTALLED_APPS = (
    ...
    ‘tinymce‘,
)
在mysite/setting.py配置編輯器
TINYMCE_DEFAULT_CONFIG = {
    ‘theme‘: ‘advanced‘,
    ‘width‘: 600,
    ‘height‘: 400,
}
在app01/urls.py配置url
urlpatterns = [
    ...
    url(r‘^tinymce/‘, include(‘tinymce.urls‘)),
]

在admin中定義使用

在app01/models.py中定義模型類

from django.db import models
from tinymce.models import HTMLField

class GoodsInfo(models.Model):
    gcontent=HTMLField()

執行遷移
在admin中進行註冊

自定義使用

在app01/views.py中定義視圖

def editor(request):
    return render(request, ‘app01/editor.html‘)
在app01/urls.py定義url
url(r‘^editor/‘,views.editor),

在項目目錄下創建cs、js、img目錄
打開py_django目錄,找到tinymce是的目錄

/home/python/.virtualenvs/py_django/lib/python3.5/site-packages/tinymce/static/tiny_mce

拷貝tiny_mce_src.js文件、langs文件夾以及themes文件夾拷貝到項目目錄下的static/js/目錄下

配置靜態文件查找路徑

創建editor.html模板

<html>
<head>
    <title>自定義使用tinymce</title>
    <script type="text/javascript" src=‘/static/js/tiny_mce.js‘></script>
    <script type="text/javascript">
        tinyMCE.init({
            ‘mode‘:‘textareas‘,
            ‘theme‘:‘advanced‘,
            ‘width‘:400,
            ‘height‘:100
        });
    </script>
</head>
<body>
<form method="post" action="#">
    <textarea name=‘gcontent‘>哈哈,這是啥呀</textarea>
</form>
</body>
</html>

No.5 全文檢索

全文檢索不同於特定字段的模糊查詢,使用全文檢索的效率更高,並且能夠對於中文進行分詞處理

  • haystack:全文檢索的框架,支持whoosh、solr、Xapian、Elasticsearc四種全文檢索引擎,點擊查看官方網站
  • whoosh:純Python編寫的全文搜索引擎,雖然性能比不上sphinx、xapian、Elasticsearc等,但是無二進制包,程序不會莫名其妙的崩潰,對於小型的站點,whoosh已經足夠使用,點擊查看whoosh文檔
  • jieba:一款免費的中文分詞包,如果覺得不好用可以使用一些收費產品。

全文檢索

安裝包

pip install django-haystack
pip install whoosh
pip install jieba

修改app01/settings.py文件,安裝應用haystack

INSTALLED_APPS = (
    ...
    ‘haystack‘,
)

在app01/settings.py文件中配置搜索引擎

HAYSTACK_CONNECTIONS = {
    ‘default‘: {
        #使用whoosh引擎
        ‘ENGINE‘: ‘haystack.backends.whoosh_cn_backend.WhooshEngine‘,
        #索引文件路徑
        ‘PATH‘: os.path.join(BASE_DIR, ‘whoosh_index‘),
    }
}

#當添加、修改、刪除數據時,自動生成索引
HAYSTACK_SIGNAL_PROCESSOR = ‘haystack.signals.RealtimeSignalProcessor‘

在app01/urls.py中添加搜索的配置

url(r‘^search/‘, include(‘haystack.urls‘)),

創建索引及引擎

在app01下創建search_indexs.py文件

from haystack import indexes
from app01.models import GoodsInfo
#指定對於某個類的某些數據建立索引
class GoodsInfoIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        return GoodsInfo

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

在templates目錄下創建search/indexes/app01/目錄

在上面的目錄中創建"goodsinfo_text.txt"文件

{{object.gcontent}}

找到虛擬環境py_django下的haystack目錄

/home/python/.virtualenvs/py_django/lib/python3.5/site-packages/haystack/backends/

在上面的目錄中創建ChineseAnalyzer.py文件

import jieba
from whoosh.analysis import Tokenizer, Token

class ChineseTokenizer(Tokenizer):
    def __call__(self, value, positions=False, chars=False,
                 keeporiginal=False, removestops=True,
                 start_pos=0, start_char=0, mode=‘‘, **kwargs):
        t = Token(positions, chars, removestops=removestops, mode=mode,
                  **kwargs)
        seglist = jieba.cut(value, cut_all=True)
        for w in seglist:
            t.original = t.text = w
            t.boost = 1.0
            if positions:
                t.pos = start_pos + value.find(w)
            if chars:
                t.startchar = start_char + value.find(w)
                t.endchar = start_char + value.find(w) + len(w)
            yield t

def ChineseAnalyzer():
    return ChineseTokenizer()

復制whoosh_backend.py文件,改為如下名稱

whoosh_cn_backend.py

打開復制出來的新文件,引入中文分析類,內部采用jieba分詞

from .ChineseAnalyzer import ChineseAnalyzer

更改詞語分析類

查找
analyzer=StemmingAnalyzer()
改為
analyzer=ChineseAnalyzer()

初始化索引數據

python manage.py rebuild_index

按提示輸入y後回車,生成索引

使用

按照配置,在admin管理中添加數據後,會自動為數據創建索引,可以直接進行搜索,可以先創建一些測試數據

在app01/views.py中定義視圖query

def query(request):
    return render(request,‘app01/query.html‘)

在app01/urls.py中配置

url(r‘^query/‘, views.query),

在templates/app01/目錄中創建模板query.html

<html>
<head>
    <title>全文檢索</title>
</head>
<body>
<form method=‘get‘ action="/search/" target="_blank">
    <input type="text" name="q">
    <br>
    <input type="submit" value="查詢">
</form>
</body>
</html>

自定義搜索結果模板:在templates/search/目錄下創建search.html

搜索結果進行分頁,視圖向模板中傳遞的上下文如下:

  • query:搜索關鍵字
  • page:當前頁的page對象
  • paginator:分頁paginator對象

視圖接收的參數如下:

  • 參數q表示搜索內容,傳遞到模板中的數據為query
  • 參數page表示當前頁碼
<html>
<head>
    <title>全文檢索--結果頁</title>
</head>
<body>
<h1>搜索?<b>{{query}}</b>?結果如下:</h1>
<ul>
{%for item in page%}
    <li>{{item.object.id}}--{{item.object.gcontent|safe}}</li>
{%empty%}
    <li>啥也沒找到</li>
{%endfor%}
</ul>
<hr>
{%for pindex in page.paginator.page_range%}
    {%if pindex == page.number%}
        {{pindex}}??
    {%else%}
        <a href="?q={{query}}&page={{pindex}}">{{pindex}}</a>??
    {%endif%}
{%endfor%}
</body>
</html>

No.6 發送郵件

Django中內置了郵件發送功能,被定義在django.core.mail模塊中。發送郵件需要使用SMTP服務器,常用的免費服務器有:163、126、QQ,下面以163郵件為例

註冊163郵箱itcast88,登錄後設置->POP3/SMTP/IMAP->客戶端授權密碼->開啟->填寫授權碼->確定

打開mysite/settings.py文件,點擊下圖配置。

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

在app01/views.py文件中新建視圖send

from django.conf import settings
from django.core.mail import send_mail
from django.http import HttpResponse
...
def send(request):
    msg=‘<a href="http://www.dingzefeng2017.cn/subject/pythonzly/index.shtml" target="_blank">點擊激活</a>‘
    send_mail(‘註冊激活‘,‘‘,settings.EMAIL_FROM,
              [‘[email protected]‘],
              html_message=msg)
    return HttpResponse(‘ok‘)

在app01/urls.py文件中配置

url(r‘^send/$‘,views.send),

No.7 celery

用戶發起request,並等待response返回,可能需要執行一段耗時的程序,那麽用戶就會等待很長時間,造成不好的用戶體驗,比如發送郵件、手機驗證碼等,使用celery後,情況就不一樣了。解決:將耗時的程序放到celery中執行

  • 點擊查看celery官方網站
  • 點擊查看celery中文文檔

celery名詞:

  • 任務task:就是一個Python函數。
  • 隊列queue:將需要執行的任務加入到隊列中。
  • 工人worker:在一個新進程中,負責執行隊列中的任務。
  • 代理人broker:負責調度,在布置環境中使用redis。

安裝包:

celery==3.1.25
django-celery==3.1.17

栗子

在app01/views.py文件中創建視圖sayhello

import time
...
def sayhello(request):
    print(‘hello ...‘)
    time.sleep(2)
    print(‘world ...‘)
    return HttpResponse("hello world")

在app01/urls.py中配置

url(r‘^sayhello$‘,views.sayhello),

在app01/settings.py中安裝

INSTALLED_APPS = (
  ...
  ‘djcelery‘,
}

在app01/settings.py文件中配置代理和任務模塊

import djcelery
djcelery.setup_loader()
BROKER_URL = ‘redis://127.0.0.1:6379/2‘

在app01/目錄下創建tasks.py文件

import time
from celery import task

@task
def sayhello():
    print(‘hello ...‘)
    time.sleep(2)
    print(‘world ...‘)

打開app01/views.py文件,修改sayhello視圖如下:

from app01 import tasks
...
def sayhello(request):
    # print(‘hello ...‘)
    # time.sleep(2)
    # print(‘world ...‘)
    tasks.sayhello.delay()
    return HttpResponse("hello world")

執行遷移生成celery需要的數據表

啟動Redis,如果已經啟動則不需要啟動

sudo service redis start

啟動worker

python manage.py celery worker --loglevel=info

打開app01/task.py文件,修改為發送郵件的代碼,就可以實現無阻塞發送郵件

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

@task
def sayhello():
    msg=‘<a href="http://www.dingzefeng2017.cn/subject/pythonzly/index.shtml" target="_blank">點擊激活</a>‘
    send_mail(‘註冊激活‘,‘‘,settings.EMAIL_FROM,
              [‘[email protected]‘],
              html_message=msg)

No.8 部署

當項目開發完成後,需要將項目代碼放到服務器上,這個服務器擁有固定的IP,再通過域名綁定,就可以供其它人瀏覽,對於python web開發,可以使用wsgi、apache服務器,此處以wsgi為例進行布署。

服務器首先是物理上的一臺性能高、線路全、運行穩定的機器,分為私有服務器、公有服務器。

  • 私有服務器:公司自己購買、自己維護,只布署自己的應用,可供公司內部或外網訪問,成本高,需要專業人員維護,適合大公司使用。
  • 公有服務器:集成好運營環境,銷售空間或主機,供其布署自己的應用,適合初創公司使用,成本低。

常用的公有服務器,如阿裏雲、青雲等,可按流量收費或按時間收費。服務器還需要安裝服務器軟件,此處需要uWSGI、Nginx。

服務器架構如下圖:

技術分享圖片

布署前需要關閉調試、允許任何機器訪問,打開app01/settings.py文件

DEBUG = False
ALLOW_HOSTS=[‘*‘,]

WSGI

在生產環境中使用WSGI作為python web的服務器。WSGI:全拼為Python Web Server Gateway Interface,Python Web服務器網關接口,是Python應用程序或框架和Web服務器之間的一種接口,被廣泛接受。WSGI沒有官方的實現, 因為WSGI更像一個協議,只要遵照這些協議,WSGI應用(Application)都可以在任何服務器(Server)上運行。

項目默認會生成一個wsgi.py文件,確定了settings模塊、application對象。

  • application對象:在Python模塊中使用application對象與應用服務器交互。
  • settings模塊:用於進行項目配置。

uWSGI

uWSGI實現了WSGI的所有接口,是一個快速、自我修復、開發人員和系統管理員友好的服務器,uWSGI代碼完全用C編寫,效率高、性能穩定

安裝uWSGI

pip install uwsgi

配置uWSGI,在項目目錄下創建uwsgi.ini文件,配置如下:

[uwsgi]
#使用nginx連接時使用
#socket=127.0.0.1:8080
#直接做web服務器使用
http=127.0.0.1:8080
#項目目錄
chdir=/home/python/Desktop/pytest/mysite
#項目中wsgi.py文件的目錄,相對於項目目錄
wsgi-file=app01/wsgi.py
processes=4
threads=2
master=True
pidfile=uwsgi.pid
daemonize=uwsgi.log

啟動

uwsgi --ini uwsgi.ini

查看

ps ajx|grep uwsgi

停止

uwsgi --stop uwsgi.pid

測試沒問題,將配置中啟用socket,禁用http

[uwsgi]
#使用nginx連接時使用
socket=127.0.0.1:8080
#直接做web服務器使用
#http=127.0.0.1:8080
#項目目錄
chdir=/home/python/Desktop/pytest/mysite
#項目中wsgi.py文件的目錄,相對於項目目錄
wsgi-file=app01/wsgi.py
processes=4
threads=2
master=True
pidfile=uwsgi.pid
daemonize=uwsgi.log

停止uwsgi服務,然後再啟動uwsgi

Python全棧開發之Django進階