全文鏈接
第一章 創(chuàng)建一個(gè)blog應(yīng)用
第二章 使用高級(jí)特性來(lái)增強(qiáng)你的blog
第三章 擴(kuò)展你的blog應(yīng)用
第四章上 創(chuàng)建一個(gè)社交網(wǎng)站
第四章下 創(chuàng)建一個(gè)社交網(wǎng)站
第五章 在你的網(wǎng)站中分享內(nèi)容
第六章 跟蹤用戶(hù)動(dòng)作
第七章 建立一個(gè)在線(xiàn)商店
第八章 管理付款和訂單
第九章上 擴(kuò)展你的商店
第九章下 擴(kuò)展你的商店
第十章上 創(chuàng)建一個(gè)在線(xiàn)學(xué)習(xí)平臺(tái)
第十章下 創(chuàng)建一個(gè)在線(xiàn)學(xué)習(xí)平臺(tái)
第十一章 緩存內(nèi)容
第十二章 構(gòu)建一個(gè)API
第十一章
緩存內(nèi)容
(譯者 @ucag 注:這是倒數(shù)第二章,最后一個(gè)項(xiàng)目即將完成。 @夜夜月 將會(huì)接過(guò)翻譯的最后一棒。這本書(shū)的翻譯即將完成。這也是我翻譯的最后一章,作為英語(yǔ)專(zhuān)業(yè)的學(xué)生,我對(duì)于翻譯有了更多的思考。同樣,校對(duì)是 @夜夜月)
(譯者 @夜夜月注:贊,倒數(shù)第二章了,接下來(lái)就是最后一章了?。?/p>
在上一章中,你使用模型繼承和一般關(guān)系創(chuàng)建了一個(gè)靈活的課程內(nèi)容模型。你也使用基于類(lèi)的視圖,表單集,以及 內(nèi)容的 AJAX 排序,創(chuàng)建了一個(gè)課程管理系統(tǒng)。在這一章中,你將會(huì):
- 創(chuàng)建展示課程信息的公共視圖
- 創(chuàng)建一個(gè)學(xué)生注冊(cè)系統(tǒng)
- 在courses中管理學(xué)生注冊(cè)
- 創(chuàng)建多樣化的課程內(nèi)容
- 使用緩存框架緩存內(nèi)容
我們將會(huì)從創(chuàng)建一個(gè)課程目錄開(kāi)始,好讓學(xué)生能夠?yàn)g覽當(dāng)前的課程以及注冊(cè)這些課程。
展示課程
對(duì)于課程目錄,我們需要?jiǎng)?chuàng)建以下的功能:
- 列出所有的可用課程,可以通過(guò)可選科目過(guò)濾
- 展示一個(gè)單獨(dú)的課程概覽
編輯 courses 應(yīng)用的 views.py ,添加以下代碼:
from django.db.models import Count
from .models import Subject
class CourseListView(TemplateResponseMixin, View):
model = Course
template_name = 'courses/course/list.html'
def get(self, request, subject=None):
subjects = Subject.objects.annotate(
total_courses=Count('courses'))
courses = Course.objects.annotate(
total_modules=Count('modules'))
if subject:
subject = get_object_or_404(Subject, slug=subject)
courses = courses.filter(subject=subject)
return self.render_to_response({'subjects':subjects,
'subject': subject,
'courses': courses})
這是 CourseListView 。它繼承了 TemplateResponseMixin 和 View 。在這個(gè)視圖中,我們實(shí)現(xiàn)了下面的功能:
- 1 我們檢索所有的課程,包括它們當(dāng)中的每個(gè)課程總數(shù)。我們使用 ORM 的
annotate()方法和Count()聚合方法來(lái)實(shí)現(xiàn)這一功能。 - 2 我們檢索所有的可用課程,包括在每個(gè)課程中包含的模塊總數(shù)。
- 3 如果給了科目的 slug URL 參數(shù),我們就檢索對(duì)應(yīng)的課程對(duì)象,然后我們將會(huì)把查詢(xún)限制在所給的科目之內(nèi)。
- 4 我們使用
TemplateResponseMixin提供的render_to_response()方法來(lái)把對(duì)象渲染到模板中,然后返回一個(gè) HTTP 響應(yīng)。
讓我們創(chuàng)建一個(gè)詳情視圖來(lái)展示單一課程的概覽。在 views.py 中添加以下代碼:
from django.views.generic.detail import DetailView
class CourseDetailView(DetailView):
model = Course
template_name = 'courses/course/detail.html'
這個(gè)視圖繼承了 Django 提供的通用視圖 DetailView 。我們定義了 model 和 template_name 屬性。Django 的 DetailView 期望一個(gè) 主鍵(pk) 或者 slug URL 參數(shù)來(lái)檢索對(duì)應(yīng)模型的一個(gè)單一對(duì)象。然后它就會(huì)渲染 template_name 中的模板,同樣也會(huì)把上下文中的對(duì)象渲染進(jìn)去。
編輯 educa 項(xiàng)目中的主 urls.py 文件,添加以下 URL 模式:
from courses.views import CourseListView
urlpatterns = [
# ...
url(r'^$', CourseListView.as_view(), name='course_list'),
]
我們把 course_list 的 URL 模式添加進(jìn)了項(xiàng)目的主 urls.py 中,因?yàn)槲覀兿胍颜n程列表展示在 http://127.0.0.1:8000/ 中,然后 courses 應(yīng)用的所有的其他 URL 都有 /course/ 前綴。
編輯 courses 應(yīng)用的 urls.py ,添加以下 URL 模式:
url(r'^subject/(?P<subject>[\w-]+)/$',
views.CourseListView.as_view(),
name='course_list_subject'),
url(r'^(?P<slug>[\w-]+)/$',
views.CourseDetailView.as_view(),
name='course_detail'),
我們定義了以下 URL 模式:
-
course_list_subject:用于展示一個(gè)科目的所有課程 -
course_detail:用于展示一個(gè)課程的概覽
讓我們?yōu)?CourseListView 和 CourseDetailView 創(chuàng)建模板。在 courses 應(yīng)用的 templates/courses/ 路徑下創(chuàng)建以下路徑:
- course/
- list.html
- detail.html
編輯 courses/course/list.html 模板,寫(xiě)入以下代碼:
{% extends "base.html" %}
{% block title %}
{% if subject %}
{{ subject.title }} courses
{% else %}
All courses
{% endif %}
{% endblock %}
{% block content %}
<h1>
{% if subject %}
{{ subject.title }} courses
{% else %}
All courses
{% endif %}
</h1>
<div class="contents">
<h3>Subjects</h3>
<ul id="modules">
<li {% if not subject %}class="selected"{% endif %}>
<a href="{% url "course_list" %}">All</a>
</li>
{% for s in subjects %}
<li {% if subject == s %}class="selected"{% endif %}>
<a href="{% url "course_list_subject" s.slug %}">
{{ s.title }}
<br><span>{{ s.total_courses }} courses</span>
</a>
</li>
{% endfor %}
</ul>
</div>
<div class="module">
{% for course in courses %}
{% with subject=course.subject %}
<h3><a href="{% url "course_detail" course.slug %}">{{ course.title }}</a></h3>
<p>
<a href="{% url "course_list_subject" subject.slug %}">{{ subject }}</a>.
{{ course.total_modules }} modules.
Instructor: {{ course.owner.get_full_name }}
</p>
{% endwith %}
{% endfor %}
</div>
{% endblock %}
這個(gè)模板用于展示可用課程列表。我們創(chuàng)建了一個(gè) HTML 列表來(lái)展示所有的 Subject 對(duì)象,然后為它們每一個(gè)都創(chuàng)建了一個(gè)鏈接,這個(gè)鏈接鏈接到 course_list_subject 的 URL 。 如果存在當(dāng)前科目,我們就把 selected HTML 類(lèi)添加到當(dāng)前科目中高亮顯示該科目。我們迭代每個(gè) Course 對(duì)象,展示模塊的總數(shù)和教師的名字。
使用 python manage.py runserver 打開(kāi)代發(fā)服務(wù)器,訪(fǎng)問(wèn) http://127.0.0.1:8000/ 。你看到的應(yīng)該是像下面這個(gè)樣子:

左邊的側(cè)邊欄包含了所有的科目,包括每個(gè)科目的課程總數(shù)。你可以點(diǎn)擊任意一個(gè)科目來(lái)篩選展示的課程。
編輯 courses/course/detail.html 模板,添加以下代碼:
{% extends "base.html" %}
{% block title %}
{{ object.title }}
{% endblock %}
{% block content %}
{% with subject=course.subject %}
<h1>
{{ object.title }}
</h1>
<div class="module">
<h2>Overview</h2>
<p>
<a href="{% url "course_list_subject" subject.slug %}">{{ subject.title }}</a>.
{{ course.modules.count }} modules.
Instructor: {{ course.owner.get_full_name }}
</p>
{{ object.overview|linebreaks }}
</div>
{% endwith %}
{% endblock %}
在這個(gè)模板中,我們展示了每個(gè)單一課程的概覽和詳情。訪(fǎng)問(wèn) http://127.0.0.1:8000/ ,點(diǎn)擊任意一個(gè)課程。你就應(yīng)該看到有下面結(jié)構(gòu)的頁(yè)面了:

我們已經(jīng)創(chuàng)建了一個(gè)展示課程的公共區(qū)域了。下面,我們需要讓用戶(hù)可以注冊(cè)為學(xué)生以及注冊(cè)他們的課程。
添加學(xué)生注冊(cè)
使用下面的命令創(chuàng)鍵一個(gè)新的應(yīng)用:
python manage.py startapp students
編輯 educa 項(xiàng)目的 settings.py ,把 students 添加進(jìn) INSTALLED_APPS 設(shè)置中:
INSTALLED_APPS = (
# ...
'students',
)
創(chuàng)建一個(gè)學(xué)生注冊(cè)視圖
編輯 students 應(yīng)用的 views.py ,寫(xiě)入下下面的代碼:
from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import CreateView
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import authenticate, login
class StudentRegistrationView(CreateView):
template_name = 'students/student/registration.html'
form_class = UserCreationForm
success_url = reverse_lazy('student_course_list')
def form_valid(self, form):
result = super(StudentRegistrationView,
self).form_valid(form)
cd = form.cleaned_data
user = authenticate(username=cd['username'],
password=cd['password1'])
login(self.request, user)
return result
這個(gè)視圖讓學(xué)生可以注冊(cè)進(jìn)我們的網(wǎng)站里。我們使用了可以提供創(chuàng)建模型對(duì)象功能的通用視圖 CreateView 。這個(gè)視圖要求以下屬性:
-
template_name:渲染這個(gè)視圖的模板路徑。 -
form_class:用于創(chuàng)建對(duì)象的表單,我們使用 Django 的UserCreationForm作為注冊(cè)表單來(lái)創(chuàng)建User對(duì)象。 -
success_url:當(dāng)表單成功提交時(shí)要將用戶(hù)重定向到的 URL 。我們逆序了student_course_listURL,我們稍候?qū)?huì)將建它來(lái)展示學(xué)生已報(bào)名的課程。
當(dāng)合法的表單數(shù)據(jù)被提交時(shí) form_valid() 方法就會(huì)執(zhí)行。它必須返回一個(gè) HTTP 響應(yīng)。我們覆寫(xiě)了這個(gè)方法來(lái)讓用戶(hù)在成功注冊(cè)之后登錄。
在 students 應(yīng)用路徑下創(chuàng)建一個(gè)新的文件,命名為 urls.py ,添加以下代碼:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^register/$',
views.StudentRegistrationView.as_view(),
name='student_registration'),
]
編輯 educa 的主 urls.py ,然后把 students 應(yīng)用的 URLs 引入進(jìn)去:
url(r'^students/', include('students.urls')),
在 students 應(yīng)用內(nèi)創(chuàng)建如下的文件結(jié)構(gòu):
templates/
students/
student/
registration.html
編輯 students/student/registration.html 模板,然后添加以下代碼:
{% extends "base.html" %}
{% block title %}
Sign up
{% endblock %}
{% block content %}
<h1>
Sign up
</h1>
<div class="module">
<p>Enter your details to create an account:</p>
<form action="" method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Create my account"></p>
</form>
</div>
{% endblock %}
最后編輯 educa 的設(shè)置文件,添加以下代碼:
from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('student_course_list')
這個(gè)是由 auth 模型用來(lái)給用戶(hù)在成功的登錄之后重定向的設(shè)置,如果請(qǐng)求中沒(méi)有 next 參數(shù)的話(huà)。
打開(kāi)開(kāi)發(fā)服務(wù)器,訪(fǎng)問(wèn) http://127.0.0.1:8000/students/register/ ,你可以看到像這樣的注冊(cè)表單:

報(bào)名
在用戶(hù)創(chuàng)建一個(gè)賬號(hào)之后,他們應(yīng)該就可以在 courses 中報(bào)名了。為了保存報(bào)名表,我們需要在 Course 和 User 模型之間創(chuàng)建一個(gè)多對(duì)多關(guān)系。編輯 courses 應(yīng)用的 models.py 然后把下面的字段添加進(jìn) Course 模型中:
students = models.ManyToManyField(User,
related_name='courses_joined',
blank=True)
在 shell 中執(zhí)行下面的命令來(lái)創(chuàng)建遷移:
python manage.py makemigrations
你可以看到類(lèi)似下面的輸出:
Migrations for 'courses':
0004_course_students.py:
- Add field students to course
接下來(lái)執(zhí)行下面的命令來(lái)應(yīng)用遷移:
python manage.py migrate
你可以看到以下輸出:
Operations to perform:
Apply all migrations: courses
Running migrations:
Rendering model states... DONE
Applying courses.0004_course_students... OK
我們現(xiàn)在就可以把學(xué)生和他們報(bào)名的課程相關(guān)聯(lián)起來(lái)了。
讓我們創(chuàng)建學(xué)生報(bào)名課程的功能吧。
在 students 應(yīng)用內(nèi)創(chuàng)建一個(gè)新的文件,命名為 forms.py ,添加以下代碼:
from django import forms
from courses.models import Course
class CourseEnrollForm(forms.Form):
course = forms.ModelChoiceField(queryset=Course.objects.all(),
widget=forms.HiddenInput)
我們將會(huì)把這張表用于學(xué)生報(bào)名。course 字段是學(xué)生報(bào)名的課程。所以,它是一個(gè) ModelChoiceField 。我們使用 HiddenInput 控件,因?yàn)槲覀儾淮蛩惆堰@個(gè)字段展示給用戶(hù)。我們將會(huì)在 CourseDetailView 視圖中使用這個(gè)表單來(lái)展示一個(gè)報(bào)名按鈕。
編輯 students 應(yīng)用的 views.py ,添加以下代碼:
from django.views.generic.edit import FormView
from braces.views import LoginRequiredMixin
from .forms import CourseEnrollForm
class StudentEnrollCourseView(LoginRequiredMixin, FormView):
course = None
form_class = CourseEnrollForm
def form_valid(self, form):
self.course = form.cleaned_data['course']
self.course.students.add(self.request.user)
return super(StudentEnrollCourseView,
self).form_valid(form)
def get_success_url(self):
return reverse_lazy('student_course_detail',
args=[self.course.id])
這就是 StudentEnrollCourseView 。它負(fù)責(zé)學(xué)生在 courses 中報(bào)名。新的視圖繼承了 LoginRequiredMixin ,所以只有登錄了的用戶(hù)才可以訪(fǎng)問(wèn)到這個(gè)視圖。我們把 CourseEnrollForm表單用在了 form_class 屬性上,同時(shí)我們也定義了一個(gè) course 屬性來(lái)儲(chǔ)存所給的 Course 對(duì)象。當(dāng)表單合法時(shí),我們把當(dāng)前用戶(hù)添加到課程中已報(bào)名學(xué)生中去。
如果表單提交成功,get_success_url 方法就會(huì)返回用戶(hù)將會(huì)被重定向到的 URL 。這個(gè)方法相當(dāng)于 success_url 屬性。我們反序 student_course_detail URL ,我們稍候?qū)?huì)創(chuàng)建它來(lái)展示課程中的學(xué)生。
編輯 students 應(yīng)用的 urls.py ,添加以下 URL 模式:
url(r'^enroll-course/$',
views.StudentEnrollCourseView.as_view(),
name='student_enroll_course'),
讓我們把報(bào)名按鈕表添加進(jìn)課程概覽頁(yè)。編輯 course 應(yīng)用的 views.py ,然后修改 CourseDetailView 讓它看起來(lái)像這樣:
from students.forms import CourseEnrollForm
class CourseDetailView(DetailView):
model = Course
template_name = 'courses/course/detail.html'
def get_context_data(self, **kwargs):
context = super(CourseDetailView,
self).get_context_data(**kwargs)
context['enroll_form'] = CourseEnrollForm(
initial={'course':self.object})
return context
我們使用 get_context_data() 方法來(lái)在渲染進(jìn)模板中的上下文里引入報(bào)名表。我們初始化帶有當(dāng)前 Course 對(duì)象的表單的隱藏 course 字段,這樣它就可以被直接提交了。
編輯 courses/course/detail.html 模板,然后找到下面的這一行:
{{ object.overview|linebreaks }}
起始行應(yīng)該被替換為下面的這幾行:
{{ object.overview|linebreaks }}
{% if request.user.is_authenticated %}
<form action="{% url "student_enroll_course" %}" method="post">
{{ enroll_form }}
{% csrf_token %}
<input type="submit" class="button" value="Enroll now">
</form>
{% else %}
<a href="{% url "student_registration" %}" class="button">
Register to enroll
</a>
{% endif %}
這個(gè)按鈕就是用于報(bào)名的。如果用戶(hù)是被認(rèn)證過(guò)的,我們就展示包含了隱藏表單字段的報(bào)名按鈕,這個(gè)表單指向了 student_enroll_course URL。如果用戶(hù)沒(méi)有被認(rèn)證,我們將會(huì)展示一個(gè)注冊(cè)鏈接。
確保已經(jīng)打開(kāi)了開(kāi)發(fā)服務(wù)器,訪(fǎng)問(wèn) http://127.0.0.1:8000/ ,然后點(diǎn)擊一個(gè)課程。如果你登錄了,你就可以在底部看到 ENROLL NOW 按鈕,就像這樣:

如果你沒(méi)有登錄,你就會(huì)看到一個(gè)Register to enroll 的按鈕。
獲取課程內(nèi)容
我們需要一個(gè)視圖來(lái)展示學(xué)生已經(jīng)報(bào)名的課程,和一個(gè)獲取當(dāng)前課程內(nèi)容的視圖。編輯 students 應(yīng)用的 views.py ,添加以下代碼:
from django.views.generic.list import ListView
from courses.models import Course
class StudentCourseListView(LoginRequiredMixin, ListView):
model = Course
template_name = 'students/course/list.html'
def get_queryset(self):
qs = super(StudentCourseListView, self).get_queryset()
return qs.filter(students__in=[self.request.user])
這個(gè)是用于列出學(xué)生已經(jīng)報(bào)名課程的視圖。它繼承 LoginRequiredMixin 來(lái)確保只有登錄的用戶(hù)才可以連接到這個(gè)視圖。同時(shí)它也繼承了通用視圖 ListView 來(lái)展示 Course 對(duì)象列表。我們覆寫(xiě)了 get_queryset() 方法來(lái)檢索用戶(hù)已經(jīng)報(bào)名的課程。我們通過(guò)學(xué)生的 ManyToManyField 字段來(lái)篩選查詢(xún)集以達(dá)到這個(gè)目的。
把下面的代碼添加進(jìn) views.py 文件中:
from django.views.generic.detail import DetailView
class StudentCourseDetailView(DetailView):
model = Course
template_name = 'students/course/detail.html'
def get_queryset(self):
qs = super(StudentCourseDetailView, self).get_queryset()
return qs.filter(students__in=[self.request.user])
def get_context_data(self, **kwargs):
context = super(StudentCourseDetailView,
self).get_context_data(**kwargs)
# get course object
course = self.get_object()
if 'module_id' in self.kwargs:
# get current module
context['module'] = course.modules.get(
id=self.kwargs['module_id'])
else:
# get first module
context['module'] = course.modules.all()[0]
return context
這是 StudentCourseDetailView 。我們覆寫(xiě)了 get_queryset 方法把查詢(xún)集限制在用戶(hù)報(bào)名的課程之內(nèi)。我們同樣也覆寫(xiě)了 get_context_data() 方法來(lái)把課程的一個(gè)模塊賦值在上下文內(nèi),如果給了 model_id URL 參數(shù)的話(huà)。否則,我們就賦值課程的第一個(gè)模塊。這樣,學(xué)生就可以在課程之內(nèi)瀏覽各個(gè)模塊了。
編輯 students 應(yīng)用的 urls.py ,添加以下 URL 模式:
url(r'^courses/$',
views.StudentCourseListView.as_view(),
name='student_course_list'),
url(r'^course/(?P<pk>\d+)/$',
views.StudentCourseDetailView.as_view(),
name='student_course_detail'),
url(r'^course/(?P<pk>\d+)/(?P<module_id>\d+)/$',
views.StudentCourseDetailView.as_view(),
name='student_course_detail_module'),
在 students 應(yīng)用的 templates/students/ 路徑下創(chuàng)建以下文件結(jié)構(gòu):
course/
detail.html
list.html
編輯 students/course/list.html 模板,然后添加下列代碼:
{% extends "base.html" %}
{% block title %}My courses{% endblock %}
{% block content %}
<h1>My courses</h1>
<div class="module">
{% for course in object_list %}
<div class="course-info">
<h3>{{ course.title }}</h3>
<p><a href="{% url "student_course_detail" course.id %}">Access contents</a></p>
</div>
{% empty %}
<p>
You are not enrolled in any courses yet.
<a href="{% url "course_list" %}">Browse courses</a>to enroll in a course.
</p>
{% endfor %}
</div>
{% endblock %}
這個(gè)模板展示了用戶(hù)報(bào)名的課程。編輯 students/course/detail.html 模板,添加以下代碼:
{% extends "base.html" %}
{% block title %}
{{ object.title }}
{% endblock %}
{% block content %}
<h1>
{{ module.title }}
</h1>
<div class="contents">
<h3>Modules</h3>
<ul id="modules">
{% for m in object.modules.all %}
<li data-id="{{ m.id }}" {% if m == module %}
class="selected"{% endif %}>
<a href="{% url "student_course_detail_module" object.id m.id %}">
<span>
Module <span class="order">{{ m.order|add:1 }}</span>
</span>
<br>
{{ m.title }}
</a>
</li>
{% empty %}
<li>No modules yet.</li>
{% endfor %}
</ul>
</div>
<div class="module">
{% for content in module.contents.all %}
{% with item=content.item %}
<h2>{{ item.title }}</h2>
{{ item.render }}
{% endwith %}
{% endfor %}
</div>
{% endblock %}
這個(gè)模板用于報(bào)名了的學(xué)生連接到課程內(nèi)容。首先我們創(chuàng)建了一個(gè)包含所有課程模塊的 HTML 列表且高亮當(dāng)前模塊。然后我們迭代當(dāng)前的模塊內(nèi)容,之后使用 {{ item.render }} 來(lái)連接展示內(nèi)容。接下來(lái)我們將會(huì)在內(nèi)容模型中添加 render() 方法。這個(gè)方法將會(huì)負(fù)責(zé)精準(zhǔn)的展示內(nèi)容。
渲染不同類(lèi)型的內(nèi)容
我們需要提供一個(gè)方法來(lái)渲染不同類(lèi)型的內(nèi)容。編輯 course 應(yīng)用的 models.py ,把 render() 方法添加進(jìn) ItemBase 模型中:
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
class ItemBase(models.Model):
# ...
def render(self):
return render_to_string('courses/content/{}.html'.format(
self._meta.model_name), {'item': self})
這個(gè)方法使用了 render_to_string() 方法來(lái)渲染模板以及返回一個(gè)作為字符串的渲染內(nèi)容。每種內(nèi)容都使用以?xún)?nèi)容模型命名的模板渲染。我們使用 self._meta.model_name 來(lái)為 la 創(chuàng)建合適的模板名。 render() 方法提供了一個(gè)渲染不同頁(yè)面的通用接口。
在 courses 應(yīng)用的 templates/courses/ 路徑下創(chuàng)建如下文件結(jié)構(gòu):
content/
text.html
file.html
image.html
video.html
編輯 courses/content/text.html 模板,寫(xiě)入以下代碼:
{{ item.content|linebreaks|safe }}
編輯 courses/content/file.html 模板,寫(xiě)入以下代碼:
<p><a href="{{ item.file.url }}" class="button">Download file</a></p>
編輯 courses/content/image.html 模板,寫(xiě)入以下代碼:
<p></p>
為了使上傳帶有 ImageField 和 FielField 的文件工作,我們需要配置我們的項(xiàng)目以使用開(kāi)發(fā)服務(wù)器提供媒體文件服務(wù)。編輯你的項(xiàng)目中的 settings.py ,添加以下代碼:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
記住 MEDIA_URL 是服務(wù)上傳文件的基本 URL 路徑, MEDIA_ROOT 是放置文件的本地路徑。
編輯你的項(xiàng)目的主 urls.py ,添加以下 imports:
from django.conf import settings
from django.conf.urls.static import static
然后,把下面這幾行寫(xiě)入文件的結(jié)尾:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
你的項(xiàng)目現(xiàn)在已經(jīng)準(zhǔn)備好使用開(kāi)發(fā)服務(wù)器上傳和服務(wù)文件了。記住開(kāi)發(fā)服務(wù)器不能用于生產(chǎn)環(huán)境中。我們將會(huì)在下一章中學(xué)習(xí)如何配置生產(chǎn)環(huán)境。
我們也需要?jiǎng)?chuàng)建一個(gè)模板來(lái)渲染 Video 對(duì)象。我們將會(huì)使用 django-embed-video 來(lái)嵌入視頻內(nèi)容。 Django-embed-video 是一個(gè)第三方 Django 應(yīng)用,它使你可以通過(guò)提供一個(gè)視頻的公共 URL 來(lái)在模板中嵌入視頻,類(lèi)似來(lái)自 YouTube 或者 Vimeo 的資源。
使用下面的命令來(lái)安裝這個(gè)包:
pip isntall django-embed-video==1.0.0
然后編輯項(xiàng)目的 settings.py 然后添加 embed_video 到 INSTALLED_APPS設(shè)置 中。你可以在這里找到 django-embed-video 的文檔:
http://django-embed-video.readthedocs.org/en/v1.0.0/ 。
編輯 courses/content/video.html 模板,寫(xiě)入以下代碼:
{% load embed_video_tags %}
{% video item.url 'small' %}
現(xiàn)在運(yùn)行開(kāi)發(fā)服務(wù)器,訪(fǎng)問(wèn) http://127.0.0.1:8000/course/mine/ 。用屬于教師組或者超級(jí)管理員的用戶(hù)訪(fǎng)問(wèn)站點(diǎn),然后添加一些內(nèi)容到一個(gè)課程中。為了引入視頻內(nèi)容,你也可以復(fù)制任何一個(gè) YouTube 視頻 URL ,比如 :https://www.youtube.com/watch?n=bgV39DlmZ2U ,然后把它引入到表單的 url 字段中。在添加內(nèi)容到課程中之后,訪(fǎng)問(wèn) http://127.0.0.1:8000/ ,點(diǎn)擊課程然后點(diǎn)擊ENROLL NOW按鈕。你就可以在課程中報(bào)名了,然后被重定向到 student_course_detail URL 。下面這張圖片展示了一個(gè)課程內(nèi)容樣本:

真棒!你已經(jīng)創(chuàng)建了一個(gè)渲染課程的通用接口了,它們中的每一個(gè)都會(huì)被用特定的方式渲染。
使用緩存框架
你的應(yīng)用的 HTTP 請(qǐng)求通常是數(shù)據(jù)庫(kù)鏈接,數(shù)據(jù)處理,和模板渲染的。就處理數(shù)據(jù)而言,它的開(kāi)銷(xiāo)可比服務(wù)一個(gè)靜態(tài)網(wǎng)站大多了。
請(qǐng)求開(kāi)銷(xiāo)在你的網(wǎng)站有越來(lái)越多的流量時(shí)是有意義的。這也使得緩存變得很有必要。通過(guò)緩存 HTTP 請(qǐng)求中 的查詢(xún)結(jié)果,計(jì)算結(jié)果,或者是渲染上下文,你將會(huì)避免在接下來(lái)的請(qǐng)求中巨大的開(kāi)銷(xiāo)。這使得服務(wù)端的響應(yīng)時(shí)間和處理時(shí)間變短。
Django 配備有一個(gè)健碩的緩存系統(tǒng),這使得你可以使用不同級(jí)別的顆粒度來(lái)緩存數(shù)據(jù)。你可以緩存單一的查詢(xún),一個(gè)特定的輸出視圖,部分渲染的模板上下文,或者整個(gè)網(wǎng)站。緩存系統(tǒng)中的內(nèi)容會(huì)在默認(rèn)時(shí)間內(nèi)被儲(chǔ)存。你可以指定緩存數(shù)據(jù)過(guò)期的時(shí)間。
這是當(dāng)你的站點(diǎn)收到一個(gè) HTTP 請(qǐng)求時(shí)將會(huì)通常使用的緩存框架的方法:
1. 試著在緩存中尋找緩存數(shù)據(jù)
2. 如果找到了,就返回緩存數(shù)據(jù)
3. 如果沒(méi)有找到,就執(zhí)行下面的步驟:
1. 執(zhí)行查詢(xún)或者處理請(qǐng)求來(lái)獲得數(shù)據(jù)
2. 在緩存中保存生成的數(shù)據(jù)
3. 返回?cái)?shù)據(jù)
你可以在這里找到更多關(guān)于 Django 緩存系統(tǒng)的細(xì)節(jié)信息:https://docs.djangoproject.com/en/1.8/topics/cache/ 。
激活緩存后端
Django 配備有幾個(gè)緩存后端,他們是:
-
backends.memcached.MemcachedCache或backends.memcached.PyLibMCCache:一個(gè)內(nèi)存緩存后端。內(nèi)存緩存是一個(gè)快速、高效的基于內(nèi)存的緩存服務(wù)器。后端的使用取決于你選擇的 Python 綁定(bindings)。 -
backends.db.DatabaseCache: 使用數(shù)據(jù)庫(kù)作為緩存系統(tǒng)。 -
backends.filebased.FileBasedCache:使用文件儲(chǔ)存系統(tǒng)。把每個(gè)緩存值序列化和儲(chǔ)存為單一的文件。 -
backends.locmem.LocMemCache:本地內(nèi)存緩存后端。這是默認(rèn)的緩存后端 -
backends.dummy.DummyCache:一個(gè)用于開(kāi)發(fā)的虛擬緩存后端。它實(shí)現(xiàn)了緩存交互界面而不用真正的緩存任何東西。緩存是獨(dú)立進(jìn)程且是線(xiàn)程安全的
對(duì)于可選的實(shí)現(xiàn),使用內(nèi)存的緩存后端吧,比如
Memcached后端。
安裝 Memcached
我們將會(huì)使用 Memcached 緩存后端。內(nèi)存緩存運(yùn)行在內(nèi)存中,它在 RAM 中分配了指定的數(shù)量。當(dāng)分配的 RAM 滿(mǎn)了時(shí),Memcahed 就會(huì)移除最老的數(shù)據(jù)來(lái)保存新的數(shù)據(jù)。
在這個(gè)網(wǎng)址下載 Memcached: http://memcached.org/downloads 。如果你使用 Linux, 你可以使用下面的命令安裝:
./configure && make && make test && sudo make install
如果你在使用 Mac OS X, 你可以使用命令 brew install Memcached 通過(guò) Homebrew 包管理器來(lái)安裝 Memcached 。你可以在這里下載 Homebrew http://brew.sh
如果你正在使用 Windwos ,你可以在這里找到一個(gè) Windows 的 Memcached 二進(jìn)制版本:http://code.jellycan.com/memcached/ 。
在安裝 Memcached 之后,打開(kāi) shell ,使用下面的命令運(yùn)行它:
memcached -l 127.0.0.1:11211
Memcached 將會(huì)默認(rèn)地在 11211 運(yùn)行。當(dāng)然,你也可以通過(guò) -l 選項(xiàng)指定一個(gè)特定的主機(jī)和端口。你可以在這里找到更多關(guān)于 Memcached 的信息:http://memcached.org 。
在安裝 Memcached 之后,你需要安裝它的 Python 綁定(bindings)。使用下面的命令安裝:】
python install python3-memcached==1.51
緩存設(shè)置
Django 提供了如下的緩存設(shè)置:
-
CACHES:一個(gè)包含所有可用的項(xiàng)目緩存。 -
CACHE_MIDDLEWARE_ALIAS:用于儲(chǔ)存的緩存別名。 -
CACHE_MIDDLEWARE_KEY_PREFIX:緩存鍵的前綴。設(shè)置一個(gè)緩存前綴來(lái)避免鍵的沖突,如果你在幾個(gè)站點(diǎn)中分享相同的緩存的話(huà)。 -
CACHE_MIDDLEWARE_SECONDS:默認(rèn)的緩存頁(yè)面秒數(shù)
項(xiàng)目的緩存系統(tǒng)可以使用 CACHES 設(shè)置來(lái)配置。這個(gè)設(shè)置是一個(gè)字典,讓你可以指定多個(gè)緩存的配置。每個(gè) CACHES 字典中的緩存可以指定下列數(shù)據(jù):
-
BACKEND:使用的緩存后端。 -
KEY_FUNCTION:包含一個(gè)指向回調(diào)函數(shù)的點(diǎn)路徑的字符,這個(gè)函數(shù)以prefix(前綴)、verision(版本)、和 key (鍵) 作為參數(shù)并返回最終緩存鍵(cache key)。 -
KEY_PREFIX:一個(gè)用于所有緩存鍵的字符串,避免沖突。 -
LOCATION:緩存的位置?;谀愕木彺婧蠖耍@可能是一個(gè)路徑、一個(gè)主機(jī)和端口,或者是內(nèi)存中后端的名字。 -
OPTIONS:任何額外的傳遞向緩存后端的參數(shù)。 -
TIMEOUT:默認(rèn)的超時(shí)時(shí)間,以秒為單位,用于儲(chǔ)存緩存鍵。默認(rèn)設(shè)置是 300 秒,也就是五分鐘。如果把它設(shè)置為None,緩存鍵將不會(huì)過(guò)期。 -
VERSION:默認(rèn)的緩存鍵的版本。對(duì)于緩存版本是很有用的。
把 memcached 添加進(jìn)你的項(xiàng)目
讓我們?yōu)槲覀兊捻?xiàng)目配置緩存。編輯 educa 項(xiàng)目的 settings.py 文件,添加以下代碼:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.
MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
我們正在使用 MemcachedCache 后端。我們使用 address:port 標(biāo)記指定了它的位置。如果你有多個(gè) memcached 實(shí)例,你可以在 LOCATION 中使用列表。
監(jiān)控緩存
這里有一個(gè)第三方包叫做 django-memcached-status ,它可以在管理站點(diǎn)展示你的項(xiàng)目的 memcached 實(shí)例的統(tǒng)計(jì)數(shù)據(jù)。為了兼容 Python3(譯者夜夜月注:python3大法好。) ,從下面的分支中安裝它:
pip install git+git://github.com/zenx/django-memcached-status.git
編輯 settings.py ,然后把 memcached_status 添加進(jìn) INSTALLED_APPS 設(shè)置中。確保 memcached 正在運(yùn)行,在另外一個(gè) shell 中打開(kāi)開(kāi)發(fā)服務(wù)器,然后訪(fǎng)問(wèn) http://127.0.0.1:8000/adim/ ,使用超級(jí)用戶(hù)登錄進(jìn)管理站點(diǎn),你就可以看到如下的區(qū)域:

這張圖片展示了緩存使用。綠色代表了空閑的緩存,紅色的表示使用了的空間。如果你點(diǎn)擊方框的標(biāo)題,它展示了你的 memcached 實(shí)例的統(tǒng)計(jì)詳情。
我們已經(jīng)為項(xiàng)目安裝好了 memcached 并且可以監(jiān)控它。讓我們開(kāi)始緩存數(shù)據(jù)吧!
緩存級(jí)別
Django 提供了以下幾個(gè)級(jí)別按照顆粒度上升的緩存排列:
-
Low-level cache API:提供了最高顆粒度。允許你緩存具體的查詢(xún)或計(jì)算結(jié)果。 -
Per-view cache:提供單一視圖的緩存。 -
Template cache:允許你緩存模板片段。 -
Per-site cache:最高級(jí)的緩存。它緩存你的整個(gè)網(wǎng)站。
在你執(zhí)行緩存之請(qǐng)仔細(xì)考慮下緩存策略。首先要考慮那些不是單一用戶(hù)為基礎(chǔ)的查詢(xún)和計(jì)算開(kāi)銷(xiāo)
使用 low-level cache API (低級(jí)緩存API)
低級(jí)緩存 API 讓你可以緩存任意顆粒度的對(duì)象。它位于 django.core.cache 。你可以像這樣導(dǎo)入它:
from django.core.cache import cache
這使用的是默認(rèn)的緩存。它相當(dāng)于 caches['default'] 。通過(guò)它的別名來(lái)連接一個(gè)特定的緩存也是可能的:
from django.core.cache import caches
my_cache = caches['alias']
讓我們看看緩存 API 是如何工作的。使用命令 python manage.py shell 打開(kāi) shell 然后執(zhí)行下面的代碼:
>>> from django.core.cache import cache
>>> cache.set('musician', 'Django Reinhardt', 20)
我們連接的是默認(rèn)的緩存后端,使用 set{key,value, timeout} 來(lái)保存一個(gè)名為 musician 的鍵和它的為字符串 Django Reinhardt 的值 20 秒鐘。如果我們不指定過(guò)期時(shí)間,Django 會(huì)使在 CACHES 設(shè)置中緩存后端的默認(rèn)過(guò)期時(shí)間。現(xiàn)在執(zhí)行下面的代碼:
>>> cache.get('musician')
'Django Reinhardt'
我們?cè)诰彺嬷袡z索鍵。等待 20 秒然后指定相同的代碼:
>>> cache.get('musician')
None
musician 緩存鍵已經(jīng)過(guò)期了,get() 方法返回了 None 因?yàn)殒I已經(jīng)不在緩存中了。
在緩存鍵中要避免儲(chǔ)存 None 值,因?yàn)檫@樣你就無(wú)法區(qū)分緩存值和緩存過(guò)期了
讓我們緩存一個(gè)查詢(xún)集:
>>> from courses.models import Subject
>>> subjects = Subject.objects.all()
>>> cache.set('all_subjects', subjects)
我們執(zhí)行了一個(gè)在 Subject 模型上的查詢(xún)集,然后把返回的對(duì)象儲(chǔ)存在 all_subjects 鍵中。讓我們檢索一下緩存數(shù)據(jù):
>>> cache.get('all_subjects')
[<Subject: Mathematics>, <Subject: Music>, <Subject: Physics>,
<Subject: Programming>]
我們將會(huì)在視圖中緩存一些查詢(xún)集。編輯 courses 應(yīng)用的 views.py ,添加以下 導(dǎo)入:
from django.core.cache import cache
在 CourseListView 的 get() 方法,把下面這幾行:
subjects = Subject.objects.annotate(
total_courses=Count('courses'))
替換為:
subjects = cache.get('all_subjects')
if not subjects:
subjects = Subject.objects.annotate(
total_courses=Count('courses'))
cache.set('all_subjects', subjects)
在這段代碼中,我們首先嘗試使用 cache.get() 來(lái)從緩存中得到 all_students 鍵。如果所給的鍵沒(méi)有找到,返回的是 None 。如果鍵沒(méi)有被找到(沒(méi)有被緩存,或者緩存了但是過(guò)期了),我們就執(zhí)行查詢(xún)來(lái)檢索所有的 Subject 對(duì)象和它們課程的數(shù)量,我們使用 cache.set() 來(lái)緩存結(jié)果。
打開(kāi)代發(fā)服務(wù)器,訪(fǎng)問(wèn) http://127.0.0.1:8000 。當(dāng)視圖被執(zhí)行的時(shí)候,緩存鍵沒(méi)有被找到的話(huà)查詢(xún)集就會(huì)被執(zhí)行。訪(fǎng)問(wèn) http://127.0.0.1:8000/adim/ 然后打開(kāi) memcached 統(tǒng)計(jì)。你可以看到類(lèi)似于下面的緩存的使用數(shù)據(jù):

看一眼 Curr Items 應(yīng)該是 1 。這表示當(dāng)前有一個(gè)內(nèi)容被緩存。Get Hits 表示有多少的 get 操作成功了,Get Miss表示有多少的請(qǐng)求丟失了。Miss Ratio 是使用它們倆來(lái)計(jì)算的。
現(xiàn)在導(dǎo)航回 http://127.0.0.1:8000/ ,重載頁(yè)面幾次。如果你現(xiàn)在看緩存統(tǒng)計(jì)的話(huà),你就會(huì)看到更多的(Get Hits和Cmd Get被執(zhí)行了)
基于動(dòng)態(tài)數(shù)據(jù)的緩存
有很多時(shí)候你都會(huì)想使用基于動(dòng)態(tài)數(shù)據(jù)的緩存的。基于這樣的情況,你必須要?jiǎng)?chuàng)建包含所有要求信息的動(dòng)態(tài)鍵來(lái)特別定以緩存數(shù)據(jù)。編輯 courses 應(yīng)用的 views.py ,修改 CourseListView ,讓它看起來(lái)像這樣:
class CourseListView(TemplateResponseMixin, View):
model = Course
template_name = 'courses/course/list.html'
def get(self, request, subject=None):
subjects = cache.get('all_subjects')
if not subjects:
subjects = Subject.objects.annotate(
total_courses=Count('courses'))
cache.set('all_subjects', subjects)
all_courses = Course.objects.annotate(
total_modules=Count('modules'))
if subject:
subject = get_object_or_404(Subject, slug=subject)
key = 'subject_{}_courses'.format(subject.id)
courses = cache.get(key)
if not courses:
courses = all_courses.filter(subject=subject)
cache.set(key, courses)
else:
courses = cache.get('all_courses')
if not courses:
courses = all_courses
cache.set('all_courses', courses)
return self.render_to_response({'subjects': subjects,
'subject': subject,
'courses': courses})
在這個(gè)場(chǎng)景中,我們把課程和根據(jù)科目篩選的課程都緩存了。我們使用 all_courses 緩存鍵來(lái)儲(chǔ)存所有的課程,如果沒(méi)有給科目的話(huà)。如果給了一個(gè)科目的話(huà)我們就用 'subject_()_course'.format(subject.id)動(dòng)態(tài)的創(chuàng)建緩存鍵。
注意到我們不能用一個(gè)緩存查詢(xún)集來(lái)創(chuàng)建另外的查詢(xún)集是很重要的,因?yàn)槲覀円呀?jīng)緩存了當(dāng)前的查詢(xún)結(jié)果,所以我們不能這樣做:
courses = cache.get('all_courses')
courses.filter(subject=subject)
相反,我們需要?jiǎng)?chuàng)建基本的查詢(xún)集 Course.objects.annotate(total_modules=Count('modules')) ,它不會(huì)被執(zhí)行除非你強(qiáng)制執(zhí)行它,然后用它來(lái)更進(jìn)一步的用 all_courses.filter(subject=subject) 限制查詢(xún)集萬(wàn)一數(shù)據(jù)沒(méi)有在緩存中找到的話(huà)。
緩存模板片段
緩存模板片段是一個(gè)高級(jí)別的方法。你需要使用 {% load cache %} 在模板中載入緩存模板標(biāo)簽。然后你就可以使用 {% cache %} 模板標(biāo)簽來(lái)緩存特定的模板片段了。你通常可以像下面這樣使用緩存標(biāo)簽:
{% cache 300 fragment_name %}
...
{% endcache %}
{% cache %} 標(biāo)簽要求兩個(gè)參數(shù):過(guò)期時(shí)間,以秒為單位,和一個(gè)片段名稱(chēng)。如果你需要緩存基于動(dòng)態(tài)數(shù)據(jù)的內(nèi)容,你可以通過(guò)傳遞額外的參數(shù)給 {% cache %} 模板標(biāo)簽來(lái)特別的指定片段。
編輯 students 應(yīng)用的 /students/course/detail.html 。在頂部添加以下代碼,就在 {% extends %} 標(biāo)簽的后面:
{% load cache %}
然后把下面幾行:
{% for content in module.contents.all %}
{% with item=content.item %}
<h2>{{ item.title }}</h2>
{{ item.render }}
{% endwith %}
{% endfor %}
替換為:
{% cache 600 module_contents module %}
{% for content in module.contents.all %}
{% with item=content.item %}
<h2>{{ item.title }}</h2>
{{ item.render }}
{% endwith %}
{% endfor %}
{% endcache %}
我們使用名字 module_contents 和傳遞當(dāng)前的 Module 對(duì)象來(lái)緩存模板片段。這對(duì)于當(dāng)請(qǐng)求不同的模型是避免緩存一個(gè)模型的內(nèi)容和服務(wù)錯(cuò)誤的內(nèi)容來(lái)說(shuō)是很重要的。
如果
USE_I18N設(shè)置是為 True,單一站點(diǎn)的中間件緩存將會(huì)遵照當(dāng)前激活的語(yǔ)言。如果你使用了{% cache %}模板標(biāo)簽以及可用翻譯特定的變量中的一個(gè),那么他們的效果將會(huì)是一樣的,比如:{% cache 600 name request.LANGUAGE_CODE %}
緩存視圖
你可以使用位于 django.views.decrators.cache 的 cache_page 裝飾器來(lái)煥春輸出的單個(gè)視圖。裝飾器要求一個(gè)過(guò)期時(shí)間的參數(shù)(以秒為單位)。
讓我們?cè)谖覀兊囊晥D中使用它。編輯 students 應(yīng)用的 urls.py ,添加以下 導(dǎo)入:
from django.views.decorators.cache import cache_page
然后按照如下在 student_course_detail_module URL 模式上應(yīng)用 cache_page 裝飾器:
url(r'^course/(?P<pk>\d+)/$',
cache_page(60 * 15)(views.StudentCourseDetailView.as_view()),
name='student_course_detail'),
url(r'^course/(?P<pk>\d+)/(?P<module_id>\d+)/$',
cache_page(60 * 15)(views.StudentCourseDetailView.as_view()),
name='student_course_detail_module'),
現(xiàn)在 StudentCourseDetailView 的結(jié)果就會(huì)被緩存 15 分鐘了。
單一的視圖緩存使用 URL 來(lái)創(chuàng)建緩存鍵。多個(gè)指向同一個(gè)視圖的 URLs 將會(huì)被分開(kāi)儲(chǔ)存
使用單一站點(diǎn)緩存
這是最高級(jí)的緩存。他讓你可以緩存你的整個(gè)站點(diǎn)。
為了使用單一站點(diǎn)緩存,你需要編輯項(xiàng)目中的 settings.py ,把 UpdateCacheMiddleware 和 FetchFromCacheMiddleware 添加進(jìn) MIDDLEWARE_CLASSES 設(shè)置中:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# ...
)
記住在請(qǐng)求的過(guò)程中,中間件是按照所給的順序來(lái)執(zhí)行的,在相應(yīng)過(guò)程中是逆序執(zhí)行的。UpdateCacheMiddleware 被放在 CommonMiddleware 之前,因?yàn)樗谙鄳?yīng)時(shí)才執(zhí)行,此時(shí)中間件是逆序執(zhí)行的。FetchFromCacheMiddleware 被放在 CommonMiddleware 之后,是因?yàn)樗枰B接后者的的請(qǐng)求數(shù)據(jù)集。
然后,把下列設(shè)置添加進(jìn) settings.py 文件:
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 60 * 15 # 15 minutes
CACHE_MIDDLEWARE_KEY_PREFIX = 'educa'
在這些設(shè)置中我們?yōu)橹虚g件使用了默認(rèn)的緩存,然后我們把全局緩存過(guò)期時(shí)間設(shè)置為 15 分鐘。我們也指定了所有的緩存鍵前綴來(lái)避免沖突萬(wàn)一我們?yōu)槎鄠€(gè)項(xiàng)目使用了相同的 memcached 后端。我們的站點(diǎn)現(xiàn)在將會(huì)為所有的 GET 請(qǐng)求緩存以及返回緩存內(nèi)容。
我們已經(jīng)完成了這個(gè)來(lái)測(cè)試單一站點(diǎn)緩存功能。盡管,以站點(diǎn)的緩存對(duì)于我們來(lái)說(shuō)是不怎么合適的,因?yàn)槲覀兊恼n程管理視圖需要展示更新數(shù)據(jù)來(lái)實(shí)時(shí)的給出任何的修改。我們項(xiàng)目中的最好的方法是緩存用于展示給學(xué)生的課程內(nèi)容的模板或者視圖數(shù)據(jù)。
我們已經(jīng)大致體驗(yàn)過(guò)了 Django 提供的方法來(lái)緩存數(shù)據(jù)。你應(yīng)合適的定義你自己的緩存策略,優(yōu)先考慮開(kāi)銷(xiāo)最大的查詢(xún)集或者計(jì)算。
總結(jié)
在這一章中,我們創(chuàng)建了一個(gè)用于課程的公共視圖,創(chuàng)建了一個(gè)用于學(xué)生注冊(cè)和報(bào)名課程的系統(tǒng)。我們安裝了 memcached 以及實(shí)現(xiàn)了不同級(jí)別的緩存。
在下一章中,我們將會(huì)為你的項(xiàng)目創(chuàng)建 RESTful API。
(譯者 @夜夜月注:終于只剩下最后一章了?。?/p>