有需要上網現查現學的東西。
分頁
- 分頁是指在web頁面有大量資料需要顯示,為了閱讀友善在每個頁頁中隻顯示部分資料。
- 好處:
- 友善閱讀
- 減少資料提取量,減輕伺服器壓力。
- Django提供了Paginator類可以友善的實作分頁功能
- Paginator類位于
子產品中。django.core.paginator
Paginator對象
- 負責分頁資料整體的管理
- 對象的構造方法
- paginator = Paginator(object_list, per_page)
- 參數
- object_list 需要分類資料的對象清單
- per_page 每頁資料個數
- 傳回值:
- Paginator的對象
- Paginator屬性
- count:需要分類資料的對象總數
- num_pages:分頁後的頁面總數
- page_range:從1開始的range對象, 用于記錄目前面碼數
- per_page 每頁資料的個數
- Paginator方法
- page(number)
- 參數 number為頁碼資訊(從1開始)
- 傳回目前number頁對應的頁資訊
- 如果提供的頁碼不存在,抛出InvalidPage異常
- page(number)
- Paginator異常exception
- InvalidPage:總的異常基類,包含以下兩個異常子類
- PageNotAnInteger:當向page()傳入一個不是整數的值時抛出
- EmptyPage:當向page()提供一個有效值,但是那個頁面上沒有任何對象時抛出
- InvalidPage:總的異常基類,包含以下兩個異常子類
Page對象
- 負責具體某一頁的資料的管理
- 建立對象
Paginator 對象的 page () 方法傳回 Page 對象
page = paginator.page(頁碼)
複制
- Page 對象屬性
object_list:目前頁上所有資料對象的清單
number:目前頁的序号,從 1 開始
paginator:目前 page 對象相關的 Paginator 對象
- Page 對象方法
has_next ():如果有下一頁傳回 True
has_previous ():如果有上一頁傳回 True
has_other_pages ():如果有上一頁或下一頁傳回 True
next_page_number ():傳回下一頁的頁碼,如果下一頁不存在,抛出 InvalidPage 異常
previous_page_number ():傳回上一頁的頁碼,如果上一頁不存在,抛出 InvalidPage 異常
len ():傳回目前頁面對象的個數
- 說明:
Page 對象是可疊代對象,可以用 for 語句來 通路目前頁面中的每個對象
- 參考文檔 https://docs.djangoproject.com/en/2.2/topics/pagination/
- 分頁示例:
視圖函數
from django.core.paginator import Paginato
def book(request):
bks = Book.objects.all()
paginator = Paginator(bks, 10)
cur_page = request.GET.get('page', 1) # 得到預設的目前頁
page = paginator.page(cur_page)
return render(request, 'bookstore/book.html', locals())
複制
模闆設計
<html>
<head>
<title>分頁顯示</title>
</head>
<body>
{% for b in page %}
<div>{{ b.title }}</div>
{% endfor %}
{% if page.has_previous %}
<a href="{% url 'book' %}?page={{ page.previous_page_number }}">上一頁</a>
{% else %}
上一頁
{% endif %}
{% for p in paginator.page_range %}
{% if p == page.number %}
{{ p }}
{% else %}
<a href="{% url 'book' %}?page={{ p }}">{{ p }}</a>
{% endif %}
{% endfor %}
{% if page.has_next %}
<a href="{% url 'book' %}?page={{ page.next_page_number }}">下一頁</a>
{% else %}
下一頁
{% endif %}
</body>
</html>
複制
檔案下載下傳
Django可直接在視圖函數中生成csv檔案 并響應給浏覽器
import csv
from django.http import HttpResponse
from .models import Book
def make_csv_view(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
all_book = Book.objects.all()
writer = csv.writer(response)
writer.writerow(['id', 'title'])
for b in all_book:
writer.writerow([b.id, b.title])
return response
複制
- 響應獲得一個特殊的MIME類型text / csv。這告訴浏覽器該文檔是CSV檔案,而不是HTML檔案
- 響應會獲得一個額外的
标頭,其中包含CSV檔案的名稱。它将被浏覽器用于“另存為…”對話框Content-Disposition
- 對于CSV檔案中的每一行,調用
,傳遞一個可疊代對象,如清單或元組。writer.writerow
檔案上傳
- 檔案上傳必須為 POST 送出方式
- 表單 <form> 中檔案上傳時必須有帶有 enctype="multipart/form-data" 時才會包含檔案内容資料。
- 表單中用 <input type="file" name="xxx"> 标簽上傳檔案
名字 xxx 對應 request.FILES['xxx'] 對應的記憶體緩沖檔案流對象。可通能過 request.FILES['xxx'] 傳回的對象擷取上傳檔案資料
file=request.FILES['xxx'] file 綁定檔案流對象,可以通過檔案流對象的如下資訊擷取檔案資料
file.name 檔案名
file.file 檔案的位元組流資料
- 上傳檔案的表單書寫方式
<!-- file: index/templates/index/upload.html -->
<html>
<head>
<meta charset="utf-8">
<title>檔案上傳</title>
</head>
<body>
<h3>上傳檔案</h3>
<form method="post" action="/test_upload" enctype="multipart/form-data">
<input type="file" name="myfile"/><br>
<input type="submit" value="上傳">
</form>
</body>
</html>
複制
- 在 setting.py 中設定 MEDIA 相關配置;Django 把使用者上傳的檔案,統稱為 media 資源
# file : settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
複制
- 在目前項目檔案夾下建立 media 檔案夾
$ mkdir media
複制
- 上傳檔案的視圖處理函數 方案 1 傳統寫入
# file views.py
from django.http import HttpResponse
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
import os
@csrf_exempt
def upload_view(request):
if request.method == 'GET':
return render(request, 'test_upload.html')
elif request.method == "POST":
a_file = request.FILES['myfile']
print("上傳檔案名是:", a_file.name)
filename =os.path.join(settings.MEDIA_ROOT, a_file.name)
with open(filename, 'wb') as f:
data = a_file.file.read()
f.write(data)
return HttpResponse("接收檔案:" + a_file.name + "成功")
複制
- 上傳檔案的視圖處理函數 方案 2 借助 orm
#test_upload/models.py
from django.db import models
# Create your models here.
class Content(models.Model):
desc = models.CharField(max_length=100)
myfile = models.FileField(upload_to='myfiles')
#test_upload/views.py
from test_upload.models import *
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def upload_view_dj(request):
if request.method == 'GET':
return render(request, 'test_upload.html')
elif request.method == 'POST':
title = request.POST['title']
a_file = request.FILES['myfile']
Content.objects.create(desc=title,myfile=a_file)
return HttpResponse('----upload is ok-----')
複制
- 若要在浏覽器中通路 上傳的資源,runserver 環境下,需要在項目得主路由下添加 media 路由的綁定
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
複制
浏覽器可以通路 http://127.0.0.1:8000/media/xxxx
Django中的使用者認證 (使用Django認證系統)
- Django帶有一個使用者認證系統。 它處理使用者賬号、組、權限以及基于cookie的使用者會話。
- 作用:
- 添加普通使用者和超級使用者
- 修改密碼
- 文檔參見
- https://docs.djangoproject.com/en/2.2/topics/auth/
- User模型類
- 位置:
from django.contrib.auth.models import User
- 預設user的基本屬性有:
- 位置:

auth基本模型操作:
- 建立使用者
建立普通使用者 create_use
from django.contrib.auth.models import Use
user = User.objects.create_user(username='使用者名', password='密碼', email='郵箱',...)
複制
- 建立超級使用者 create_superuse
from django.contrib.auth.models import Use
user = User.objects.create_superuser(username='使用者名', password='密碼', email='郵箱',...)
複制
- 删除使用者
from django.contrib.auth.models import Use
try:
user = User.objects.get(username='使用者名')
user.is_active = False # 記目前使用者無效
user.save()
print("删除普通使用者成功!")
except:
print("删除普通使用者失敗")
複制
- 修改密碼 set_password
from django.contrib.auth.models import Use
try:
user = User.objects.get(username='xiaonao')
user.set_password('654321')
user.save()
return HttpResponse("修改密碼成功!")
except:
return HttpResponse("修改密碼失敗!")
複制
- 檢查密碼是否正确 check_password
from django.contrib.auth.models import Use
try:
user = User.objects.get(username='xiaonao')
if user.check_password('654321'): # 成功傳回True,失敗傳回False
return HttpResponse("密碼正确")
else:
return HttpResponse("密碼錯誤")
except:
return HttpResponse("沒有此使用者!")
複制
auth擴充字段
如果需要在預設auth表上擴充新的字段,如phone
- 添加新的應用
- 定義模型類 繼承 AbstractUser
- settings.py中 指明 AUTH_USER_MODEL = ‘應用名.類名’
#models.py案例
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class UserInfo(AbstractUser):
phone = models.CharField(max_length=11, default='')
#settings.py添加配置
AUTH_USER_MODEL = 'user.UserInfo'
#添加使用者
from user.models import UserInfo
UserInfo.objects.create_user(username='guoxiao', password='123456', phone='13488871101')
複制
電子郵件發送
- 利用QQ郵箱發送電子郵件
- django.core.mail 子包封裝了 電子郵件的自動發送SMTP協定
- 前其準備:
- 申請QQ号
- 用QQ号登陸QQ郵箱并修改設定
- 用申請到的QQ号和密碼登陸到 https://mail.qq.com/
- 修改
QQ郵箱->設定->帳戶->“POP3/IMAP......服務”
- 設定Django伺服器端的,用簡單郵件傳輸協定SMTP(Simple Mail Transfer Protocol) 發送電子郵件
-
設定settings.py
# 發送郵件設定
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 固定寫法
EMAIL_HOST = 'smtp.qq.com' # 騰訊QQ郵箱 SMTP 伺服器位址
EMAIL_PORT = 25 # SMTP服務的端口号
EMAIL_HOST_USER = '[email protected]' # 發送郵件的QQ郵箱
EMAIL_HOST_PASSWORD = '******' # 在QQ郵箱->設定->帳戶->“POP3/IMAP......服務” 裡得到的在第三方登入QQ郵箱授權碼
EMAIL_USE_TLS = True # 與SMTP伺服器通信時,是否啟動TLS連結(安全連結)預設false
複制
視圖函數中
from django.core import mail
mail.send_mail(
subject, #題目
message, # 消息内容
from_email, # 發送者[目前配置郵箱]
recipient_list=['[email protected]'], # 接收者郵件清單
)
複制
項目部署
- 項目部署是指在軟體開發完畢後,将開發機器上運作的開發闆軟體實際安裝到伺服器上進行長期運作
- 部署要分以下幾個步驟進行
在安裝機器上安裝和配置同版本的環境
- django 項目遷移
- $ sudo scp 目前項目源代碼 遠端主機位址和檔案夾
sudo scp /home/tarena/django/mysite1 [email protected]:/home/root/xxx
請輸入root密碼:
複制
3. 用 uwsgi 替代 python3 manage.py runserver 方法啟動伺服器
4. 配置 nginx 反向代理伺服器
5.用 nginx 配置靜态檔案路徑,解決靜态路徑問題
uWSGI 網關接口配置 (ubuntu 18.04 配置)
- WSGI (Web Server Gateway Interface) Web 伺服器網關接口,是 Python 應用程式或架構和 Web 伺服器之間的一種接口,被廣泛使用
- 使用 python manage.py runserver 通常隻在開發和測試環境中使用。
- 當開發結束後,完善的項目代碼需要在一個高效穩定的環境中運作,這時可以使用 WSGI
- uWSGI 是 WSGI 的一種,它實作了 http 協定 WSGI 協定 以及 uwsgi 協定
- 安裝 uWSGI
終端輸入如下指令
sudo pip3 install uwsgi==2.0.18 -i https://pypi.tuna.tsinghua.edu.cn/simple/
複制
檢查是否安裝成功
sudo pip3 freeze|grep -i 'uwsgi'
#如果成功安裝,則會輸出
uWSGI==2.0.18
複制
- 配置 uWSGI
- 添加配置檔案 項目同名檔案夾/uwsgi.ini
如: mysite1/mysite1/uwsgi.ini
[uwsgi]
# 套接字方式的 IP位址:端口号
# socket=127.0.0.1:8000
# Http通信方式的 IP位址:端口号
http=127.0.0.1:8000
# 項目目前工作目錄
chdir=/home/tarena/.../my_project 這裡需要換為項目檔案夾的絕對路徑
# 項目中wsgi.py檔案的目錄,相對于目前工作目錄
wsgi-file=my_project/wsgi.py
# 程序個數
process=4
# 每個程序的線程個數
threads=2
# 服務的pid記錄檔案
pidfile=uwsgi.pid
# 服務的目志檔案位置
daemonize=uwsgi.log
# 開啟主程序管理模式
master=true
複制
- 修改 settings.py 将 DEBUG=True 改為 DEBUG=False
- 修改 settings.py 将 ALLOWED_HOSTS = [] 改為 ALLOWED_HOSTS = [‘網站域名’] 或者 [‘服務監聽的 ip 位址’]
- uWSGI 的運作管理
啟動 uwsgi
$ 進入到項目同名檔案夾下 【即settings.py所在目錄】
$ sudo uwsgi --ini uwsgi.ini
複制
停止 uwsgi
$ 進入到項目同名檔案夾下 【即settings.py所在目錄】
$ sudo uwsgi --stop uwsgi.pid
複制
說明:
- 當 uwsgi 啟動後,目前 django 項目的程式已變成背景守護程序,在關閉目前終端時此程序也不會停止。
- 若執行 stop 操作失敗,則需要執行如下操作殺死程序
ps aux|grep 'uwsgi' -> 檢視uwsgi程序
tarena 103408 0.0 0.9 137172 39984 ? S 10:02 0:01 uwsgi --ini uwsgi.ini
tarena 103410 0.0 0.9 436200 38552 ? Sl 10:02 0:00 uwsgi --ini uwsgi.ini
ps -ef | grep 'uwsgi' | grep -v grep | awk '{print $2}' | xargs sudo kill -9
複制
測試:
- 在浏覽器端輸入 http://127.0.0.1:8000 進行測試
- 注意,此時端口号為 8000
nginx 及反向代理配置
- Nginx 是輕量級的高性能 Web 伺服器,提供了諸如 HTTP 代理和反向代理、負載均衡、緩存等一系列重要特性,在實踐之中使用廣泛。
- C 語言編寫,執行效率高
- nginx 作用
- 負載均衡, 多台伺服器輪流處理請求
- 反向代理
- 原理:
- 用戶端請求 nginx, 再由 nginx 将請求轉發 uWSGI 運作的 django
-
ubuntu 下 nginx 安裝
$ sudo apt install nginx
vim /etc/apt/sources.list
更改國内源
sudo apt-get update
複制
- nginx 配置
- 修改 nginx 的配置檔案 /etc/nginx/sites-enabled/default
# 在server節點下添加新的location項,指向uwsgi的ip與端口。
server {
...
location / {
uwsgi_pass 127.0.0.1:8000; # 重定向到127.0.0.1的8000端口
include /etc/nginx/uwsgi_params; # 将所有的參數轉到uwsgi下
}
...
}
nginx 服務控制
SHELL
1
2
3
$ sudo /etc/init.d/nginx start|stop|restart|status
# 或
$ sudo service nginx start|stop|restart|status
複制
通過 start,stop,restart,status 可能實作 nginx 服務的啟動、停止、重新開機、操作
- 修改 uWSGI 配置
修改項目同名檔案夾/uwsgi.ini 下的 Http 通信方式改為 socket 通信方式
[uwsgi]
# 去掉如下
# http=127.0.0.1:8000
# 改為
socket=127.0.0.1:8000
複制
- 重新開機 uWSGI 服務
進入到 項目同名檔案夾下
$ sudo uwsgi --stop uwsgi.pid
$ sudo uwsgi --ini uwsgi.ini
複制
測試:
在浏覽器端輸入 http://127.0.0.1 進行測試
注意 :
1,此時端口号為 80 (nginx 預設值)
2,Django 中有任何修改 需要重新開機 uwsgi , 否則修改不生效
nginx 配置靜态檔案路徑
- 建立新路徑 - 主要存放 Django 所有靜态檔案 如: /home/tarena/ 項目名_static/
- 在 Django settings.py 中添加新配置
STATIC_ROOT = '/home/tarena/項目名_static/static
#注意 此配置路徑為 存放所有正式環境中需要的靜态檔案
複制
- 進入項目,執行 python3 manage.py collectstatic 。執行該指令後,Django 将項目重所有靜态檔案 複制到 STATIC_ROOT 中 ,包括 Django 内建的靜态檔案【如 admin 背景的樣式】
- Nginx 配置中添加新配置
# file : /etc/nginx/sites-enabled/default
# 新添加location /static 路由配置,重定向到指定的 第一步建立的路徑即可
server {
...
location /static {
# root 第一步建立檔案夾的絕對路徑,如:
root /home/tarena/項目名_static;
}
...
}
複制
404/500 界面
- 在模闆檔案夾内添加 404.html 模版,當視圖觸發 Http404 異常時将會被顯示
- 404.html 僅在釋出版中 (即 setting.py 中的 DEBUG=False 時) 才起作用
- 當向應處理函數觸發 Http404 異常時就會跳轉到 404 界面
from django.http import Http404
def xxx_view( ):
raise Http404 # 直接傳回404
複制
郵件告警
報錯郵件中會顯示一些錯誤的追蹤,這些錯誤追蹤中會出現如 password等敏感資訊,Django已經将配置檔案中的敏感資訊 過濾修改為 多個星号,但是使用者自定義的視圖函數需要使用者手動過濾敏感資訊
1,視圖函數中的局部變量
from django.views.decorators.debug import sensitive_variables
@sensitive_variables('user', 'pw', 'cc')
def process_info(user):
pw = user.pass_word
cc = user.credit_card_number
name = user.name
...
#注意:
#1 若報錯郵件中牽扯到user,pw,cc等局部變量的值,則會将其替換成 *****, 而 name 變量還顯示其真實值
#2 多個裝飾器時,需要将其放在最頂部
#3 若不傳參數,則過濾所有局部變量的值
複制
2,POST送出中的資料
from django.views.decorators.debug import sensitive_post_parameters
@sensitive_post_parameters('password', 'username')
def index(request):
s = request.POST['username'] + request.POST['abcd']
#'abcd' 并不存在,此時引發error
#POST中 username 及 password的值會被替換成 ******
複制