1. 程式人生 > >Django專案——編輯主題的條目

Django專案——編輯主題的條目

一 程式碼

1 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'),
    
    # 用於編輯條目的頁面
    # 在 URL (如 http://localhost:8000/edit_entry/1/ )中傳遞的 ID 儲存在形參 entry_id 中。
    # 這個 URL 模式將預期匹配的請求傳送給檢視函式 edit_entry()
    url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry,
        name='edit_entry'),
]

2 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')

@login_required
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)

@login_required
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)

@login_required
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)

@login_required
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)

'''
頁面 edit_entry 收到 GET 請求時, edit_entry() 將返回一個表單,讓使用者能夠對條目進行編輯。
頁面收到 POST 請求(條目文字經過修訂)時,它將修改後的文字儲存到資料庫中
'''
@login_required
def edit_entry(request, entry_id):
    """ 我們獲取使用者要修改的條目物件,以及與該條目相關聯的主題。在請求方法為 GET 時將執行的 if 程式碼塊中,我們使用實
        參 instance=entry 建立一個 EntryForm 例項。
        這個實參讓 Django 建立一個表單,並使用既有條目物件中的資訊填充它。使用者將看到既有的資料,並能夠編輯它們。
        處理 POST 請求時,我們傳遞實參 instance=entry 和 data=request.POST ,讓 Django 根據既有條目物件建立一個表單例項,
        並根據 request.POST 中的相關資料對其進行修改。然後,我們檢查表單是否有效,如果有效,就呼叫 save() ,且不指定任何實參。
        接下來,我們重定向到顯示條目所屬主題的頁面,使用者將在其中看到其編輯的條目的新版本。"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    if topic.owner != request.user:
        raise Http404
    
    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 learning_logs/templates/learning_logs/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>
  <!--實參 action 將表單發回給函式 edit_entry() 進行處理。在標籤 url 中,我們將條目 ID 作為一個實參,
  讓檢視物件能夠修改正確的條目物件。我們將提交按鈕命名為 儲存修改 ,以提醒使用者:單擊該按鈕將儲存所做的編輯,
  而不是建立一個新條目-->
  <form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <button name="submit">儲存修改</button>
  </form>

{% endblock content %}

4 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>
        <!--我們將編輯連結放在每個條目的日期和文字後面。在迴圈中,我們使用模板標籤 url .
         根據 URL 模式 edit_entry 和當前條目的 ID 屬性( entry.id )來確定 URL 。連結
         文字為 "編輯條目" ,它出現在頁面中每個條目的後面。-->
        <a href="{% url 'learning_logs:edit_entry' entry.id %}">編輯條目</a>
      </p>
    </li>
  {% empty %}
    <li>
      沒有針對該主題的條目.
    </li>
  {% endfor %}
  </ul>

{% endblock content %}

二 測試結果