1. 程式人生 > >Django專案——使用表單新增一個主題的條目

Django專案——使用表單新增一個主題的條目

一 程式碼

1 learning_logs/forms.py

# -*- coding: utf-8 -*-
# 匯入模組 forms 以及要使用的模型 Topic,Entry
from django import forms

from .models import Topic, Entry

'''
定義了一個名為 TopicForm 的類,它繼承了 forms.ModelForm
最簡單的 ModelForm 版本只包含一個內嵌的 Meta 類,它告訴 Django 根據哪個模型建立表單,以及在表單中包含哪些欄位。
根據模型 Topic 建立一個表單,該表單只包含欄位 text
'''
class TopicForm(forms.ModelForm):
    class Meta:
        model = Topic
        fields = ['text']
        # 讓 Django 不要為欄位 text 生成標籤。
        labels = {'text': ''}

class EntryForm(forms.ModelForm):
    class Meta:
        model = Entry
        fields = ['text']
        # 這裡也給欄位 'text' 指定了一個空標籤
        labels = {'text': ''}
        # 通過設定屬性 widgets ,可覆蓋 Django 選擇的預設小部件。
        # 通過讓 Django 使用 forms.Textarea ,我們定製了欄位 'text' 的輸入小部件,將文字區域的寬度設定為 80 列,而不是預設的 40 列。
        # 這給使用者提供了足夠的空間,可以編寫有意義的條目。
        widgets = {'text': forms.Textarea(attrs={'cols': 80})}

2 learning_logs/urls.py

# -*- coding: utf-8 -*-

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
    
    # 用於新增新主題的網頁
    # 該URL 模式將請求交給檢視函式 new_topic()
    url(r'^new_topic/$', views.new_topic, name='new_topic'),

    # 用於新增新條目的頁面
    # 這個 URL 模式與形式為 http://localhost:8000/new_entry/ id / 的 URL 匹配,其中 id  是一個與主題 ID 匹配的數字。
    # 程式碼 (?P<topic_id>\d+) 捕獲一個數字值,並將其儲存在變數 topic_id 中。
    # 請求的 URL 與這個模式匹配時, Django 將請求和主題 ID 傳送給函式 new_entry() 。
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
    
    # Page for editing an entry.
    url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry,
        name='edit_entry'),
]

3 learning_logs/views.py

# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required

from .models import Topic, Entry
from .forms import TopicForm, EntryForm

def index(request):
    return render(request, 'learning_logs/index.html')

def topics(request):
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

def topic(request, topic_id):
    topic = Topic.objects.get(id=topic_id)
    # Make sure the topic belongs to the current user.
    if topic.owner != request.user:
        raise Http404
        
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)


def new_topic(request):
    """ 新增新主題 """
    if request.method != 'POST':
        # 未提交資料:建立一個新表單
        form = TopicForm()
    else:
        # POST 提交的資料 , 對資料進行處理
        # HttpResponseRedirect 類,使用者提交主題後我們將使用這個類將使用者重定向到網頁 topics 。
        # 函式 reverse() 根據指定的 URL 模型確定 URL ,這意味著 Django將在頁面被請求時生成 URL 。
        # 我們還匯入了剛才建立的表單 TopicForm 。
        # 我們使用使用者輸入的資料(它們儲存在 request.POST 中)建立一個 TopicForm 例項
        # 這樣物件 form 將包含使用者提交的資訊。
        form = TopicForm(request.POST)
        # 函式 is_valid() 核實使用者填寫了所有必不可少的欄位(表單欄位預設都是必不可少的),
        # 且輸入的資料與要求的欄位型別一致(例如,欄位 text 少於 200 個字元)。
        # 這種自動驗證避免了我們去做大量的工作。
        if form.is_valid():
            new_topic = form.save(commit=False)
            new_topic.owner = request.user
            # 將表單中的資料寫入資料庫
            new_topic.save()
            # 使用 reverse() 獲取頁面 topics 的 URL ,並將其傳遞給 HttpResponseRedirect()
            # 後者將使用者的瀏覽器重定向到頁面 topics 。
            # 在頁面 topics 中,使用者將在主題列表中看到他剛輸入的主題。
            return HttpResponseRedirect(reverse('learning_logs:topics'))

    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)


def new_entry(request, topic_id):
    """ 在特定的主題中新增新條目 """
    # 形參 topic_id ,用於儲存從 URL 中獲得的值。渲染頁面以及處理表單資料時,都
    # 需要知道針對的是哪個主題,因此我們使用 topic_id 來獲得正確的主題。
    topic = Topic.objects.get(id=topic_id)
    if topic.owner != request.user:
        raise Http404
    
    if request.method != 'POST':
        # 未提交資料 , 建立一個空表單
        form = EntryForm()        
    else:
        # POST 提交的資料 , 對資料進行處理
        form = EntryForm(data=request.POST)
        if form.is_valid():
            # 讓 Django 建立一個新的條目物件,並將其儲存到 new_entry 中,但不將它儲存到資料庫中。
            new_entry = form.save(commit=False)
            # 設定條目物件的屬性 topic ,再將條目物件儲存到資料庫。
            new_entry.topic = topic
            new_entry.save()
            # 呼叫 reverse() 時,需要提供兩個實參:要根據它來生成 URL 的 URL 模式的名稱;
            # 列表 args ,其中包含要包含在 URL 中的所有實參。在這裡,列表 args 只有一個元素 —— topic_id 。
            # 接下來,呼叫 HttpResponseRedirect() 將使用者重定向到顯示新增條目所屬主題的頁面,使用者將在該頁面的
            # 條目列表中看到新新增的條目。
            return HttpResponseRedirect(reverse('learning_logs:topic',
                                        args=[topic_id]))
    
    context = {'topic': topic, 'form': form}
    return render(request, 'learning_logs/new_entry.html', context)

4 learning_logs/templates/learning_logs/new_entry.html

{% extends "learning_logs/base.html" %}

{% block content %}

  <p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
    
  <p>新增新條目</p>
  <form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <button name='submit'>新增新條目</button>
  </form>
    
{% endblock content %}

5 learning_logs/templates/learning_logs/topic.html

{% extends 'learning_logs/base.html' %}

{% block content %}

  <p>主題: {{ topic }}</p>

  <p>條目:</p>
  <p>
      <!---顯示條目前新增連結,因為在這種頁面中,執行的最常見的操作是新增新條目。-->
      <a href="{% url 'learning_logs:new_entry' topic.id %}">新增新條目</a>
  </p>
  <ul>
  {% 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 %}">編輯新條目</a>
      </p>
    </li>
  {% empty %}
    <li>
      There are no entries for this topic yet.
    </li>
  {% endfor %}
  </ul>

{% endblock content %}

二 測試