一、添加新主題
首先讓用戶添加新主題,創建基於表單的方法幾乎與前面創建網頁一樣,定義一個URL,編寫一個視圖函數並編寫一個模板。
一個人主要差別是需要導入含表單的模塊forms.py。
1.用於添加主題的表單
在Django中,創建表單最簡單的方法是使用ModelForm。該表單只含字段text,並不要讓字段生成標籤。
forms.py
from django import forms
from .models import Topic
class TopicForm(forms.ModelForm):
class Meta:
model=Topic
fields=['text']
labels={'text':''}
2.URL模式new_topic
urls.py
urlpatterns=[
--snip
#用於添加新主題的網頁
url(r'^new_topic/$',views.new_topic,name='new_topic'),]
這個URL模式將請求交給視圖函數new_topic()
3.視圖函數new_topic()
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Topic
from .forms import TopicForm
--snip--
def new_topic(request):
"""添加新主題"""
if request.method!='POST':
#未提交數據:創建一個新表單
form=TopicForm()
else:
#POST提交的數據,對數據進行處理
form=TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
我們導入了HttpResponseRedirect類,用戶提交主題後我們將使用這個類將用戶重定向到網頁topics。函數reverse()根據指定的URL模型確定URL,這意味着Django將在頁面被請求是生成URL。
4.GET請求和POST請求
創建Wed應用程序時,主要有兩種請求:GET請求和POST請求。對於只從服務器讀取數據的頁面,使用GET請求;在用戶需要通過表單提交信息時,通常使用POST請求。
new_topic()將請求對象作爲參數,用戶初次請求該網頁時,其瀏覽器發送GET請求,用戶填寫並提交表單時,其瀏覽器發送POST請求。如果是POST請求,我們先通過檢查確定它們是否有效的。如果有效,save()方法保存到數據庫保存頁面,就可以離開這個頁面了,在頁面topics中,用戶將在主題列表中看到剛輸入的主題。
5.模板new_topic
new_topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a new topic:</p>
<form action="{% url 'learning_logs:new_topic' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">add topic</button>
</form>
{% endblock content %}
模板首先繼承base.html ,我們定義了一個HTML表單,其中實參action告訴服務器將提交的表單數據發送到哪裏,這裏將發送到視圖函數new_topic()。實參method讓瀏覽器以POST請求的方式提交數據,Django使用模板標籤{% csrf_token %}來防止攻擊者利用表單來獲得對服務器未經授權的訪問。{{form.as_p}}可以讓Django自動創建顯示錶單所需的全部字段,修飾符as_p讓Django以段落的格式渲染所有表單元素。
6.鏈接到頁面new_topic
topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
--snip--
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{% endblock content %}
由於添加新主題的頁面
二、添加新條目
1.用於添加新條目的表單
我們創建一個與模型Entry相關聯的表單。
forms.py
from django import forms
from .models import Topic,Entry
class EntryForm(forms.ModelForm):
class Meta:
model=Entry
fields=['text']
labels={'text':''}
widgets={'text':forms.Textarea(attrs={'cols':80})}
新類EntryForm繼承了forms.ModelForm。我們定義了屬性widgets,小部件(widget)是一個HTML表單元素,如單行文本框、多行文本區域或下拉列表。通過設置屬性widgets,可覆蓋Django選擇的默認小部件。通過讓Django使用froms.Textarea,我們定製了字段‘text’的輸入小部件,將文本區域的寬度設置爲80列,而不是默認的40列。
2.URL模式new_entry
在用於添加新條目的頁面的URL模式中,需要包含實參topic_id,因爲條目必須與特定的主題相關聯。
urls.py
--snip--
urlpatterns=[
--snip--
#用於添加新條目的頁面
url(r'^new_entry/(?P<topic_id>\d+)/$',views.new_entry,name='new_entry'),]
這個URL模式與形式爲http://localhost:8000/new_entry/id/的URL匹配,其中id是一個與主題ID匹配的數字。代碼(?P<topic_id>\d+)捕獲一個數字值,並將其儲存在變量topic_id中。請求的URL與這個模式匹配時,Django將請求和主題ID發送給函數new_entry()
3.視圖函數new_entry()
views.py
from django.shortcuts import render
--snip--
from .models import Topic
from .forms import TopicForm,EntryForm
--snip--
def new_entry(request,topic_id):
"""在特定的主題中添加新條目"""
topic=Topic.objects.get(id=topic_id)
if request.method != 'POST':
#未提交數據,創建一個空表單
form=EntryForm()
else:
#POST提交的數據,對數據進行處理
form=EntryForm(data=request.POST)
if form.is_valid():
new_entry=form.save(commit=False)
new_entry.topic=topic
new_entry.save()
return HttpResponseRedirect(reverse('learning_logs:topic',
args=[topic_id]))
context={'topic':topic,'form':form}
return render(request,'learning_logs/new_entry.html',context)
在調用save()時,我們傳遞了實參commit=False,讓Django創建一個新的條目對象,並將其儲存在new_entry中,但不將它保存在數據庫中。
4.模板new_entry
new_entry.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>Add a new entry:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">add entry</button>
</form>
{% endblock content %}
5.鏈接到頁面new_entry
topic.html
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<p>
<a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
</p>
<ul>
--snip
</ul>
{% endblock content %}
頁面new_entry
三、編輯條目
1.URL模式edit_entry
urls.py
--snip--
urlpatterns=[
--snip--
#用於編輯條目的頁面
url(r'^edit_entry/(?P<entry_id>\d+)/$',views.edit_entry,
name='edit_entry'),]
2.視圖函數edit_entry()
views.py
def edit_entry(request, entry_id):
"""編輯既有條目"""
entry = Entry.objects.get(id = entry_id) #獲得用戶要修改的條目對象和與該條目相關的主題
topic = entry.topic
if request.method != 'POST':
""" 初次請求,使用當前條目填充表單"""
form = EntryForm(instance = entry)
else:
""" POST提交的數據,對數據進行處理 """
form = EntryForm(instance = entry, data = request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topic', args=[topic.id]))#重新定向到條目所屬主題的頁面
context = {'entry' : entry, 'topic' : topic, 'form' : form}
return render(request, 'learning_logs/edit_entry.html', context)
3.模板edit_entry
edit_entry.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>Edit entry:</p>
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">save changes</button>
</form>
{% endblock content %}
4.鏈接到頁面edit_entry
topic.html
--snip--
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d,Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
<p>
<a href="{% url 'learning_logs:edit_entry' entry.id %}">edit entry</a>
</p>
</li>
--snip--
每個條目都有一個用於對其進行編輯的鏈接