[Python+Django]初心者筆記11(form表單介紹 part1)

[Python+Django]初心者筆記11(form表單介紹 part1)

預計新增一個圖書館員才有權限的功能,讓他可以幫讀者更新書本到期的日期
先新增這個檔案locallibrary/catalog/forms.py,內容是:
forms.py是專門用來驗證表單是否正確用的

from django import forms

from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
import datetime #for checking renewal date range.
    
class RenewBookForm(forms.Form):
    #取得表單的input資料
    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")

    #clean_OOXX就是用來驗證這個欄位的
    def clean_renewal_date(self):
        data = self.cleaned_data['renewal_date']
        
        #Check date is not in past. 
        if data < datetime.date.today():
            raise ValidationError(_('Invalid date - renewal in past'))

        #Check date is in range librarian allowed to change (+4 weeks).
        if data > datetime.date.today() + datetime.timedelta(weeks=4):
            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))

        # Remember to always return the cleaned data.
        return data



然後在locallibrary/catalog/urls.py最下面加入:

#圖書館管理人員限定的 更新讀者書本到期日的功能
#網址格式:/catalog/book/<bookinstance id>/renew/ 
#renew_book_librarian是底線分隔,表示這是一個function-based view
urlpatterns += [   
    path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'),
]


再來於locallibrary/catalog/views.py加入:

#renew_book_librarian用於讀書館員幫讀者手動更新書的到期日	
from django.contrib.auth.decorators import permission_required

from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
import datetime

from .forms import RenewBookForm

#加上適當的權限,限制此功能只有圖書館員可使用
@permission_required('catalog.can_edit_all_borrowed_books')
def renew_book_librarian(request, pk):
    """
    View function for renewing a specific BookInstance by librarian
    """
	#執行query到db找這筆資料
    #找不到這筆資料的話,會丟出404網頁錯誤
    book_inst=get_object_or_404(BookInstance, pk = pk)

	#if post == true, 表示是user編輯完畢
    # If this is a POST request then process the Form data
    if request.method == 'POST':

		# 透過forms.py去驗證使用者提交的欄位value是否合法
        # Create a form instance and populate it with data from the request (binding):
        form = RenewBookForm(request.POST)

		#透過reverse,可以將url.py的name轉成實際的網址
        # Check if the form is valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
            book_inst.due_back = form.cleaned_data['renewal_date']
            book_inst.save()

            # redirect to a new URL:
            return HttpResponseRedirect(reverse('all-borrowed') )

	#if post == false, 表示是user初次載入這個編輯頁,僅給予一些欄位預設value而已
    #預設給讀者多三個禮拜的時間續借			
    # If this is a GET (or any other method) create the default form.
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})

    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})

接著請新增template檔/catalog/templates/catalog/book_renew_librarian.html,內容如下:

{% extends "base_generic.html" %}
{% block content %}

    <!-- book_inst的由來是views.py -->
    <h1>Renew: {{bookinst.book.title}}</h1>
    <p>Borrower: {{bookinst.borrower}}</p>
    <p{% if bookinst.is_overdue %} class="text-danger"{% endif %}>Due date: {{bookinst.due_back}}</p>
    
    <form action="" method="post">
        {% csrf_token %}
        <table>
            <!-- forms.py定義的欄位將會自動在下面的form變數裡面產生 -->
        {{ form }}
        </table>
        <input type="submit" value="Submit" />
    </form>

    <!-- 讓畫面上的date欄位有可愛的UI可以快速選取日期 -->
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <link rel="stylesheet" href="/resources/demos/style.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script>
        $( function() {
            $( "#id_renewal_date" ).datepicker( { dateFormat: 'yy-mm-dd' } );
        } );
    </script>

{% endblock %}

為了方便測試上面新增的部分,我們在上一篇文章
[Python+Django]初心者筆記11(authentication,authorization,login驗證機制範例,permission權限機制範例)
的bookinstance_list_borrowed_all.html所列出的每本書籍的後面加入以下這段,這樣就方便使用本篇新增的功能,去更新每個借出去的書本的到期時間:

- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a>

測試只要以圖書館員身份登入之後打開網頁http://127.0.0.1:8000/catalog/borrowed/,即可透過"ReNew"按鈕更新書本的到期日了:



這篇先這樣,其他的在part2才繼續,不然篇幅太長……

參考資料:
Django Tutorial Part 9: Working with forms
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms