Python Django 學習紀錄(五) 資料新增、刪除和修改

 

 

一、表單資料的傳送與接收:

 

1.表單傳送資料的方法

在頁面中建置表單區域,區域內放置填寫資料的表單元件,按下表單中的submit送出資料,頁面會將表單區域中的資料傳定的目標網頁接收處理。

<form> 標籤所包圍的區域為表單區域,action 屬性指定傳送的目標頁面,method 屬性即是傳送的方式,又分為GET跟POST兩種

  • GET   :表單資料將以字串的方式附加在網址後面傳送
  • POST :表單資料將放置在HTTP標頭的方式傳送 

2.表單接收資料的方法

在<views.py>視圖中的函式,第一個參數必須是HttpRequest型別物件(預設名稱為 request),它包含頁面請求和使用者資訊。

request提供三種方法:

  • GET:取得以GET方式傳送的表單欄位內容
  • POST:取得以POST方式傳送的表單欄位內容
  • method:取得表單的傳送方式

 

這裡將延續使用 學習紀錄(四) 的 students 專案

URL路徑設定的官方說明文件

首先在 <urls.py> 定義下列的 URL:

先將還不會用到的路徑註解掉,之後要使用時再陸續打開,以免之後運行伺服器會產生找不到路徑中函數的問題:  

from django.contrib import admin
from django.urls import path,re_path
from studentsapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('listone/',views.listone),
    path('listall',views.listall),
    path('',views.index),
    path('index/',views.index),

    path('post/',views.post),    #POST傳送表單
    # path('post1/',views.post1),  #資料新增,資料不驗證
    # path('post2/',views.post2),  #資料新增,資料作驗證

    # re_path(r'delete/(\d+)/$',views.delete),

    # re_path(r'edit/(\d+)/$',views.edit),
    # re_path(r'edit/(\d+)/(\w+)$',views.edit),  #由 瀏覽器開啟
    # re_path(r'edit2/(\d+)/(\w+)$',views.edit2),

    # path('postform',views.postform),    #表單驗證

]

 

範例1.使用POST方式傳送資料

欲達成目標:

  • 佈置一個簡單的表單,使用POST的方式傳送資料到目標網頁接收顯示

請打開studentsapp裡的<view.py>寫一個名為post的自訂函數    

def post(request):
    if request.method == "POST":        #如果是以POST的方式才處理
        mess = request.POST['username'] #取得表單輸入資料
    else:
        mess = "表單資料尚未送出!"
    return render(request,"post.html",locals())

 

接著在 templates目錄中創建一個<post.html>模版  

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>表單傳送範例</title>
</head>
<body>
    <form action="/post" method="POST" name="form1">
        {% csrf_token %}  <!-- 啟動CSRF防護,保護伺服器避免被攻擊 -->
        <div>請輸入姓名:<input type="text" name="username">
            <input type="submit" value="送出資料">
        </div>
        <div>接收到的資料:{{mess}}</div>
    </form>
</body>
</html>

最後記得在在<urls.py>新增post的url路徑(或是去掉之前的註解)

網頁執行結果如下:

36.JPG

輸入好資料後,點選送出資料

37.JPG

※範例.整合資料目錄

接下來將會做「新增、修改、刪除」的動作,而這些都將反映在最後的目錄上,所以先將整合的目錄先寫出來,再來才做新增修改刪除的動作。

對於之前的<index.html>相比而言,加入了許多與其他頁面的連結。

※按下編輯二按鈕時以「"/edit2/{{student.id}}/load"」傳送id和load參數,load字串表示他是由<index.html>傳送過來的。

打開在 templates目錄中的<index.html>模版,這將是所有程式最後指向的目錄:

{% extends 'base.html' %}

{% block title %}
    <title>顯示所有資料</title>{% endblock %}
{% block content %}
    <h2 align="left">
       顯示 student 資料表所有資料 &nbsp;&nbsp;
       <a href="/post1/">新增一</a>
       <a href="/post2/">新增二</a>
    </h2>
    <table border="1" cellpadding="0" cellspacing="0">
        <th>編號</th>
        <th>姓名</th>
        <th>性別</th>
        <th>生日</th>
        <th>郵件帳號</th>
        <th>電話</th>
        <th>地址</th>
        {% for student in students %}   
        <tr>
            <td>{{student.id}}  </td>
            <td>{{student.cName}}  </td>
            <td>{{student.cSex}}  </td>
            <td>{{student.cBirthday}}  </td>
            <td>{{student.cEmail}}  </td>
            <td>{{student.cPhone}}  </td>
            <td>{{student.cAddr}}  </td>
            <td>
                <a href="/edit/{{student.id}}" title="編輯一">編輯一</a>
                <a href="/edit/{{student.id}}/load" title="編輯二">編輯二</a>
                <a href="/delete/{{student.id}}" title="刪除">刪除</a>
            </td>
        </tr>
        {% endfor %}
    </table>



{% endblock %}

二、資料新增:

 

1.資料新增和儲存

利用 objects.create方法可以新增一筆資料,語法: 

紀錄 = 資料表.object.create(欄位 1= 內容 1,...)

: 以save方法可以將該筆紀錄寫入資料庫

unit.save()

範例2.資料新增

欲達成目標:

  • 將表單資料和資料庫結合,在表單輸入資料後,以POST方式傳送資料到資料庫建立一筆紀錄

請打開studentsapp裡的<view.py>寫一個名為post1的自訂函數    

這裡會使用到redirect套件,所以要導入該套件 from django.shortcuts import render,redirect

def post1(request):
    if request.method == "POST":#如果是以POST的方式才處理
        cName = request.POST['cName']    #取得表單輸入資料
        cSex = request.POST['cSex']
        cBirthday = request.POST['cBirthday']
        cEmail = request.POST['cEmail']
        cPhone = request.POST['cPhone']
        cAddr = request.POST['cAddr']
        unit = student.objects.create(cName=cName, cSex=cSex, cBirthday=cBirthday, cEmail=cEmail, cPhone=cPhone, cAddr=cAddr) 
        unit.save()                      #寫入資料庫
        return redirect('/index/')       #重導到<index.html>網頁
    else:
        message = '請輸入資料(資料不作驗證)'
    return render(request, "post1.html", locals())

接著在 templates目錄中創建一個<post1.html>模版  

{% extends 'base.html' %}

{% block title %}
<meta charset="utf-8">
<title>資料表新增(一)</title>
{% endblock %}

{% block content %}
    <h2>資料表新增(一)</h2>
    
    <form action="." method="POST" name="form1">   <!-- "."表示執行相同的url -->
        {% csrf_token %}     #CSRF防護請加在此
        <table border="1" cellpadding="1" cellspacing="4">
            <tr>
                <th>姓名</th>
                <td><input type="text" id="cName" name="cName" /></td>
            </tr>
            <tr>
                <th>姓別</th>
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M" checked="checked"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F"/>女生
                </td>
            </tr>
            <tr>
                <th>生日</th>
                <td><input type="text" id="cBirthday" name="cBirthday" /></td>
            </tr>
            <tr>
                <th>郵件帳號</th>
                <td><input type="text" id="cEmail" name="cEmail" /></td>
            </tr>
            <tr>
                <th>電話</th>
                <td><input type="text" id="cPhone" name="cPhone" /></td>
            </tr>
            <tr>
                <th>地址</th>
                <td><input type="text" id="cAddr" name="cAddr" /></td>
            </tr>

            <tr>
                <th colspan="2" align="center">
                    <input type="submit" name="button" id="button" value="送出">
                    <input type="reset" name="button2" id="button2" value="重設">
            </tr>
        </table>
        <span style="color:red">{{message}}</span>
    </form>    
{% endblock %}

最後記得在<urls.py>新增post1的url路徑(或是去掉之前的註解)

網頁執行結果如下:

39.JPG

新增後結果如下:

44.JPG

※編號為6是因為我刪除兩筆資料做過測試,所以這邊再新增直接從6開始

三、表單模型化:

若輸入的資料並未作驗證,很容易引發不可預期的錯誤,Django提供很好的表單驗證,可以有效的驗證資料格式是否正確。

1.建立表單模型

首先必須在 studentsapp 目錄下新增一個 <form.py> 檔案,然後建立繼承forms.Form的類別,格式與Mode的格式相似

max_length可設定最大長度,initial設定初始值,required設定資料是否可選填,預設值True表示資料不可空白 

以下將建立一個名為PostForm類別的表單模型

from django import forms #導入form套件

class PostForm(forms.Form):  #建立類別,需繼承 forms.Form
    cName = forms.CharField(max_length=20,initial='')
    cSex = forms.CharField(max_length=2,initial='M')
    cBirthday = forms.DateField()
    cEmail = forms.CharField(max_length=100,initial='',required=False)
    cPhone = forms.CharField(max_length=20,initial='',required=False)
    cAddr = forms.CharField(max_length=20,initial='',required=False)

2.建立表單模型物件

利用表單模型就可以建立表單物件,例如以PostForm類別建立空白物件:

postform = PostForm()

也可以字典建立含有初始值的物件。

而因為request.POST可以取得form表單以POST方式傳送的資料,最適合直接用來建立表單物件,這樣postform初始值就是表單傳送的資料:

postform = PostForm(request.POST)

 

3.輸出表單

輸出表單的部分將在下面的範例直接示範說明。

 

範例3.基本表單驗證

欲達成目標:

  • 利用表單模型物件,建立基本的表單驗證

請打開studentsapp裡的<view.py>寫一個名為postform的自訂函數,並將其中的postform物件傳送給<postform.html>樣板    

from studentsapp.form import PostForm #導入form模型的PostForm類別
def postform(request):
    postform = PostForm()   #建立postform物件
    return render(request,"post.html",locals())

接著在 templates目錄中創建一個<postform.html>模版  

{% extends "base.html" %}
{% block title %}<title>基本表單驗證</title>{% endblock %}
{% block content %}
<h2>基本表單驗證</h2>
<form action="." method="POST" name="form1">
    {% csrf_token %}
    <table border="1" cellspacing="1" cellpadding="4">
        {{postform}}
        <!-- {{postform.as_p}} #段落模式 -->
        <!-- {{postform.as_ul}} #列表格式 -->
    </table>
    
</form>
{% endblock %}

最後記得在<urls.py>新增postform的url路徑(或是去掉之前的註解)

網頁執行結果如下:

40.JPG

4.表單樣式客製化

以單一欄位輸出的表單格式可以搭配css樣式製作個人風格,例如:

<p class="css1">姓名:{{postform.cName}}</p>

5.表單驗證

前面已經有提到,在表單輸入欄位的設定,required 表示資料是否可選填,預設值True表示資料不可空白 ,則輸入的資料就必須符合其型別驗證,例如type=Email的輸入資料就必須符合Email格式。若值為False則表示資料可以空白。

可以用 is_vaild()方法檢查輸入資料是否通過驗證,通過驗證後就可以cleaned_data取得表單輸入的資料,例如:

if postform.is_vaild():
    cName = postform.cleaned_data['cName']

 

範例4.資料新增並驗證

欲達成目標:

  • 在表單中輸入資料後,以POST方式傳送到資料庫建立一筆紀錄,輸入資料必須作驗證

請打開studentsapp裡的<view.py>寫一個名為post2的自訂函數

  1. 判斷是否以POST方式送出
  2. 檢查表單是否通過form驗證
  3. 通過驗證的話就以cleaned_data取得輸入資料,並將其寫入資料庫
def post2(request):                  #新增資料,資料必須驗證
    if request.method == "POST":     #如果是以POST方式才處理
        postform = PostForm(request.POST)  #以form表單以POST方式傳入的資料為初始值
        if postform.is_valid(): #檢查是否通過forms驗證
          cName = postform.cleaned_data['cName']    #取得表單輸入資料
          cSex = postform.cleaned_data['cSex']
          cBirthday = postform.cleaned_data['cBirthday']
          cEmail = postform.cleaned_data['cEmail']
          cPhone = postform.cleaned_data['cPhone']
          cAddr = postform.cleaned_data['cAddr']
          #新增一筆資料
          unit = student.objects.create(cName=cName,cSex=cSex,cBirthday=cBirthday,cEmail=cEmail,cPhone=cPhone,cAddr=cAddr)
          unit.save() #寫入資料庫
          message = "已儲存"
          return redirect('/index/')
        else:
            message = "驗證碼錯誤!"   #若未通過驗證,顯示此訊息
    else:
        message = "姓名、性別、生日必須輸入!"
        postform = PostForm()  #建立空白的postform物件
    return render(request,"post2.html",locals())

接著在 templates目錄中創建一個<post2.html>模版  

建立表單,輸入資料後以POST的方式傳送資料並驗證

{% extends 'base.html' %}

{% block title %}
<meta charset="utf-8">
<title>資料表新增(二)</title>
{% endblock %}

{% block content %}
    <h2>資料表新增(二)</h2>
    
    <form action="." method="POST" name="form1">   <!-- "."表示執行相同的url -->
        {% csrf_token %}     <!-- #CSRF防護請加在此 -->
        <table border="1" cellpadding="1" cellspacing="4">
            <tr>
                <th>姓名</th>
                <td>{{postform.cName}}</td>
            </tr>
            <tr>
                <th>姓別</th>
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M" checked="checked"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F"/>女生
                </td>
            </tr>
            <tr>
                <th>生日</th>
                <td>{{postform.cBirthday}}</td>
            </tr>
            <tr>
                <th>郵件帳號</th>
                <td>{{postform.cEmail}}</td>
            </tr>
            <tr>
                <th>電話</th>
                <td>{{postform.cPhone}}</td>
            </tr>
            <tr>
                <th>地址</th>
                <td>{{postform.cAddr}}</td>
            </tr>

            <tr>
                <th colspan="2" align="center">
                    <input type="submit" name="button" id="button" value="送出">
                    <input type="reset" name="button2" id="button2" value="重設">
            </tr>
        </table>
        <span style="color:red">{{message}}</span>
    </form> 
{% endblock %}

最後記得在<urls.py>新增post2的url路徑(或是去掉之前的註解)

網頁執行結果如下:

43.JPG

※未通過驗證的話會出現提醒輸入的訊息

 

 

四、資料刪除:

delete 可以刪除指定的資料,使用 objects 物件的 get all 或 filter方法可取得資料,再以 delete 方法刪除指定的資料

例如刪除 「id = 6」的資料:

id = 6
unit = student.object.get(id=id)
unit.delete

 

範例5.資料刪除

欲達成目標:

  • 依據 id 取得該筆資料,再以 delete 刪除該筆資料。
  • 若 id 不存在則將顯示頁面讓使用者重新輸入編號

請打開studentsapp裡的<view.py>寫一個名為delete的自訂函數

def delete(request,id=None):                  #刪除資料
    if id!=None:
        if request.method == "POST":  #如果是以POST的分是才處理
            id = request.POST('cId')  #取得表單輸入的編號
        try:
            unit = student.objects.get(id=id)  #取得id欄位的資料
            unit.delete()                      #刪除資料
            return redirect('/index/')
        except:
            message = "讀取錯誤!"
    return render(request,"delete.html",locals())

接著在 templates目錄中創建一個<delete.html>模版  

建立表單,輸入資料後以POST的方式傳送資料

{% extends "base.html" %}
{% load staticfiles %}
{% block title %}<title>資料表刪除</title>{% endblock %}
{% block content %}
    <h2>資料表刪除</h2>
    <form action="." method="POST" name="form1">
        {% csrf_token %}
        <div>請輸入編號:<input type="text" name="cId"></div>
        <div><input type="submit" name="button" value="確定刪除" /></div>
        <span style="color: red">{{message}}</span>
    </form>
{% endblock %}

最後記得在<urls.py>新增delete的url路徑(或是去掉之前的註解)

輸入「127.0.0.1:8000/delete/id」後,例如(id=20),會依據 id 刪除指定的資料,或 id 存在就會直接刪除該筆資料,並重新導向到index目錄

若 id 不存在則將顯示以下頁面讓使用者重新輸入編號:

45.JPG

 

五、資料修改:

利用 save 方法可以將資料寫回資料,如此即可修改資料庫。

例如將編號1的 cName 欄位內容更改為「ivankao」:

unit = student.object.get(id=1)
unit.cName = "ivankao"
unit.save()

 

範例6.資料修改(一)

欲達成目標:

  • 依據id取得指定的資料,更改資料後按送出鈕,即會更新資料庫中的該筆資料並重導到index目錄頁面。
  • 若該id不存在會顯示空白表單並出現「此 id 不存在!」的訊息。

 

請打開studentsapp裡的<view.py>寫一個名為edit的自訂函數

在這個自訂函數中,要先判斷mode是否為edit字串,若是表示他是由<edit.html>送出的。

後面最做一個轉日期格式的例外處理,例如將「2001年5月18日」轉換為「2001-05-18」

def edit(request,id=None,mode=None):
    if mode == "edit": #如果是由<edit.html>按submit
        unit = student.objects.get(id=id)  #取得要修改的資料紀錄
        unit.cName = request.GET['cName']    #取得表單輸入資料
        unit.cSex = request.GET['cSex']
        unit.cBirthday = request.GET['cBirthday']
        unit.cEmail = request.GET['cEmail']
        unit.cPhone = request.GET['cPhone']
        unit.cAddr = request.GET['cAddr']
        unit.save()
        message = "已修改"
        return redirect('/index/')
    else: #由網址列直接輸入
        try:
            unit = student.objects.get(id=id)  #取得要修改的資料紀錄
            strdate = str(unit.cBirthday)
            strdate2 = strdate.replace("年","-")
            strdate2 = strdate.replace("月","-")
            strdate2 = strdate.replace("日","-")
            unit.cBirthday = strdate2
        except:
            message = "此 id 不存在!"
    return render(request,"edit.html",locals())

 

接著在 templates目錄中創建一個<edit.html>模版  

建立表單,輸入資料後以GET的方式傳送資料

{% extends 'base.html' %}

{% block title %}
<meta charset="utf-8">
<title>資料表修改(一)</title>
{% endblock %}

{% block content %}
    <h2>資料表修改(一)</h2>
    
    <form action="/edit/{{unit.id}}/edit" method="GET" name="form1">   <!-- 建立form表單,設定傳送方式為GET,「action="/edit/{{unit.id}}/edit"」中第三個參數為edit,表示他是從<edit.html>按送出鈕傳送過來的-->
        {% csrf_token %}     <!-- #CSRF防護請加在此 -->
        <table border="1" cellpadding="1" cellspacing="4">
            <tr>
                <th>姓名</th>
                <td><input type="text" id="cName" name="cName" value="{{unit.cName}}"></td>
            </tr>
            <tr>
                <th>姓別</th>
                {% if unit.cSex == "M" %}
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M" checked="checked"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F"/>女生
                </td>
                {% else %}
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F" checked="checked"/>女生
                </td>
                {% endif %}
            </tr>
            <tr>
                <th>生日</th>
                <td><input type="text" id="cBirthday" name="cBirthday" value="{{unit.cBirthday}}"></td>
            </tr>
            <tr>
                <th>郵件帳號</th>
                <td><input type="text" id="cEmail" name="cEmail" value="{{unit.cEmail}}"></td>
            </tr>
            <tr>
                <th>電話</th>
                <td><input type="text" id="cPhone" name="cPhone" value="{{unit.cPhone}}"></td>
            </tr>
            <tr>
                <th>地址</th>
                <td><input type="text" id="cAddr" name="cAddr" value="{{unit.cAddr}}"></td>
            </tr>

            <tr>
                <th colspan="2" align="center">
                    <input type="submit" name="button" id="button" value="送出">
                    <input type="reset" name="button2" id="button2" value="重設">
            </tr>
        </table>
        <span style="color:red">{{message}}</span>
    </form> 
{% endblock %}

 

最後記得在<urls.py>新增edit的url路徑(或是去掉之前的註解)

網頁執行結果如下(以編號9為例):

46.JPG

若 id 不存在則會顯示空白頁面與提示訊息:

47.JPG

 

 

範例7.資料修改(二)

欲達成目標:

  • 在<index.html>頁面二下編輯二連結,依據id取得指定的資料,更改資料後按送出鈕,即會更新資料庫中的該筆資料並重導到index目錄頁面。
  •  

請打開studentsapp裡的<view.py>寫一個名為edit2的自訂函數

  • 在這個自訂函數中,要先判斷mode是否為load字串,若是表示他是由<index.html>按 編輯二 鈕傳送過來的,則依據id讀取該筆資料。
  • 再來將資料傳給<edit2.html>準備編輯,判斷mode是否為save字串,若是表示他是由<edit2.html>按 送出 鈕傳送過來的

 

def edit2(request,id=None,mode=None):
    if mode == "load": #如果是由 <index.html> 按 編輯二 鈕
        unit = student.objects.get(id=id)  #取得要修改的資料紀錄
        strdate = str(unit.cBirthday)
        strdate2 = strdate.replace("年","-")
        strdate2 = strdate.replace("月","-")
        strdate2 = strdate.replace("日","-")
        unit.cBirthday = strdate2
        return render(request,"edit2.html",loacls())
    elif mode =="save": #如果是由<edit2.html>按submit
        unit = student.objects.get(id=id)  #取得要修改的資料紀錄
        unit.cName = request.POST['cName']    #取得表單輸入資料
        unit.cSex = request.POST['cSex']
        unit.cBirthday = request.POST['cBirthday']
        unit.cEmail = request.POST['cEmail']
        unit.cPhone = request.POST['cPhone']
        unit.cAddr = request.POST['cAddr']
        unit.save()
        message = "已修改"
        return redirect('/index/')

接著在 templates目錄中創建一個<edit.html>模版  

建立表單,輸入資料後POST的方式傳送資料

{% extends 'base.html' %}

{% block title %}
<meta charset="utf-8">
<title>資料表修改(二)</title>
{% endblock %}

{% block content %}
    <h2>資料表修改(二)</h2>
    
    <form action="/edit2/{{unit.id}}/save" method="POST" name="form1">   <!-- 建立form表單,設定傳送方式為POST,「action="/edit2/{{unit.id}}/save"」中第三個參數為save,表示他是從<edit2.html>按送出鈕傳送過來的-->
        {% csrf_token %}     <!-- #CSRF防護請加在此 -->
        <table border="1" cellpadding="1" cellspacing="4">
            <tr>
                <th>姓名</th>
                <td><input type="text" id="cName" name="cName" value="{{unit.cName}}"></td>
            </tr>
            <tr>
                <th>姓別</th>
                {% if unit.cSex == "M" %}
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M" checked="checked"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F"/>女生
                </td>
                {% else %}
                <td>
                    <input type="radio" id="cSex1" name="cSex" value="M"/>男生
                    <input type="radio" id="cSex2" name="cSex" value="F" checked="checked"/>女生
                </td>
                {% endif %}
            </tr>
            <tr>
                <th>生日</th>
                <td><input type="text" id="cBirthday" name="cBirthday" value="{{unit.cBirthday}}"></td>
            </tr>
            <tr>
                <th>郵件帳號</th>
                <td><input type="text" id="cEmail" name="cEmail" value="{{unit.cEmail}}"></td>
            </tr>
            <tr>
                <th>電話</th>
                <td><input type="text" id="cPhone" name="cPhone" value="{{unit.cPhone}}"></td>
            </tr>
            <tr>
                <th>地址</th>
                <td><input type="text" id="cAddr" name="cAddr" value="{{unit.cAddr}}"></td>
            </tr>

            <tr>
                <th colspan="2" align="center">
                    <input type="submit" name="button" id="button" value="送出">
                    <input type="reset" name="button2" id="button2" value="重設">
            </tr>
        </table>
        <span style="color:red">{{message}}</span>
    </form> 
{% endblock %}

最後記得在<urls.py>新增edit的url路徑(或是去掉之前的註解)

在<index.html>按下 編輯二 執行結果如下(以編號9為例):

48.JPG

arrow
arrow
    全站熱搜

    ivankao 發表在 痞客邦 留言(2) 人氣()