Django-入門

Pycharm-Django

此時打開瀏覽器訪問//127.0.0.1:8000/,你將看到熟悉的火箭標誌頁面。

創建新的APP

1、使用python manage.py startapp demo命令創建一個名為demo的應用,然後把其加入項目配置文件settings.py的INSTALLED_APPS中。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'demo', # 註冊app
]

2、然後編輯/urls.py, 把demo應用的urls也加入到項目的urls中去,如下所示:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('demo.urls')) # 加入app對應urls
]

3、編寫視圖函數和 URL 配置

編輯demo/views.py, 新增一個名為index的視圖函數。每個視圖函數的第一個默認參數都必需是request, 它是一個全局變數。

Django把每個用戶請求封裝成了request對象,它包含里當前請求的所有資訊,比如請求路徑request.path, 當前用戶request.user以及用戶通過POST提交的數據request.POST

index視圖函數通過調用HttpReponse方法列印輸出當前的請求路徑request.path

# demo/views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("請求路徑:{}" .format(request.path))

4、接下來我們要進行URL配置。

新建demo/urls.py, 添加如下程式碼,其作用是將用戶請求的地址與實際需要執行的視圖函數相關聯。

下例中當用戶在瀏覽器中訪問index/時,Django將解析url,並調用執行views.py中的index視圖函數。

# demo/urls.py

from django.urls import path
from . import views

app_name = "demo"
urlpatterns = [
    path('index/', views.index, name='index'),
]

MVT設計模式

1、創建一個app (與上面的步驟相同)

2、創建模型(M)

編輯目錄下models.py創建模型。

當你使用python manage.py makemigrationspython manage.py migrate命令時,Django會自動為你在資料庫創建數據表(默認使用的資料庫是免費的sqlite)。

    # tasks/models.py
    
    from django.db import models
    
    class Status(models.TextChoices):
        UNSTARTED = 'u', "Not started yet"
        ONGOING = 'o', "Ongoing"
        FINISHED = 'f', "Finished"
    
    # Task模型
    class Task(models.Model):
        name = models.CharField(verbose_name="Task name", max_length=65, unique=True)
        status = models.CharField(verbose_name="Task status", max_length=1, choices=Status.choices)
    
        def __str__(self):
            return self.name

3、編寫視圖並配置路由URL(V)

接下來我們要編輯視圖views.py,並新增一個視圖函數, 用於展示任務清單。

該視圖函數從資料庫讀取了對象列表,指定了渲染模板並向模板傳遞了數據。

# tasks/views.py
from django.shortcuts import render
from .models import Task

# 任務清單
def task_list(request):
    # 從資料庫獲取Task對象列表
    tasks = Task.objects.all()
    # 指定渲染模板並向模板傳遞數據
    return render(request, "tasks/task_list.html", { "tasks": tasks,})

光編寫視圖(views.py)還不夠,我們還得為寫好的視圖函數配置路由,這樣才能將視圖函數與用戶的請求地址建立好對應關係。

4、編輯或創建tasks/urls.py, 添加如下程式碼:

# tasks/urls.py
from django.urls import path
from . import views

# namespace
app_name = 'tasks'

urlpatterns = [
    # Retrieve task list
    path('', views.task_list, name='task_list'),
]

這樣當用戶訪問/tasks/時,Django將調用task_list視圖函數。這個視圖函數將同時與資料庫和模板進行交互。

編輯模板(T)

最後我們要創建task_list.html用於展示視圖傳來的任務列表數據。

這個文件的完整路徑為tasks/templates/tasks/task_list.html

Django提供了自己的模板語言,包括常見的判斷和循環,專門用來渲染模板。

# tasks/templates/tasks/task_list.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Task List</title>
</head>
<body>
<h3>Task List</h3>
{% for task in tasks %}
    <p>{{ forloop.counter }}. {{ task.name }} - {{ task.get_status_display }}
    </p>
{% endfor %}
</body>
</html>

當然此時如果你通過瀏覽器訪問/tasks/, 還看不到任何內容,這是因為你的數據表裡還沒有任何數據。你可以通過django的admin添加或新增task_create視圖實現。

CRUD-DEMO

在 MVT設計模式 中添加程式碼。

1、使用ModelForm類創建了TaskForm,在創建任務或更新任務時需要用到這個表單。

 # tasks/forms.py
 from .models import Task
 from django import forms

 class TaskForm(forms.ModelForm):

     class Meta:
         model = Task
         fields = "__all__"

2、編寫路由URLConf及視圖

# tasks/urls.py
 from django.urls import path, re_path
 from . import views

 # namespace
 app_name = 'tasks'

 urlpatterns = [
     # Create a task
     path('create/', views.task_create, name='task_create'),

     # Retrieve task list
     path('', views.task_list, name='task_list'),

     # Retrieve single task object
     re_path(r'^(?P<pk>\d+)/$', views.task_detail, name='task_detail'),

     # Update a task
     re_path(r'^(?P<pk>\d+)/update/$', views.task_update, name='task_update'),

     # Delete a task
     re_path(r'^(?P<pk>\d+)/delete/$', views.task_delete, name='task_delete'),
 ]
# tasks/views.py

from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from .models import Task
from .forms import TaskForm


# Create a task
def task_create(request):
    # 如果用戶通過POST提交,通過request.POST獲取提交數據
    if request.method == "POST":
        # 將用戶提交數據與TaskForm表單綁定
        form = TaskForm(request.POST)
        # 表單驗證,如果表單有效,將數據存入資料庫
        if form.is_valid():
            form.save()
            # 跳轉到任務清單
            return redirect(reverse("tasks:task_list"))
    else:
        # 否則空表單
        form = TaskForm()
    return render(request, "tasks/task_form.html", {"form": form, })


# Retrieve task list
def task_list(request):
    # 從資料庫獲取任務清單
    tasks = Task.objects.all()
    # 指定渲染模板並傳遞數據
    return render(request, "tasks/task_list.html", {"tasks": tasks, })


# Retrieve a single task
def task_detail(request, pk):
    # 從url里獲取單個任務的pk值,然後查詢資料庫獲得單個對象
    task = get_object_or_404(Task, pk=pk)
    return render(request, "tasks/task_detail.html", {"task": task, })


# Update a single task
def task_update(request, pk):
    # 從url里獲取單個任務的pk值,然後查詢資料庫獲得單個對象實例
    task_obj = get_object_or_404(Task, pk=pk)
    if request.method == 'POST':
        form = TaskForm(instance=task_obj, data=request.POST)
        if form.is_valid():
            form.save()
            return redirect(reverse("tasks:task_detail", args=[pk, ]))
    else:
        form = TaskForm(instance=task_obj)
    return render(request, "tasks/task_form.html", {"form": form, "object": task_obj})


# Delete a single task
def task_delete(request, pk):
    # 從url里獲取單個任務的pk值,然後查詢資料庫獲得單個對象
    task_obj = get_object_or_404(Task, pk=pk)
    task_obj.delete()  # 刪除然後跳轉
    return redirect(reverse("tasks:task_list"))

3、前端

# tasks/templates/tasks/task_list.html
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Task List</title>
 </head>
 <body>
 <h3>Task List</h3>
 {% for task in tasks %}
     <p>{{ forloop.counter }}. {{ task.name }} - {{ task.get_status_display }}
         (<a href="{% url 'tasks:task_update' task.id %}">Update</a> |
         <a href="{% url 'tasks:task_delete' task.id %}">Delete</a>)
     </p>
 {% endfor %}
 <p> <a href="{% url 'tasks:task_create' %}"> + Add A New Task</a></p>
 </body>
 </html>


 # tasks/templates/tasks/task_detail.html
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Task Detail</title>
 </head>
 <body>
 <p> Task Name: {{ task.name }} | <a href="{% url 'tasks:task_update' task.id %}">Update</a> |
     <a href="{% url 'tasks:task_delete' task.id %}">Delete</a>
 </p>
 <p> Task Status: {{ task.get_status_display }} </p>
 <p> <a href="{% url 'tasks:task_list' %}">View All Tasks</a> |
     <a href="{% url 'tasks:task_create'%}">New Task</a>
 </p>
 </body>
 </html>


 # tasks/templates/tasks/task_form.html
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>{% if object %}Edit Task {% else %} Create New Task {% endif %}</title>
 </head>
 <body>
 <h3>{% if object %}Edit Task {% else %} Create New Task {% endif %}</h3>
     <form action="" method="post" enctype="multipart/form-data">
         {% csrf_token %}
         {{ form.as_p }}
         <p><input type="submit" class="btn btn-success" value="Submit"></p>
     </form>
 </body>
 </html> 

執行下面命令後看效果:

python manage.py makemigrations

python manage.py migrate

python manage.py runserver

model

模型的組成

一個標準的Django模型分別由模型欄位、META選項和方法三部分組成。

Django官方編碼規範建議按如下方式排列:

  • 定義的模型欄位:包括基礎欄位和關係欄位
  • 自定義的Manager方法:改變模型
  • class Meta選項: 包括排序、索引等等(可選)。
  • def __str__():定義單個模型實例對象的名字(可選)。
  • def save():重寫save方法(可選)。
  • def get_absolute_url():為單個模型實例對象生成獨一無二的url(可選)
  • 其它自定義的方法。

模型的欄位

models.Model提供的常用模型欄位包括基礎欄位和關係欄位。

基礎欄位

**CharField() **

一般需要通過max_length = xxx 設置最大字元長度。

如不是必填項,可設置blank = True和default = 『『。

如果用於username, 想使其唯一,可以設置unique = True

如果有choice選項,可以設置 choices = XXX_CHOICES

**TextField() **

適合大量文本,max_length = xxx選項可選。

**DateField() 和DateTimeField() **

可通過default=xx選項設置默認日期和時間。

  • 對於DateTimeField: default=timezone.now – 先要from django.utils import timezone
  • 如果希望自動記錄一次修改日期(modified),可以設置: auto_now=True
  • 如果希望自動記錄創建日期(created), 可以設置auto_now_add=True

**EmailField() **

如不是必填項,可設置blank = True和default = 『。

一般Email用於用戶名應該是唯一的,建議設置unique = True

IntegerField(), SlugField(), URLField(),BooleanField()

可以設置blank = True or null = True。

對於BooleanField一般建議設置defaut = True or False

**FileField(upload_to=None, max_length=100) – 文件欄位 **

  • upload_to = 「/some folder/」:上傳文件夾路徑
  • max_length = xxxx:文件最大長度

**ImageField (upload_to=None, max_length=100,)- 圖片欄位 **

  • upload_to = 「/some folder/」: 指定上傳圖片路徑

關係欄位

OneToOneField(to, on_delete=xxx, options) – 單對單關係

  • to必需指向其他模型,比如 Book or 『self』 .
  • 必需指定on_delete選項(刪除選項): i.e, 「on_delete = models.CASCADE」 or 「on_delete = models.SET_NULL」 .
  • 可以設置 「related_name = xxx」 便於反向查詢。

ForeignKey(to, on_delete=xxx, options) – 單對多關係

  • to必需指向其他模型,比如 Book or 『self』 .
  • 必需指定on_delete選項(刪除選項): i.e, 「on_delete = models.CASCADE」 or 「on_delete = models.SET_NULL」 .
  • 可以設置」default = xxx」 or 「null = True」 ;
  • 如果有必要,可以設置 「limit_choices_to = 「,
  • 可以設置 「related_name = xxx」 便於反向查詢。

ManyToManyField(to, options) – 多對多關係

  • to 必需指向其他模型,比如 User or 『self』 .
  • 設置 「symmetrical = False 「 表示多對多關係不是對稱的,比如A關注B不代表B關注A
  • 設置 「through = 'intermediary model' 「 如果需要建立中間模型來搜集更多資訊。
  • 可以設置 「related_name = xxx」 便於反向查詢。

示例:一個人加入多個組,一個組包含多個人,我們需要額外的中間模型記錄加入日期和理由。

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

對於OneToOneFieldForeignKey, on_delete選項和related_name是兩個非常重要的設置,前者決定了了關聯外鍵刪除方式,後者決定了模型反向查詢的名字。

on_delete刪除選項

Django提供了如下幾種關聯外鍵刪除選項, 可以根據實際需求使用。

  • CASCADE:級聯刪除。當你刪除publisher記錄時,與之關聯的所有 book 都會被刪除。
  • PROTECT: 保護模式。如果有外鍵關聯,就不允許刪除,刪除的時候會拋出ProtectedError錯誤,除非先把關聯了外鍵的記錄刪除掉。例如想要刪除publisher,那你要把所有關聯了該publisher的book全部刪除才可能刪publisher。
  • SET_NULL: 置空模式。刪除的時候,外鍵欄位會被設置為空。刪除publisher後,book 記錄裡面的publisher_id 就置為null了。
  • SET_DEFAULT: 置默認值,刪除的時候,外鍵欄位設置為默認值。
  • SET(): 自定義一個值。
  • DO_NOTHING:什麼也不做。刪除不報任何錯,外鍵值依然保留,但是無法用這個外鍵去做查詢。

related_name選項

related_name用於設置模型反向查詢的名字,非常有用。

# models.py
from django.db import models
 
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=60)
 
    def __str__(self):
        return self.name

# 將related_name設置為books
class Book(models.Model):
    name = models.CharField(max_length=30)
    description = models.TextField(blank=True, default='')
    publisher = ForeignKey(Publisher,on_delete=models.CASCADE, related_name='books')
    add_date = models.DateField(auto_now_add=True)
 
    def __str__(self):
        return self.name

我們再來對比一下如何通過publisher查詢其出版的所有書籍,你覺得哪個更好呢?

  1. 設置related_name前:publisher.book_set.all
  2. 設置related_name後:publisher.books.all

模型的META選項

  • abstract=True: 指定該模型為抽象模型
  • proxy=True: 指定該模型為代理模型
  • verbose_name=xxxverbose_name_plural=xxx: 為模型設置便於人類閱讀的別名
  • db_table= xxx: 自定義數據表名
  • odering=['-pub-date']: 自定義按哪個欄位排序,-代表逆序
  • permissions=[]: 為模型自定義許可權
  • managed=False: 默認為True,如果為False,Django不會為這個模型生成數據表
  • indexes=[]: 為數據表設置索引,對於頻繁查詢的欄位,建議設置索引
  • constraints=: 給資料庫中的數據表增加約束。

模型的方法

標準方法

以下三個方法是Django模型自帶的三個標準方法:

  • def __str__():給單個模型對象實例設置人為可讀的名字(可選)。
  • def save():重寫save方法(可選)。
  • def get_absolute_url():為單個模型實例對象生成獨一無二的url(可選)

除此以外,我們經常自定義方法或Manager方法

ORM數據增刪改查介面

我們用到的Article模型如下所示:

from django.db import models

class Article(models.Model):
    title = models.CharField('標題', max_length=200, unique=True)
    body = models.TextField('正文')
    created = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.title

對於新增數據,Django提供了兩種方法,save()create()方法。

方法一:save方法

from XX.models import Article

article = Article(title="My first article", body="My first article body")
article.save()

注意: 該方法如果不主動選擇save(), 創建的對象實例只會存於記憶體之中,不會保存到資料庫中去。

正因為如此,Django還提供了更便捷的create方法。

方法二:create方法

article = Article.objects.create(title="My first article", body="My first article body")

為了避免重複創建數據表中已存在的條目,Django還提供了get_or_create方法。

它會返回查詢到的或新建的模型對象實例,還會返回這個對象實例是否是剛剛創建的。

obj, created = Article.objects.get_or_create(title="My first article", body="My first article body")

注意: 對Django自帶auth模組中的User模型操作,比如創建新的用戶時,請用create_user方法。該方法會將密碼自動加Hash存儲到資料庫中, 如下所示:

from django.contrib.auth.models import User
user = User.objects.create_user(username='john, email='[email protected]',password='somepwd')

方法三:bulk_create方法

在Django中向資料庫中插入多條數據時,每使用save或create方法保存一條就會執行一次SQL。

而Django提供的bulk_create方法可以一次SQL添加多條數據,效率要高很多,如下所示:

# 記憶體生成多個對象實例
articles  = [Article(title="title1", body="body1"), Article(title="title2", body="body2"), Article(title="title3", body="body3")]

# 執行一次SQL插入數據
Article.objects.bulk_create(articles)

刪即從數據表中刪除一個已有條目。Django也允許同時刪除一條或多條數據。

刪除單條數據

# 刪除第5篇文章
Article.objects.get(pk=5).delete() 

刪除部分數據

# 刪除標題含有python的文章
Article.objects.filter(title__icontains="python").delete() 

刪除所有數據

# 慎用
Article.objects.all().delete() 

改既可以用save方法,也可以用update方法。其區別在於save方法不僅可以更新數據中現有對象數據,還可以創建新的對象。而update方法只能用於更新已有對象數據。一般來說,如果要同時更新多個對象數據,用update方法或bulk_update方法更合適。

方法一: save方法

article = Article.objects.get(id=1)
article.title = "New article title"
article.save()

方法二:update方法更新單篇文章

article = Article.objects.get(id=1).update(title='new title')

方法三:update方法同時更新多篇文章

# 更新所有文章標題
article = Article.objects.filter(title__icontains='python').update(title='Django')

方法四: bulk_update方法

bulk_create方法類似,Django還提供了bulk_update方法可以對資料庫里的數據進行批量更新。

查主要使用get, filter及exclude方法,而且這些方法是可以聯用的。

查詢所有數據

# QuerySet類型,實例對象列表
Article.objects.all() 
# 字典列表
Article.objects.all().values() 
# 只獲取title-字典形式
Article.objects.all().values('title') 
# 只獲取title列表- 元組形式,只有value,沒有key
Article.objects.all().values_list('title')
# 只獲取title列表,只有value
Article.objects.all().values_list('title', flat=True)

查詢單條數據

article = Article.objects.get(id=11)

當上述查詢有個問題,如果id不存在,會拋出錯誤。還有一種方式是使用filter方法, 這樣即使id不存在也不會報錯。

article = Article.objects.filter(id=1).first()

一個更好的方式是使用Django提供的get_object_or_404方法,如下所示:

from django.shortcuts import get_object_or_404 
article = get_object_or_404(Article, pk=1) 

查詢多條數據

按大於、小於及不等於查詢

# gte:大於等於,lte:小於等於
articles = Article.objects.filter(id__gte=2).filter(id__lte=11)
# 不等於
articles = Article.objects.exclude(id=10)

按範圍查詢

# 按範圍查詢,in或者range
articles = Article.objects.filter(id__range=[2, 11])
articles = Article.objects.filter(id__in=[3, 6,9])

字元串模糊查詢

#標題包含python,若忽略大小寫使用icontains
articles = Article.objects.filter(title__contains='python')

#標題以python開頭,若忽略大小寫使用istartswith
articles = Article.objects.filter(title__startswith='python')

#標題是python結尾的,若忽略大小寫使用__iendswith
articles = Article.objects.filter(title__endswith='python')

按日期時間查詢

# 查詢2021年發表的文章
Article.objects.filter(created__year=2021)

# 查詢2021年3月19日發表的文章
import datetime
Article.objects.filter(created__date=datetime.date(2021,3,19))

# 查詢2021年1月1日以後發表的文章
Article.objects.filter(created__gt=datetime.date(2021, 1, 1))

# 與當前時間相比,查詢即將發表的文章
from django.utils import timezone
Article.objects.filter(created__gt=timezone.now())

# 按絕對時間範圍查詢,查詢2021年1月1日到6月30日發表文章
article = Aritlce.objects.filter(created__gte=datetime.date(2021, 1, 1),
pub_date__lte=datetime.date(2021, 6, 30))

# 按相對時間範圍查詢,用range查詢3月1日以後30天內發表文章
startdate = datetime.date(2021, 3, 1)
enddate = startdate + datetime.timedelta(days=30)
Article.objects.filter(pub_date__range=[startdate, enddate])

切片、排序、去重

# 切片
articles = Article.objects.filter(created__year=2021)[:5]

# 排序:created正序,-表示逆序
articles = Article.objects.all().order_by('-created')

# 去重
Article.objects.filter(title__icontains='python').distinct()

高級Q和F方法

Q方法

有時候我們需要執行or邏輯的條件查詢,這時使用Q方法就可以了,它可以連接多個查詢條件。Q對象前面加~可以表示否定。

from django.db.models import Q
# 查詢標題含有python或Django的文章
article = Article.objects.filter(Q(title__icontains='python')|Q(title__icontains='django'))
# 查詢標題含有python,不含有Django的文章
article = Article.objects.filter(Q(title__icontains='python')|~Q(title__icontains='django'))

F方法

使用F()方法可以實現基於自身欄位值來過濾一組對象,它還支援加、減、乘、除、取模和冪運算等算術操作。

from django.db.models import F
Article.objects.filter(n_commnets__gt=F('n_pingbacks'))
Article.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

Django-test

from django.test import TestCase

# Create your tests here.
class test(TestCase):
    pass

路由配置

一個優美的URL不僅層次分明、邏輯清晰,而且便於搜索引擎收錄。一個糟糕的URL不僅可讀性差,而且易造成程式衝突。

URL conf是如何工作的?

假如我們有一個blog的部落格應用,你需要編寫兩個視圖函數,一個用於展示文章列表,一個用於展示文章詳情,你的urls.pyviews.py正常情況下應如下所示:

# blog/urls.py
from django.urls import path
from . import views
 
urlpatterns = [
    path('blog/', views.index),
    path('blog/articles/<int:id>/', views.article_detail),
]
 
# blog/views.py
def index(request):
    # 展示所有文章
   
def article_detail(request, id):
    # 展示某篇具體文章

那麼上面這段程式碼是如何工作的呢?

  • 當用戶在瀏覽器輸入/blog/時,URL收到請求後會調用視圖views.py里的index方法,展示所有文章。
  • 當用戶在瀏覽器輸入/blog/article/<int:id>/時,URL不僅調用了views.py里的article_detail方法,而且還把參數文章id通過<>括弧的形式傳遞給了視圖。int這裡代表只傳遞整數,傳遞的參數名字是id。

在上述程式碼中,我們通過urlpatterns列表的url-視圖映射關係列表起了決定性作用,起到了任務調度的作用。

注意:注意當你配置URL時,別忘了把你的應用(blog)的urls加入到項目的URL配置里(mysite/urls.py), 如下圖所示:

from django.urls import include, path

urlpatterns = [
    path('', include('blog.urls')),
    ...
]

path和re_path方法

Django提供了兩種設計URL的方法: pathre_path,它們均支援向視圖函數或類傳遞參數。

path是正常參數傳遞,re_path是採用正則表達式regex匹配。pathre_path傳遞參數方式如下:

  • path方法:採用雙尖括弧<變數類型:變數名><變數名>傳遞。
  • re_path方法: 採用命名組(?P<變數名>表達式)的方式傳遞參數。

下例中,分別以pathre_path 定以了兩個urls,它們是等效的,把文章的id(整數類型)傳遞給了視圖。

re_path里引號前面的小寫r表示引號里為正則表達式, ^代表開頭,$代表以結尾,\d+代表正整數。

# blog/urls.py
from django.urls import path, re_path
from . import views
 
urlpatterns = [
    path('blog/articles/<int:id>/', views.article_detail, name = 'article_detail'),
    re_path(r'^blog/articles/(?P<id>\d+)/$', views.article_detail, name='article_detail'),
]
 
# blog/views.py
def article_detail(request, id):
    # 展示某篇文章

在使用pathre_path方法設計urls需注意:

  • url中的參數名要用尖括弧,而不是圓括弧;
  • 匹配模式的最開頭不需要添加斜杠/,但建議以斜杠結尾;
  • 使用re_path時不一定總是以$結尾,有時不能加。
from django.urls import include, re_path

urlpatterns = [
    re_path(r'^blog/', include('blog.urls')),
    ...
]

URL指向基於類的視圖(View)

目前pathre_path都只能指向視圖view里的一個函數或方法,而不能直接指向一個基於類的視圖(Class based view)。

Django提供了一個額外as_view()方法,可以將一個類偽裝成方法。

這點在當你使用Django自帶的類視圖或自定義的類視圖時非常重要。

具體使用方式如下:

# blog/urls.py
from django.urls import path, re_path
from . import views
 
urlpatterns = [
    # path('blog/articles/', views.article_list, name = 'article_list'),
    path('blog/articles/', views.ArticleList.as_view(), name='article_list'),
]
 
# View (in blog/views.py)
from django.views.generic import ListView
from .views import Article
 
class ArticleList(ListView):
    queryset = Article.objects.filter(date__lte=timezone.now()).order_by('date')[:5]
    context_object_name = 'article_list『
    template_name = 'blog/article_list.html'

模板

模板文件有兩種, 一種是屬於整個項目(project)的模板,一種是屬於某個應用(app)的模板。

模板文件的放置路徑必需正確, 否則Django找不到模板容易出現TemplateDoesNotExist的錯誤。

項目模板

屬於項目的模板文件路徑一般是項目根目錄下的templates文件夾。

除此以外, 你還需要在settings.py種顯示地將模板目錄設置為BASE_DIR目錄下的templates文件夾。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]

應用模板

屬於單個應用的模板文件路徑一般是app目錄下的app/templates/app文件夾,這樣做的好處是可以避免模板命名衝突。

下圖以部落格項目為例展示了項目模板文件和應用模板文件正確的存放路徑。

myproject/ # 項目名
    manage.py
    myproject/
        __init__.py
        urls.py
        wsgi.py
        settings.py
    blog/ # 應用名
        __init__.py
        models.py
        managers.py
        views.py
        urls.py
        templates/ # 應用模板文件
            blog/
                base.html
                list.html
                detail.html
     templates/ # 項目模板文件
         base.html
         index.html
     requirements/
         base.txt
         dev.txt
         test.txt
         prod.txt

對於上面這個項目布局,在使用render方法指定渲染模板時,無需給出完整的路徑,只給出相對於templates的路徑即可,比如:

# 指定項目模板
return render(request, "index.html", { "msg": "hello world!",})

# 指定應用模板
return render(request, "blog/list.html", { "articles": articles,})

Django-admin

1、初始化

python manage.py createsuperuser

2、根據提示設置用戶名、郵箱和密碼:

用戶名 (leave blank to use 'admin'):
電子郵件地址: 
Password: 
Password (again): 
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

MySQL

第一步: 安裝MySQL

第二步 創建資料庫名和用戶

第三步 安裝第三方庫mysqlclient

Django項目中操作MySQL,官方推薦mysqlclient這個庫。

pip install mysqlclient

第四步 修改配置文件settings.py

修改項目文件夾里的settings.py的文件,添加創建的資料庫和用戶資訊。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   # 資料庫引擎
        'NAME': 'mydb',         # 資料庫名,Django不會幫你創建,需要自己進入資料庫創建。
        'USER': 'myuser',       # 設置的資料庫用戶名
        'PASSWORD': 'mypass',   # 設置的密碼
        'HOST': 'localhost',    # 本地主機或資料庫伺服器的ip
        'PORT': '3306',         # 資料庫使用的埠
    }
}

另一種設置方式是使用OPTIONS和配置文件my.cnf進行設置。

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}

# my.cnf
[client]
database = mydb
user = myuser
password = mypass
default-character-set = utf8

設置好後,連續使用如下命令如果沒有出現錯誤,那麼恭喜你已經在Django項目中使用MySQL資料庫啦。

python manage.py makemigrations                                                              
python manage.py migrate

Cookie和Session

Cookie

django中使用cookie驗證用戶是否已登錄的一個示例。

用戶首次登錄時設置cookie,再次請求時驗證請求攜帶的cookie。

# 如果登錄成功,設置cookie
def login(request):
    if request.method == 'POST':
        form = LoginForm(request.POST)
        
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            user = User.objects.filter(username__exact=username, password__exact=password)

            if user:
                response = HttpResponseRedirect('/index/')
                # 將username寫入瀏覽器cookie,有效時間為360秒
                response.set_cookie('username', username, 360)
                return response
            else:
                return HttpResponseRedirect('/login/')
                                                           
    else:
        form = LoginForm()

    return render(request, 'users/login.html', {'form': form})


# 通過cookie判斷用戶是否已登錄
def index(request):
    # 讀取客戶端請求攜帶的cookie,如果不為空,表示為已登錄帳號
    username = request.COOKIES.get('username', '')
    if not username:
        return HttpResponseRedirect('/login/')
    return render(request, 'index.html', {'username': username})

Session

第一步:檢查基本設置

Django中使用session首選需要確保settings.py中已開啟了SessionMiddleware中間件。

'django.contrib.sessions.middleware.SessionMiddleware',

Django默認使用資料庫存儲每個session的sessionid, 所以你還需確保INSTALLED_APPS 是包含如下app:

'django.contrib.sessions',

當然你還可以使用更快的文件或快取來存儲會話資訊,可以通過SESSION_ENGINE設置就行。

第二步:使用session

request.session是一個字典,你可以在視圖和模板中直接使用它。

# 設置session的值
request.session['key'] = value
request.session.set_expiry(time): 設置過期時間,0表示瀏覽器關閉則失效

# 獲取session的值
request.session.get('key',None)

# 刪除session的值, 如果key不存在會報錯
del request.session['key']

# 判斷一個key是否在session里
'fav_color' in request.session

# 獲取所有session的key和value
request.session.keys()
request.session.values()
request.session.items()

另外,settings.py 還有兩項有關session比較重要的設置:

1、SESSION_COOKIE_AGE:以秒為單位,session的有效時間,可以通過set_expiry 方法覆蓋。

2、SESSION_EXPIRE_AT_BROWSER_CLOSE:默認為Flase,是否設置為瀏覽器關閉,會話自動失效。

Session使用示例:

下面是django中使用session進行用戶登錄和登出的一個示例。

用戶首次登錄時設置session,退出登錄時刪除session。

# 如果登錄成功,設置session
def login(request):
    if request.method == 'POST':
        form = LoginForm(request.POST)

        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            user = User.objects.filter(username__exact=username, password__exact=password)
            if user:
                # 將username寫入session,存入伺服器
                request.session['username'] = username
                return HttpResponseRedirect('/index/')
            else:
                return HttpResponseRedirect('/login/')
    else:
        form = LoginForm()

    return render(request, 'users/login.html', {'form': form})


# 通過session判斷用戶是否已登錄
def index(request):
    # 獲取session中username
    username = request.session.get('username', '')
    if not username:
        return HttpResponseRedirect('/login/')
    return render(request, 'index.html', {'username': username})

# 退出登錄
def logout(request):
    try:
        del request.session['username']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

例子:通過session控制不讓用戶連續評論兩次的例子。

實際應用中我們還可以通過session來控制用戶登錄時間,記錄訪問歷史,記錄購物車資訊等等。

from django.http import HttpResponse

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

上傳文件

Django文件上傳需要考慮的重要事項

文件或圖片一般通過表單進行。用戶在前端點擊文件上傳,然後以POST方式將數據和文件提交到伺服器。

伺服器在接收到POST請求後需要將其存儲在伺服器上的某個地方。

Django默認的存儲地址是相對於根目錄的/media/文件夾,存儲的默認文件名就是文件本來的名字。

上傳的文件如果不大於2.5MB,會先存入伺服器記憶體中,然後再寫入磁碟。

如果上傳的文件很大,Django會把文件先存入臨時文件,再寫入磁碟。


Django默認處理方式會出現一個問題,所有文件都存儲在一個文件夾里。

不同用戶上傳的有相同名字的文件可能會相互覆蓋。

另外用戶還可能上傳一些不安全的文件如js和exe文件,我們必需對允許上傳文件的類型進行限制。

因此我們在利用Django處理文件上傳時必需考慮如下3個因素:

  • 設置存儲上傳文件的文件夾地址
  • 對上傳文件進行重命名
  • 對可接受的文件類型進行限制(表單驗證)

注意:以上事項對於上傳圖片是同樣適用的。

目錄結構

需要將file_upload這個app加入到我們項目里,然後設置/media/和/STATIC_URL/文件夾。

上傳的文件都會放在/media/文件夾里。我們還需要使用css和js這些靜態文件,所以需要設置STATIC_URL。

#file_project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'file_upload',# 新增
]

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

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

#file_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('file/', include("file_upload.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  • 創建模型

使用File模型包括fileupload_method兩個欄位。通過upload_to選項指定了文件上傳後存儲的地址,並對上傳的文件名進行了重命名。

#file_upload/models.py
from django.db import models
import os
import uuid

# Create your models here.
# Define user directory path
def user_directory_path(instance, filename):
    ext = filename.split('.')[-1]
    filename = '{}.{}'.format(uuid.uuid4().hex[:10], ext)
    return os.path.join("files", filename)

class File(models.Model):
    file = models.FileField(upload_to=user_directory_path, null=True)
    upload_method = models.CharField(max_length=20, verbose_name="Upload Method")

注意:如果你不使用ModelForm,你還需要手動編寫程式碼存儲上傳文件。

  • URLConf配置

本項目一共包括3個urls, 分別對應普通表單上傳,ModelForm上傳和顯示文件清單。

#file_upload/urls.py
from django.urls import re_path, path
from . import views

# namespace
app_name = "file_upload"

urlpatterns = [
    # Upload File Without Using Model Form
    re_path(r'^upload1/$', views.file_upload, name='file_upload'),

    # Upload Files Using Model Form
    re_path(r'^upload2/$', views.model_form_upload, name='model_form_upload'),

    # View File List
    path('file/', views.file_list, name='file_list'),

]
  • 使用一般表單上傳文件

我們先定義一個一般表單FileUploadForm,並通過clean方法對用戶上傳的文件進行驗證,如果上傳的文件名不以jpg, pdf或xlsx結尾,將顯示錶單驗證錯誤資訊。

#file_upload/forms.py

from django import forms
from .models import File

# Regular form
class FileUploadForm(forms.Form):
    file = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}))
    upload_method = forms.CharField(label="Upload Method", max_length=20,
                                   widget=forms.TextInput(attrs={'class': 'form-control'}))
    def clean_file(self):
        file = self.cleaned_data['file']
        ext = file.name.split('.')[-1].lower()
        if ext not in ["jpg", "pdf", "xlsx"]:
            raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")
        # return cleaned data is very important.
        return file

注意: 使用clean方法對錶單欄位進行驗證時,別忘了return驗證過的數據,即cleaned_data

只有返回了cleaned_data, 視圖中才可以使用form.cleaned_data.get(『xxx』)獲取驗證過的數據。

對應一般文件上傳的視圖file_upload方法如下所示:

當用戶的請求方法為POST時,我們通過form.cleaned_data.get('file')獲取通過驗證的文件,並調用自定義的handle_uploaded_file方法來對文件進行重命名,寫入文件。

如果用戶的請求方法不為POST,則渲染一個空的FileUploadFormupload_form.html里。定義了一個file_list方法來顯示文件清單。

#file_upload/views.py

from django.shortcuts import render, redirect
from .models import File
from .forms import FileUploadForm, FileUploadModelForm
import os
import uuid
from django.http import JsonResponse
from django.template.defaultfilters import filesizeformat

# Create your views here.


# Show file list
def file_list(request):
    files = File.objects.all().order_by("-id")
    return render(request, 'file_upload/file_list.html', {'files': files})

# Regular file upload without using ModelForm
def file_upload(request):
    if request.method == "POST":
        form = FileUploadForm(request.POST, request.FILES)
        if form.is_valid():
            # get cleaned data
            upload_method = form.cleaned_data.get("upload_method")
            raw_file = form.cleaned_data.get("file")
            new_file = File()
            new_file.file = handle_uploaded_file(raw_file)
            new_file.upload_method = upload_method
            new_file.save()
            return redirect("/file/")
    else:
        form = FileUploadForm()

    return render(request, 'file_upload/upload_form.html', 
                  {'form': form, 'heading': 'Upload files with Regular Form'}
                 )

def handle_uploaded_file(file):
    ext = file.name.split('.')[-1]
    file_name = '{}.{}'.format(uuid.uuid4().hex[:10], ext)

    # file path relative to 'media' folder
    file_path = os.path.join('files', file_name)
    absolute_file_path = os.path.join('media', 'files', file_name)

    directory = os.path.dirname(absolute_file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

    with open(absolute_file_path, 'wb+') as destination:
        for chunk in file.chunks():
            destination.write(chunk)

    return file_path

注意:

  • handle_uploaded_file方法里文件寫入地址必需是包含/media/的絕對路徑,如果/media/files/xxxx.jpg,而該方法返回的地址是相對於/media/文件夾的地址,如/files/xxx.jpg。存在數據中欄位的是相對地址,而不是絕對地址。
  • 構建文件寫入絕對路徑時請用os.path.join方法,因為不同系統文件夾分隔符不一樣。寫入文件前一個良好的習慣是使用os.path.exists檢查目標文件夾是否存在,如果不存在先創建文件夾,再寫入。

上傳表單模板upload_form.html程式碼如下:

#file_upload/templates/upload_form.html
{% extends "file_upload/base.html" %}
{% block content %}
{% if heading %}
<h3>{{ heading }}</h3>
{% endif %}

<form action="" method="post" enctype="multipart/form-data" >
  {% csrf_token %}
  {{ form.as_p }}
 <button class="btn btn-info form-control " type="submit" value="submit">Upload</button>
</form>
{% endblock %} 

顯示文件清單模板file_list.html程式碼如下所示:

# file_upload/templates/file_list.html
{% extends "file_upload/base.html" %}

{% block content %}
<h3>File List</h3>
<p> <a href="/file/upload1/">RegularFormUpload</a> | <a href="/file/upload2/">ModelFormUpload</a>
    | <a href="/file/upload3/">AjaxUpload</a></p>
{% if files %}
<table class="table table-striped">
    <tbody>
    <tr>
        <td>Filename & URL</td>
        <td>Filesize</td>
        <td>Upload Method</td>
    </tr>
    {% for file in files %}
    <tr>
        <td><a href="{{ file.file.url }}">{{ file.file.url }}</a></td>
        <td>{{ file.file.size | filesizeformat }}</td>
        <td>{{ file.upload_method }}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>

{% else %}

<p>No files uploaded yet. Please click <a href="{% url 'file_upload:file_upload' %}">here</a>
    to upload files.</p>
{% endif %}
{% endblock %}

注意:

  • 對於上傳的文件我們可以調用file.url, file.namefile.size來查看上傳文件的鏈接,地址和大小。

  • 上傳文件的大小默認是以B顯示的,數字非常大。使用Django模板過濾器filesizeformat可以將文件大小顯示為人們可讀的方式,如MB,KB。

  • 使用ModelForm上傳文件

使用ModelForm上傳是推薦的上傳方式,前提是你已經在模型中通過upload_to選項自定義了用戶上傳文件存儲地址,並對文件進行了重命名。

首先要自定義自己的FileUploadModelForm,由File模型重建的。

程式碼如下所示:

#file_upload/forms.py
from django import forms
from .models import File

# Model form
class FileUploadModelForm(forms.ModelForm):
    class Meta:
        model = File
        fields = ('file', 'upload_method',)
        widgets = {
            'upload_method': forms.TextInput(attrs={'class': 'form-control'}),
            'file': forms.ClearableFileInput(attrs={'class': 'form-control'}),
        }

    def clean_file(self):
        file = self.cleaned_data['file']
        ext = file.name.split('.')[-1].lower()
        if ext not in ["jpg", "pdf", "xlsx"]:
            raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")
        # return cleaned data is very important.
        return file

使用ModelForm處理文件上傳的視圖model_form_upload方法非常簡單,只需調用form.save()即可,無需再手動編寫程式碼寫入文件。

#file_upload/views.py

from django.shortcuts import render, redirect
from .models import File
from .forms import FileUploadForm, FileUploadModelForm
import os
import uuid
from django.http import JsonResponse
from django.template.defaultfilters import filesizeformat

# Create your views here.
# Upload File with ModelForm

def model_form_upload(request):
    if request.method == "POST":
        form = FileUploadModelForm(request.POST, request.FILES)
        if form.is_valid():
            form.save() # 一句話足以
            return redirect("/file/")
    else:
        form = FileUploadModelForm()

    return render(request, 'file_upload/upload_form.html', 
                  {'form': form,'heading': 'Upload files with ModelForm'}
                 )

Django配置文件

  • BASE_DIR

默認值BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

這個是Django項目文件夾所在目錄得絕對路徑,一般不要修改。

  • DEBUG

默認值是True。在本地開發測試環境下設置DEBUG=True可以顯示bug資訊,便於開發者找出程式碼錯誤所在。當你在部署項目在生產環境時,請切記設置DEBUG=False。這是因為生產環境下打開Debug一旦發生錯誤或異常會暴露很多敏感設置資訊。

注意: 當你設置DEBUG=False, 你一定要設置ALLOWED_HOSTS選項, 否則會拋出異常。

  • ALLOWED_HOSTS

默認值為空[]。設置ALLOWED_HOSTS是為了限定用戶請求中的host值,以防止黑客構造包來進行頭部攻擊。該選項正確設置方式如下:

  • DEBUG=True: ALLOWED_HOSTS可以為空,也可設置為[『127.0.0.01』, 『localhost』]

  • 在正式部署項目時,請盡量不要設置ALLOWED_HOSTS=['*']

  • SECRET_KEY

SECRET_KEY是Django根據自己演算法生成的一大串隨機數,本質是個加密鹽,用於防止CSRF(Cross-site request forgery)跨站請求偽造攻擊。

當部署Django項目到生產環境中時,Django文檔建議不直接在settings.py里輸入字元串,而是採取下面幾種方法讀取SECRET_KEY。

方法一: 從環境變數中讀取SECRET_KEY

import os
SECRET_KEY = os.environ['SECRET_KEY']

方法二: 從伺服器上Django項目文件價外的某個文件讀取

with open('/etc/secret_key.txt') as f:
    SECRET_KEY = f.read().strip()
  • INSTALLED_APPS

這個設置比較簡單,也比較常用,用於增刪一個項目(Project)所包含的應用(APP)。

只有對列入此項的APP, Django才會生成相應的數據表。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',  # 自定義的APP
]
  • AUTH_USER_MODEL

默認為auth.user。也可以為自定義用戶模型, 如users.user

  • STATIC_ROOT和STATIC_URL

這兩個選項是關於靜態文件(如CSS, JS,和圖片)的最重要的設置。

一般設置如下。STATIC_URL是靜態文件URL,設置後可以通過使用{% static 'assets/imges/xxx.jpg' %}方式直接訪問/static/文件夾里的靜態文件。

如果你設置了STATIC_ROOT, 當你運行python manage.py collectstatic命令的時候,Django會將各app下所有名為static的文件夾及其子目錄複製收集到STATIC_ROOT。把靜態文件集中一起的目的是為了更方便地通過Apache或Nginx部署。

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

一般情況下我們會盡量把靜態文件只放在static文件夾或它的子目錄下,所以上述兩個設置對於一般項目是夠的。

那麼問題來了,如果你還有一些文件夾中也有靜態文件,可是文件夾並不是以static命名也不在static子目錄里,此時你也希望搜集使用那些靜態文件,你該怎麼辦呢?

這時我們就要設置靜態文件目錄STATICFILES_DIRS值了。

  • STATICFILES_DIRS

默認值為空。當你設置該選項後,python manage.py collectstatic命令會把static文件夾及靜態文件目錄STATICFILES_DIRS里的靜態文件都複製到一份到STATIC_ROOT

比如下例中Django會將下面兩個文件夾內容也複製到STATIC_ROOT。注意裡面的路徑必需是絕對路徑哦。

STATICFILES_DIRS = [
"/home/user/pictures",
"/opt/webfiles/myfiles",
]
  • MEDIA_ROOT和MEDIA_URL

media文件價一般用於放置用戶上傳的文件。

對於此文件夾的許可權設置異常重要,因為用戶可能會上傳可執行的文件,影響網站和伺服器的安全。

對於此文件夾許可權,建議使用sudo chmod 755 media命令設置成755,而不要使用777(可讀、可寫、可執行)。

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • 國際化(語言與時間)
USE_TZ = True # 默認值True。
TIME_ZONE = 'Asia/Shanghai' # 設置時區
USE_I18N = True # 默認為True,是否啟用自動翻譯系統
USE_L10N = True # 默認False,以本地化格式顯示數字和時間
  • 郵箱服務配置
EMAIL_HOST = 'smtp.qq.com' # 發送者郵箱伺服器
EMAIL_PORT = 25 # 埠
EMAIL_HOST_USER = ''        # 發送者用戶名(郵箱地址)
EMAIL_HOST_PASSWORD = ''    # 發送者密碼
EMAIL_USE_SSL = True
DEFAULT_FROM_EMAIL = '[email protected]'
  • 模板設置

如果你在根目錄下建立了一個templates文件夾,專門用於存放屬於項目的模板文件,你還需要在settings.py中顯示地將模板目錄設置為BASE_DIR目錄下的templates文件夾。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]
  • 中間件設置

如果你希望在Django項目中使用自定義的中間件,你需要在 MIDDLEWARE選項里註冊。

注意:中間件的添加順序很重要。

MIDDLEWARE = [
    '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',
    'myapp.middleware.CustomMiddleware1', # 新增自定義中間件。
]
  • 資料庫設置

Django默認使用輕量級的SQLite資料庫,無需進行任何設置開箱即用。

當然小編我並不建議在settings.py直接寫入資料庫密碼,而是採取讀取外部配置文件的方式,更安全。

下面以MYSQL為例介紹了基本配置方式。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   # 資料庫引擎
        'NAME': 'mydb',         # 你要存儲數據的庫名,事先要創建之
        'USER': 'xxs',         # 資料庫用戶名
        'PASSWORD': 'xxxx',     # 密碼
        'HOST': 'localhost',    # 主機
        'PORT': '3306',         # 資料庫使用的埠
    }
}
  • 快取設置

Django中提供了多種快取方式,如果要使用快取,需要先在settings.py中進行配置,然後應用。

根據快取介質的不同,你需要設置不同的快取後台Backend。

比如如果你希望使用redis做快取後台,你需要先安裝redisdjango_redis, 然後再修改settings.py中的快取配置。

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://your_host_ip:6379', # redis所在伺服器或容器ip地址
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
             "PASSWORD": "your_pwd", # 你設置的密碼
        },
    },
}
  • Session相關設置
SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # 引擎(默認)
SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在瀏覽器上時的key,
SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名(默認)
SESSION_COOKIE_SECURE = False  # 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支援http傳輸(默認)
SESSION_COOKIE_AGE = 60 * 30  # Session的cookie失效日期(30min)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = True  # 是否關閉瀏覽器使得Session過期(默認)
SESSION_SAVE_EVERY_REQUEST = True  # 是否每次請求都保存Session,默認修改之後才保存