主頁 > 後端開發 > Django-ORM

Django-ORM

2021-06-29 06:19:47 後端開發

Django ORM

ORM(Object Relational Mapping):物件關系映射,描述Django資料模型類和資料庫之間的映射關系,通俗的講就是讓一個類和一個資料庫表進行對應,這使ORM在資料庫層和業務邏輯層之間起到橋梁作用,

Django通過類代碼描述資料表欄位、表間關系等內容,并通過相應命令把類所描述的內容持久化到資料庫,

Django ORM的模式特征

Django ORM與資料庫映射的關系表現為django中的一個資料模型(Model)映射一個資料庫表,其基本情況是:類映射到資料庫表,類的屬性映射為資料庫表欄位,類的實體物件則映射為資料行,

Django ORM能實作的功能:一是生成資料庫表,如資料庫表的創建、修改、洗掉;二是操作資料庫表的資料行,如資料行的增刪改查,但不能創建資料庫,

Django ORM使用步驟主要有:

  1. 在專案使用的資料庫管理系統中建立資料庫,
  2. 在專案的組態檔settings中設定資料庫的連接字符,
  3. 在應用程式的models檔案撰寫繼承于models.Model的資料模型,
  4. 運行python manage.py makemigrations 和 python manage.py migrate 兩個命令生成資料庫表,
  5. 使用django ORM操作資料庫表,

Django ORM的用法

資料庫連接

以MySQL為例,先創建test_orm資料庫,在settings檔案中配置:

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'NAME': 'test_orm',
        'USER': 'root',
        'PASSWORD': '1234',
    }
}
創建資料模型

創建一個group模型,有兩個屬性,即user和email,在models.py中輸入以下代碼,假設在專案中有一個應用名稱為employee,

# 必須匯入資料模型相關的模塊
from django.db import models
# 資料模型一定要繼承于models.Model
class Group(models.Model):
    # group_name為團體名稱,CharField為型別,max_length設定最大字符數
    # verbose_name設定在django Admin管理后臺頁面上顯示的欄位名
    group_name = models.CharField(max_length=32,verbose_name='團體名稱')
    # 團體名稱備注
    group_script = models.CharField(max_length=60,verbose_name='備注')

group_name和group_script可以稱作模型欄位,每個欄位在類中表現為一個類屬性,根據映射關系,每個類屬性映射為一個資料表欄位,

在命令列輸入python manage.py makemigrations 和 python manage.py migrate生成資料表,

Django ORM欄位

Django ORM欄位在models中創建,按照固定格式在資料模型類中建立,主要包括指定欄位名的欄位型別、欄位屬性等,

常用欄位型別
  1. CharField:字符型別,必須提供max_length引數,表示字符長度,verbose_name在Django Admin管理后臺是欄位的顯示名稱,可理解為欄位別名,SQL層面沒有具體體現,對資料庫中的欄位沒有影響,

    name = models.CharField(max_length=32,verbose_name='名稱')
    
  2. EmailField:郵箱型別,實際上是字符型別,只是提供了郵箱格式的校驗,

    email = models.EmailField(verbose_name='郵箱')
    
  3. TextField:文本型別,存盤大段文本字串,

    descript = models.IntegerField(verbose_name='簡介')
    
  4. IntegerField:整數型別,

    int = models.IntegerField()
    
  5. DateField:日期欄位

    date = models.DateField(auto_now=True,auto_now_add=False)
    

    auto_now引數自動保存當前時間,一般用來表示最后修改時間,在第一次創建記錄的時候,django就將auto_now_add欄位值自動設定為當前時間,用來表示記錄物件的創建時間,

  6. TimeField:時間欄位

    time = models.TimeField(auto_now=False,auto_now_add=False)
    
  7. DateTimeField:日期時間欄位,合并了日期欄位與時間欄位,

    datetime = models.DateTimeField(auto_now=False,auto_now_add=False)
    
  8. FileField:實際上是字串型別,用來把上傳的檔案的路徑保存在資料庫中,檔案上傳到指定目錄,主要引數upload_to指明上傳檔案的保存路徑,這個路徑與django組態檔的MEDIA_ROOT有關,

    filetest = models.FileField(upload_to = 'tets/')
    

    如果MEDIA_ROOT = os.path.join(BASE_DIR,'upload/')這句代碼設定MEDIA_ROOT值為/test_orm/upload/,假設在資料表中filetest的值是test.txt,那么檔案路徑為/test_orm/upload/test/test.txt,

  9. ImageField

    picture = models.ImageField(upload_to = 'pic/')
    
常用欄位屬性
  1. db_index:等于True表示設定此欄位為資料庫表的索引,

    title = models.CharField(max_length=32,db_index=True)
    
  2. unique:等于True表示該欄位在資料庫表中不能有重復值,

  3. default:設定欄位默認值,如default=’good’,

  4. auto_now_add:是DateTimeField、TimeField、DateField的獨有屬性,等于True表示把新建該記錄的時間保存為該欄位的值,

  5. auto_now:是DateTimeField、TimeField、DateField的獨有屬性,等于True表示每次修改記錄時,把當前時間存盤到該欄位,

Django ORM基本資料操作

通過資料模型的objects屬性來提供資料操作的介面,

  • 增加記錄

    # 第一種方式
    new_emp = models.employee.objects.create(name = "tom",email = "[email protected]",dep_id = 66)
    # 第二種方式
    new_emp = models.employee(name = "tom",email = "[email protected]",dep_id=66)
    new_emp.save()
    
  • 洗掉記錄,用filter()過濾出符合條件的記錄后呼叫delete()洗掉,

    models.employee.objects.filter(name='張三').delete()
    
  • 修改記錄

    # 將指定條件的記錄更新,并更新指定欄位的值
    models.employee.objects.filter(name='tom').update(email='[email protected]')
    # 修改單條資料
    obj = models.employee.objects.get(id=66)
    obj.email = '[email protected]'
    obj.save()
    
  • 查詢

    # 查詢全部
    emp_list = models.employee.objects.all()
    # 獲取單條資料,資料不存在則報錯
    emp=models.employee.objects.get(id=123)
    # 獲取指定條件的記錄集
    emp_group = models.employee.objects.filter(name='張三')
    
Django ORM資料庫操作常用函式

下面列舉的5個函式的回傳值都是QuerySet物件集,

  • all()函式,回傳符合條件的全部記錄,

    objects = models.employee.objects.all()
    
  • filter()函式,回傳指定條件的記錄,filter后面的括號內是過濾條件,

    objects = models.employee.objects.filter(name='tom')
    

    過濾一般用“欄位名+雙下劃線+條件名詞”,

    # 獲取name欄位包含tom的記錄
    models.employee.objects.filter(name__contains="tom")
    # 獲取name欄位包含tom的記錄,忽略大小寫
    models.employee.objects.filter(name__icontains="tom")
    # 獲取employee資料表中id=10、20、66的資料
    models.employee.objects.filter(id__in=[10,20,66])
    # 獲取employee資料表中id不等于10、20、66的資料
    models.employee.objects.exclude(id__in=[10,20,66])
    # 獲取employee資料表中id大于1且小于10的記錄
    models.employee.objects.filter(id_gt=1,id_lt=10)
    # 獲取employee資料表中id在1~66內的記錄
    models.employee.objects.filter(id_range=[1,66])
    # 獲取employee資料表中birthday欄位月份為9的記錄
    models.employee.objects.filter(birthday_month=9)
    
  • exclude()函式,回傳不符合括號內條件的記錄,和filter相反,

    objects = models.employee.objects.exclude(name='tom')
    
  • order_by()函式,按照括號內的欄位排序,

    objects = models.employee.objects.exclude(name='tom').order_by('name','id')
    

    欄位名中加-,表示按該欄位倒序排序,如下按name欄位倒序排列串列,

    objects = models.employee.objects.order_by('-name')
    
  • distinct()函式,去掉記錄集合中完全一樣的記錄再回傳,

    objects = models.employee.objects.filter(name='tom').distinct()
    

以下三個函式回傳其他資料型別,可以理解為特殊的QuerySet型別,

  • values()函式,回傳一個字典型別序列,

    objects = models.employee.objects.values('id','name','email')
    <QuerySet
    [{'id':1,'name':'大華','email':'[email protected]'},{'id':2,'name':'大d','email':'[email protected]'}]
    >
    
  • values_list()函式,回傳一個元組型別序列,回傳一個元組型別序列,

    objects = models.employee.objects.values_list('id','name','email')
    <QuerySet
    [('id':1,'name':'大華','email':'[email protected]'),('id':2,'name':'大d','email':'[email protected]')]
    >
    
  • get()、first()、last()回傳單個物件,可以理解為回傳資料表中的一條記錄,

    # 回傳id為1的記錄,括號內是過濾條件
    object1=models.employee.objects.get(id=1)
    # 回傳資料集的第一條記錄
    object2=models.employee.objects.first()
    # 回傳資料集的最后一條記錄
    object3=models.employee.objects.last()
    # 回傳資料集的個數
    object4=models.employee.objects.count()
    

樣例1:資料庫表操作

準備作業
  1. 先建立一個test_orm專案,輸入django-admin startproject test_orm,生成專案,這個test_orm就是專案的根目錄,里面包括一個test_orm/專案目錄和一個manage.py,里面包括生成django應用程式、資料庫表等命令集,

  2. 在命令列終端輸入python manage.py startapp employee,生成一個應用程式,

  3. 以MySQL作為后臺資料庫,新建資料庫名稱為test_orm,

  4. 如果沒有pymysql模塊先安裝,然后在/test_orm//test_orm/__init__.py檔案中輸入以下代碼,使用pymysql代替Django MySQL客戶端模塊,

    import pymysql
    pymysql.install_as_MySQLdb()
    
  5. 在settings里修改配置,一是在INSTALLED_APPS里加入employee,二是在DATABASES里把資料庫配置為MySQL型別:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'NAME': 'test_orm',
            'USER': 'root',
            'PASSWORD': '1234',
        }
    }
    
  6. 在models中輸入資料模型代碼:

    from django.db import models
    # 員工資料模型(員工資料表)
    class employee(models.Model):
        name = models.CharField(max_length=32,verbose_name='姓名')
        email = models.EmailField(verbose_name='郵箱')
        # 員工部門,Foreignkey型別,與department表中記錄形成多對一關系
        # on_delete = models.CASCADE表示如果外鍵所關聯的department表中的一條記錄被洗掉
        # 本表中與這條記錄有關的記錄將全被洗掉
        # 有外鍵的表是多,關聯的表是一
        # 外鍵在資料庫表中以外鍵名_id形式命名欄位
        dep = models.ForeignKey(to="department",on_delete=models.CASCADE)
        # 員工加入的團體,多對多關系
        group = models.ManyToManyField(to="group")
        salary = models.DecimalField(max_digits=8, decimal_places=2)
        info = models.OneToOneField(to="employeeinfo",on_delete=models.CASCADE,null=True)
    
    # 部門資料模型(部門資料表)
    class department(models.Model):
        dep_name = models.CharField(max_length=32,verbose_name='部門名稱')
        dep_script = models.CharField(max_length=60, verbose_name='備注')
        
    # 團體資料表
    class group(models.Model):
        group_name = models.CharField(max_length=32,verbose_name='團體名稱')
        group_script = models.CharField(max_length=60,verbose_name='備注')
        
    # 員工補充資訊資料表
    class employeeinfo(models.Model):
        phone = models.CharField(max_length=11)
        address = models.CharField(max_length=50)
    
  7. 終端輸入python manage.py makemigrations和python manage.py migrate生成資料表,第一個命令對資料模型代碼進行檢查,出錯時回傳相關資訊,第二個命令真正建立資料表,

    提示:如果出錯,去應用里的migrations里面洗掉__pycache__和0001_initial即可,

建立路由與視圖函式對應關系

Django是在urls中設立路由與視圖函式的對應關系,用戶在瀏覽器地址欄中輸入網址,django通過URL配置關系找到對應函式,這個函式接受請求,運行其中的邏輯代碼并生成回應發回瀏覽器,從而完成一次用戶業務訪問程序,

為了層次清晰,我們建立兩級URL組態檔,先建一級組態檔,在urls中輸入:

urlpatterns = [
    path('admin/', admin.site.urls),
    # 用include()函式把二級配置包含進來
    path('test_orm_old/', include('employee.urls')),
]

說明:

  • include函式的引數是一個字串,這個字串指定二級URL組態檔的位置,用點作為分隔符,并且最后的檔案名不包含擴展名,
  • 如果URL組態檔分級,那么在匹配URL時,要把各級組態檔中URL運算式合并成一個完整的URL運算式進行匹配,

在employee檔案夾下新建一個urls檔案,輸入:

from django.urls import path,include
# 匯入視圖函式
from employee.views import *
urlpatterns = [
    # 操作員工資料表相關URL配置項
    path('list_employee_old/',list_employee_old),
    path('add_employee_old/',add_employee_old),
    path('edit_employee_old/<int:emp_id>/',edit_employee_old),
    path('del_employee_old/<int:emp_id>/',delete_employee_old),
    # 操作部門資料表相關URL配置項
    path('add_dep_old/',add_dep_old),
    path('list_dep_old/',list_dep_old),
    path('del_dep_old/<int:dep_id>/',del_dep_old),
    path('edit_dep_old/<int:dep_id>/',edit_dep_old),
    # 操作團體資料表相關URL配置項
    path('add_group_old/',add_group_old),
    path('list_group_old/',list_group_old),
    path('del_group_old/<int:group_id>/',del_group_old),
    path('edit_group_old/<int:group_id>/',edit_group_old),
    # 操作員工補充資訊資料表相關URL配置項
    path('add_employeeinfo_old/', add_employeeinfo_old),#增加一條用戶補充資訊(employeeinfo表)
    path('list_employeeinfo_old/', list_employeeinfo_old),#用戶補充資訊串列(employeeinfo表)
    path('del_employeeinfo_old/<int:info_id>/', del_employeeinfo_old),#洗掉一條用戶補充資訊(employeeinfo表)
    path('edit_employeeinfo_old/<int:info_id>/', edit_employeeinfo_old),#修改一條用戶補充資訊(employeeinfo表)
]

說明:

  • 以上代碼分別建立員工、部門、團體、員工補充資訊的增刪改查配置項,path()的兩個引數一個用來匹配路徑,被稱作URL運算式,它匹配網址的方式類似于正則運算式;另一個是視圖函式名,在views中定義,
  • 我們在URL運算式和視圖函式名后面都加了_old,因為這是初始版本,沒有對頁面進行美化,后續會有新樣例,
撰寫視圖函式

在urls中建立對應關系后還需建立相應的視圖函式,函式名與path第二個引數相同,

打開views,撰寫對部門資料表department進行串列查詢,

from django.shortcuts import render,redirect,HttpResponse
from .models import employee,department,group,employeeinfo
# 對部門資料表的增刪改查
def list_dep_old(request):
    # 取得資料庫表全部記錄
    dep_list = department.objects.all()
    return render(request,'test_orm_old/list_dep_old.html',{'dep_list':dep_list})

說明:

首先匯入模塊和4個資料模型,dep_list保存部門表的全部記錄,再通過render函式發送給list_dep_old.html,render有三個引數,第一個request是固定的,第二個是html檔案,第三個是字典型別,這個引數傳值給html檔案,在網頁中以模板變數形式放置在相應的位置,

下面是list_dep_old.html檔案的代碼,存放在templates/list_dep_old檔案夾中,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>部門串列</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div align="center">
    <h1>部門串列</h1>
    <hr>
    <div><a href="https://www.cnblogs.com/test_orm_old/add_dep_old/">增加一條記錄</a></div>
    <table border="1">
        <thead>
            <tr>
                <td>部門名稱</td>
                <td>備注說明</td>
                <td colspan="2">操作</td>
            </tr>
        </thead>
        <tbody>
        {% for dep in dep_list %}
        <tr>
            <td>{{ dep.dep_name }}</td>
            <td>{{ dep.dep_script }}</td>
            <td><a href="https://www.cnblogs.com/test_orm_old/del_dep_old/{{ dep.id }}/">洗掉</a></td>
            <td><a href="https://www.cnblogs.com/test_orm_old/edit_dep_old/{{ dep.id }}">修改</a></td>
        </tr>
            {% empty %}
            <tr>
                <td colspan="4">無相關記錄!</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>
</body>
</html>

說明:

  • 視圖函式傳入的變數dep_list是一個QuertSet物件,它是一個資料集,實際包含資料表中一行一行的記錄,所以在HTML檔案中用{% for dep in dep_list %}取出每一行記錄存在dep中,然后通過{{ dep.欄位名 }}取出每個欄位的值,

    {% for dep in dep_list %}......{% empty %}是模板標簽,是一個回圈陳述句代碼塊,

  • <td><a href="https://www.cnblogs.com/test_orm_old/del_dep_old/{{ dep.id }}/">洗掉</a></td>中的{{ dep.id }}獲取department資料表的id值,/test_orm_old/與一級URL組態檔/test_orm/test_orm/urls.py中path('test_orm_old/', include('employee.urls'))配置項有關,它匹配path函式的第一個引數;del_dep_old/{{ dep.id }}/與二級URL組態檔/test_orm/employee/urls.py中path('del_dep_old/<int:dep_id>/',del_dep_old)配置項有關,它匹配path函式第一個引數,可以理解為單擊這個a標簽,django會用views中的del_dep_old視圖函式,這個函式由path函式第二個引數指定,

總結:實作以上功能需要在urls、views中撰寫代碼,還需建立一個HTML檔案:

  • 在一級組態檔的urls中加入path('test_orm_old/', include('employee.urls'))配置項,
  • 在二級組態檔的urls中加入path('list_dep_old/',list_dep_old)配置項,
  • 在views中建立視圖函式def list_dep_old(request),撰寫邏輯代碼,
  • 在templates/list_dep_old檔案夾下建立list_dep_old.html,

開啟django,地址欄輸入http://127.0.0.1:8000/test_orm_old/list_dep_old/

增加部門視圖函式add_dep_old()的代碼如下:

def add_dep_old(request):
    # 判斷請求方式,如果是post,說明前端頁面要提交資料
    if request.method == 'POST':
        dep_name = request.POST.get('dep_name')
        dep_script = request.POST.get('dep_script')
        if dep_name.strip() == '':
            return render(request, 'test_orm_old/add_dep_old.html', {'error_info':'部門名稱不能為空'})
        try:
            # 用create函式新建一條記錄,這條記錄會自動保存,不用呼叫save函式
            p = department.objects.create(dep_name=dep_name,dep_script=dep_script)
            return redirect('/test_orm_old/list_dep_old/')
        except Exception as e:
            return render(request,'test_orm_old/add_dep_old.html',{'error_info':'輸入部門名稱重復或資訊有誤'})
        finally:
            pass
    return render(request,'test_orm_old/add_dep_old.html')

說明:

提交資料一般用POST,通過request.POST.get取得HTML檔案中form的input標簽中的值,request.POST.get函式中的引數就是HTML檔案中input標簽的name屬性,

代碼把request.POST.get取得的值傳遞給django orm的create函式,生成一條資料記錄,代碼中p = department.objects.create(dep_name=dep_name,dep_script=dep_script)也可以用下面兩種方式代替:

# 一:
obj = department(dep_name=dep_name,dep_script=dep_script)
obj.save()
# 二:
dic = {"dep_name":dep_name,"deo_script":dep_script}
department.create(**dic)

在生成新的記錄之后,通過return redirect('/test_orm_old/list_dep_old/')重定向到部門串列頁面;redirect函式的引數是一個字串,匹配的是URL配置項,不是HTML檔案名,即views的list_deo_old視圖函式,

add_dep_old.html檔案:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增加部門</title>
</head>
<body>
<div align="center">
    <h1>增加部門</h1>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <input type="hidden" name="id" id="id" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ department.id }}" >
        <div>
            <label>部門:</label>
              <input type="text" name="dep_name" id="dep_name" >
        </div>
        <br>
        <div>
            <label>備注:</label>
              <input type="text" name="dep_script" id="dep_script" >
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/保存"></div>
    </form>
    {{ error_info }}
</div>
</body>
</html>

說明:

form標簽中的每個input標簽中的輸入的值會隨著POST請求傳給視圖函式,視圖函式通過request.POST.get('xxx')取得輸入的值,xxx是input標簽name的值,

{% csrf_token %}是為了防止CSRF所做的保護,是一種安全機制,

下面是洗掉部門記錄的視圖函式,根據傳入引數,獲取id欄位等于引數值的記錄物件,然后洗掉這個物件,視圖函式del_dep_old的第二個引數是在urls檔案配置項的path函式中定義的,而path('del_dep_old/<int:dep_id>/', del_dep_old)中的int指明資料型別,dep_id指明視圖函式del_dep_old()第二個引數的名稱,引數值來自部門串列檔案list_dep_old.html中的{{ dep.id }},

def del_dep_old(request,dep_id):
    dep_object = department.objects.get(id=dep_id)
    dep_object.delete()
    return redirect('/test_orm_old/list_dep_old/')

視圖函式edit_dep_old()實作修改功能,首先判斷請求方式是不是POST,是則通過dep_object=department.objects.get(id=id)取出資料表記錄,然后給每一個欄位賦值,這些值是POST請求傳遞過來的,如果不是POST請求就推斷是第一次請求頁面,首先根據引數dep_id(來自部門串列檔案list_dep_old.html中的{{ dep.id }}取出記錄放到變數dep_object中,通過render函式傳遞到edit_dep_old.html檔案中,代碼如下:

def edit_dep_old(request, dep_id):
    if request.method == 'POST':
        id = request.POST.get('id')
        # 獲取前端頁面提交的資料
        dep_name = request.POST.get('dep_name')
        dep_script = request.POST.get('dep_script')
        dep_object = department.objects.get(id=id)
        # 給欄位賦值
        dep_object.dep_name = dep_name
        dep_object.dep_script = dep_script
        # 保存資料到資料表
        dep_object.save()
        return redirect('/test_orm_old/list_dep_old/')
    else:
        dep_object = department.objects.get(id=dep_id)
        return render(request,'test_orm_old/edit_dep_old.html',{'department':dep_object})

視圖函式edit_dep_old通過render(request,'test_orm_old/edit_dep_old.html',{'department':dep_object})傳遞引數給edit_dep_old.html檔案,這個檔案部分代碼如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改部門</title>
</head>
<body>
<div align="center">
    <h1>修改部門</h1>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <input type="hidden" name="id" id="id" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ department.id }}" >
        <div>
            <label>部門:</label>
              <input type="text" name="dep_name" id="dep_name" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ department.dep_name }}">
        </div>
        <br>
        <div>
            <label>備注:</label>
              <input type="text" name="dep_script" id="dep_script" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ department.dep_script }}">
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/保存"></div>


    </form>
    {{ error_info }}
</div>
</body>
</html>

說明:

  • 以上代碼與add_dep_old.html相似,只是在input標簽中給value屬性進行了賦值,
  • 隱含的input標簽用于保存資料庫表記錄主鍵id的值,并提供給視圖函式修改記錄,

以上是部門資料表增刪查改功能的實作,總結如下:

  • 在urls中建立URL與視圖函式的一一對應關系,
  • 在views中建立函式,實作業務邏輯,傳遞變數給HTML,
  • 在HTML檔案設計網頁結構,接收視圖函式傳遞變數,通過模板語言進行渲染,形成用戶需要的頁面,

group團體資料庫表的增刪改查視圖函式代碼如下:

#團隊增刪改查
def list_group_old(request):
    group_list=group.objects.all()
    return render(request,'test_orm_old/list_group_old.html',{'group_list':group_list})

def add_group_old(request):
    if request.method=='POST':
        group_name=request.POST.get('group_name')
        group_script = request.POST.get('group_script')
        if group_name.strip()=='':
            return render(request, 'test_orm_old/add_group.html', {'error_info': '團隊名稱不能為空!'})
        try:
            group.objects.create(group_name=group_name,group_script=group_script)
            return redirect('/test_orm_old/list_group_old/')
        except Exception as e:
            return render(request, 'test_orm_old/add_group_old.html',{'error_info':'錄入團隊名稱重復或資訊有錯誤!'})
        finally:
            pass
    return render(request, 'test_orm_old/add_group_old.html')

def del_group_old(request,group_id):
    group_object=group.objects.get(id=group_id)
    group_object.delete()
    return redirect('/test_orm_old/list_group_old/')

def edit_group_old(request,group_id):
    if request.method=='POST':
        id=request.POST.get('id')
        group_name=request.POST.get('group_name')
        group_script=request.POST.get('group_script')
        group_object=group.objects.get(id=id)
        group_object.group_name=group_name
        group_object.group_script=group_script
        group_object.save()
        return redirect('/test_orm_old/list_group_old/')
    else:
        group_object=group.objects.get(id=group_id)
        return render(request,'test_orm_old/edit_group_old.html',{'group':group_object})

以下是list_group_old.html代碼:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>團隊串列</title>
</head>
<body>

<div align="center">
    <h1>團隊串列</h1>
    <hr>
    <div><a href="https://www.cnblogs.com/test_orm_old/add_group_old/">增加一條記錄</a></div>
    <table border="1">
        <thead>
        <tr>
            <td>團隊名稱</td>
            <td>備注說明</td>
            <td colspan="2">操作</td>
        </tr>
        </thead>
        <tbody>
        {% for group in group_list %}
        <tr>
            <td>{{ group.group_name }}</td>
            <td>{{ group.group_script }}</td>
            <td><a href="https://www.cnblogs.com/test_orm_old/del_group_old/{{ group.id }}/">洗掉</a></td>
            <td><a href="https://www.cnblogs.com/test_orm_old/edit_group_old/{{ group.id }}/">修改</a></td>
        </tr>
        {% empty %}
           <tr>
            <td colspan="4">無相關記錄!</td>

        </tr>
        {% endfor %}
        </tbody>
    </table>

</div>
</body>
</html>

以下是add_group_old.html代碼:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增加團隊</title>
</head>
<body>
<div align="center">
    <h1>增加團隊</h1>
    <hr>
    <form action="/test_orm_old/add_group_old/" method="post">
        {% csrf_token %}
        <div>
            <label>團隊:</label>
              <input type="text" name="group_name" id="group_name">
        </div>
        <br>
        <div>
            <label>備注:</label>
              <input type="text" name="group_script" id="group_script">
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/增加"></div>


    </form>
   <div style="color:red;">{{ error_info }}</div>
</div>
</body>
</html>

以下是edit_group_old.html代碼:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改團隊</title>
</head>
<body>
<div align="center">
    <h1>修改團隊</h1>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <input type="hidden" name="id" id="id" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ group.id }}" >
        <div>
            <label>團隊:</label>
              <input type="text" name="group_name" id="group_name" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ group.group_name }}">
        </div>
        <br>
        <div>
            <label>備注:</label>
              <input type="text" name="group_script" id="group_script" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ group.group_script }}">
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/保存"></div>


    </form>
    {{ error_info }}
</div>
</body>
</html>

employeeinfo員工補充資訊表的視圖函式代碼如下,employee和employeeinfo兩表有一對一關系,實際上相當于一個表分到了兩個地方,這樣的原因主要是表的欄位訪問頻率不同,因此把訪問頻率高的欄位放在一個表中,

#employeeinf增刪改查
def list_employeeinfo_old(request):#員工補充資訊串列
    info_list=employeeinfo.objects.all()
    return render(request,'test_orm_old/list_employeeinfo_old.html',{'info_list':info_list})
def add_employeeinfo_old(request):#增加一條員工補充資訊記錄
    if request.method=='POST':
        phone=request.POST.get('phone')
        address = request.POST.get('address')
        if phone.strip()=='':
            return render(request, 'test_orm_old/add_employeeinfo_old.html', {'error_info': '電話不能為空!'})
        try:
            employeeinfo.objects.create(phone=phone,address=address)
            return redirect('/test_orm_old/list_employeeinfo_old/')
        except Exception as e:
            return render(request, 'test_orm_old/add_employeeinfo_old.html',{'error_info':'資訊有錯誤!'})
        finally:
            pass
    return render(request, 'test_orm_old/add_employeeinfo_old.html')

def del_employeeinfo_old(request,info_id):#洗掉一條員工補充資訊記錄
    info_object=employeeinfo.objects.get(id=info_id)
    info_object.delete()
    return redirect('/test_orm_old/list_employeeinfo_old/')

def edit_employeeinfo_old(request,info_id):#修改一條員工補充資訊記錄
    if request.method=='POST':
        id=request.POST.get('id')
        phone = request.POST.get('phone')
        address = request.POST.get('address')
        info_object=employeeinfo.objects.get(id=id)
        info_object.phone=phone
        info_object.address=address
        info_object.save()
        return redirect('/test_orm_old/list_employeeinfo_old/')
    else:
        info_object=employeeinfo.objects.get(id=info_id)
        return render(request,'test_orm_old/edit_employeeinfo_old.html',{'info':info_object})

以下是list_employeeinfo_old.html代碼:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h1>人員地址電話串列</h1>
    <hr>
    <div><a href="https://www.cnblogs.com/test_orm_old/add_employeeinfo_old/">增加一條記錄</a></div>
    <table border="1">
        <thead>
        <tr>
            <td>電話</td>
            <td>地址</td>
            <td colspan="2">操作</td>
        </tr>
        </thead>
        <tbody>
        {% for info in info_list %}
        <tr>
            <td>{{ info.phone }}</td>
            <td>{{ info.address }}</td>
            <td><a href="https://www.cnblogs.com/test_orm_old/del_employeeinfo_old/{{ info.id }}/">洗掉</a></td>
            <td><a href="https://www.cnblogs.com/test_orm_old/edit_employeeinfo_old/{{ info.id }}/">修改</a></td>
        </tr>
        {% empty %}
           <tr>
            <td colspan="4">無相關記錄!</td>

        </tr>
        {% endfor %}
        </tbody>
    </table>

</div>
</body>
</html>

以下是add_employeeinfo_old.html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h1>增加用戶電話地址</h1>
    <hr>
    <form action="/test_orm_old/add_employeeinfo_old/" method="post">
        {% csrf_token %}
        <div>
            <label>電話號碼:</label>
              <input type="text" name="phone" id="phone">
        </div>
        <br>
        <div>
            <label>家庭住址:</label>
              <input type="text" name="address" id="address">
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/增加"></div>


    </form>
   <div style="color:red;">{{ error_info }}</div>
</div>
</body>
</body>
</html>

以下是edit_employeeinfo_old.html代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h1>修改電話地址</h1>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <input type="hidden" name="id" id="id" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ info.id }}" >
        <div>
            <label>電話:</label>
              <input type="text" name="phone" id="phone" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ info.phone }}">
        </div>
        <br>
        <div>
            <label>地址:</label>
              <input type="text" name="address" id="address" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ info.address }}">
        </div>
        <br>

        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/保存"></div>


    </form>
    {{ error_info }}
</div>
</body> 
</html>
employee資料模型的操作

employee資料模型中有外鍵、多對多鍵、一對一鍵,對它的資料操作有個別不同之處,以下是員工資料表的洗掉操作的視圖函式:

def list_employee_old(request):
    emp=employee.objects.all()
    return render(request,'test_orm_old/list_employee_old.html',{'emp_list':emp})
def delete_employee_old(request,emp_id):
    emp=employee.objects.get(id=emp_id)
    emp.delete()
    return redirect('/test_orm_old/list_employee_old')

list_employee_old.html檔案如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>員工串列</title>
</head>
<body>
<div align="center">
    <h1>員工串列</h1>
    <hr>
    <div><a href="https://www.cnblogs.com/test_orm_old/add_employee_old/">增加一條記錄</a></div>
    <table border="1">
        <thead>
        <tr>
            <td>姓名</td>
            <td>郵件</td>
            <td>薪水</td>
            <td>地址</td>
            <td>部門</td>
            <td>團隊</td>

            <td colspan="2">操作</td>
        </tr>
        </thead>
        <tbody>
        {% for emp in emp_list %}
        <tr>
            <td>{{ emp.name }}</td>
            <td>{{ emp.email }}</td>
             <td>{{ emp.salary }}</td>
            <td>{{ emp.info.address }}</td>
            <td>{{ emp.dep.dep_name }}</td>
            <td>
                {% for gp in emp.group.all %}
                {% if forloop.last %}
                 {{ gp.group_name }}
                {% else %}
                {{ gp.group_name }},
                {% endif %}
                {% endfor %}
            </td>
            <td><a href="https://www.cnblogs.com/test_orm_old/del_employee_old/{{ emp.id }}/">洗掉</a></td>
            <td><a href="https://www.cnblogs.com/test_orm_old/edit_employee_old/{{ emp.id }}/">修改</a></td>
        </tr>
        {% empty %}
           <tr>
            <td colspan="7">無相關記錄!</td>

        </tr>
        {% endfor %}
        </tbody>
    </table>

</div>
</body>
</html>

說明:

  1. emp_list是視圖函式傳過來的變數,是一個Django QuerySet物件集,用{% for emp in emp_list %}取出每一個物件放到emp中,這樣emp物件稱為employee資料模型的實體化物件,外鍵dep、多對多鍵group、一對一鍵info這些關聯關系也包含在emp物件中,因為Django ORM會自動把關聯關系也放在Query Set物件中,
  2. 在模板語法{{ emp.dep }}中可通過dep這個外鍵取得與它關聯的department資料表中的一條記錄,{{ emp.dep.dep_name }}可取得department資料表中關聯的dep_name欄位的值,
  3. 同理{{ emp.group }}通過group這個多對多鍵可取得group資料表中的相關聯的紀錄,由于是多對多關系,這些關聯的紀錄不止一條,所以要用{% for gp in emp.group.all %}把記錄一條條取出來放在gp中,這樣{{ gp.group_name }}就可顯示團體名稱了,
  4. <a href='https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/test_orm_old/del_employee_old/{{ emp.id }}/'>洗掉</a>中的del_employee_old/{{ emp.id }}/匹配urls檔案的配置項path('del_employee_old/<int:emp_id>/',delete_employee_old)陳述句中path函式的第一個引數,

增加員工記錄視圖函式的代碼:

def add_employee_old(request):
    if request.method=="POST":
        name=request.POST.get("name")
        email=request.POST.get("email")
        dep=request.POST.get("dep")
        info = request.POST.get("info")
        salary = request.POST.get("salary")
        groups=request.POST.getlist("group")
        new_emp=employee.objects.create(name=name,email=email,salary=salary,dep_id=dep,info_id=info)
        new_emp.group.set(groups)
        return redirect('/test_orm_old/list_employee_old/')
    dep_list=department.objects.all()
    group_list=group.objects.all()
    info_list = employeeinfo.objects.all()

    return render(request,'test_orm_old/add_employee_old.html',{'dep_list':dep_list,'group_list':group_list,'info_list':info_list})

說明:

  1. employee資料庫表有個多對多鍵group,要用getlist()取值,
  2. 外鍵在資料表中產生的欄位名為外鍵名_id,因此在new_emp=employee.objects.create(name=name,email=email,salary=salary,dep_id=dep,info_id=info)陳述句中可以直接把變數值賦給dep_id和info_id,
  3. 多對多鍵group涉及多個值,因此在生成一條記錄new_emp后要通過new_emp.group.set(groups)進行賦值,
  4. 如果是第一次打開網頁需要將dep_list、group_list、info_list變數傳遞給HTML檔案,通過render傳到網頁,通過語言模板放到select標簽供用戶使用,

add_employee_old.html如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h1>增加員工</h1>
    <hr>
    <form action="/test_orm_old/add_employee_old/" method="post">
        {% csrf_token %}
        <div>
            <label>姓名:</label>
              <input type="text" name="name" id="name">
        </div>
        <br>
        <div>
            <label>郵箱:</label>
              <input type="text" name="email" id="email">
        </div>
        <br>
         <div>
            <label>工資:</label>
              <input type="text" name="salary" id="salary">
        </div>
        <br>
        <div>
            <label>電話地址:</label>
            <select name="info" id="info">
                {% for info in info_list %}
                <option value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ info.id}}"> {{ info.phone }}||{{ info.address }}</option>
                {% endfor %}
            </select>
             
        </div>
        <br>
        <div>
            <label>部門:</label>
            <select name="dep" id="dep">
                {% for dep in dep_list %}
                <option value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ dep.id}}"> {{ dep.dep_name }}</option>
                {% endfor %}
            </select>
             
        </div>
        <br>
        <div>
            <label>團體:</label>
            <select name="group" id="group"   multiple="true" >
                  {% for group  in group_list %}
                <option value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ group.id}}"> {{ group.group_name }}</option>
                {% endfor %}
            </select>
             
        </div>
        <br>
        <div><input type="submit" value="https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/增加"></div>


    </form>
</div>
</body>
</html>

edit_employee_old函式代碼如下:

def edit_employee_old(request,emp_id):
    if request.method=="POST":
        id=request.POST.get('id')
        name=request.POST.get("name")
        email=request.POST.get("email")
        dep=request.POST.get("dep")
        info=request.POST.get("info")
        groups=request.POST.getlist("group")
        emp=employee.objects.get(id=id)
        emp.name=name
        emp.email=email
        emp.dep_id=dep
        emp.info_id=info
        emp.group.set(groups)
        emp.save()

        return redirect('/test_orm_old/list_employee_old/')
    emp=employee.objects.get(id=emp_id)
    dep_list = department.objects.all()
    group_list = group.objects.all()
    info_list = employeeinfo.objects.all()
    return render(request, 'test_orm_old/edit_employee_old.html',{'emp':emp,'dep_list':dep_list,'group_list':group_list,'info_list':info_list})

edit_employee_old.html如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h1>修改員工資訊</h1>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <input type="hidden" name='id' id='id' value=https://www.cnblogs.com/zzdshidashuaige/archive/2021/06/28/{{ emp.id }}>