1. 程式人生 > >django-模型層(model)-多表相關操作(圖書管理練習)

django-模型層(model)-多表相關操作(圖書管理練習)

brush height cit query == es2017 blank res name

66、django之模型層(model)--多表相關操作(圖書管理小練習)

前面幾篇隨筆的數據庫增刪改查操作都是在單表的操作上的,然而現實中不可能都是單表操作,更多的是多表操作,一對一,一對多,多對多的表結構才是我們經常需要處理的,本篇將帶我們了解多表操作的一些相關操作。也會帶著大家做一個簡單的圖書管理的小練習。

本篇導航:

  • 建表
  • template模版的設計
  • 添加表記錄
  • 查詢表記錄
  • 修改表記錄
  • 刪除表記錄
  • 圖書管理小練習(只貼上圖書的增刪改查代碼)

一、建表

本篇繼續以圖書管理的例子。

模型:書籍有書名、作者、出版日期、價格,出版社,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關系就是多對多的關聯關系(many-to-many);一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關系(one-to-many)。

1、準備工作

1)創建一個項目

2)提前在mysql數據庫裏建立一個庫

3)修改相關setting配置。(詳情可以參考前面63、64、65三篇隨筆)

2、建表

你如果在建表時沒有添加主鍵,django會自動給我們的表添加一個主鍵id,是不是很棒0.0

1)語法

技術分享
一對一:
models.OneToOneField() ===>models.ForeignKey(,unique="True")
一對多:
models.ForeignKey()
多對多:
models.ManyToManyField()

屬性:
related_name=""    
可選屬性用來給此次關聯起名,如果不用此屬性django會自動給一個名字後面查詢的例子會說明(是關聯的名字不是字段名)
技術分享

2)建表實例

技術分享 圖書、出版社、作者

這個圖書的小練習中的表沒有一對一關聯用法用其他兩個關聯基本相同

3、註意

1)主鍵id 字段是自動添加的

2)對於外鍵字段,Django 會在字段名上添加"_id" 來創建數據庫中的列名

3)外鍵字段 ForeignKey 有一個 null=True 的設置(它允許外鍵接受空值 NULL),你可以賦給它空值 None 。

4)在表與表的連接中有related_name屬性可以起名用於反向查詢,當然不寫有默認(表名_set),一對一關聯可以直接用表名


二、template模版的設計

此次的小練習template是用Bootstrap框架搭建的,因為我們本篇主講的django模版層所以會貼出代碼逮捕做分析,對前端有問題的可以看以前相關隨筆哦。

相關隨筆推薦:

Bootstrap使用:http://www.cnblogs.com/liluning/p/7643879.html

靜態文件在模版中的使用:http://www.cnblogs.com/liluning/p/7724699.html

Bootstrap官網:http://v3.bootcss.com/

模版使用:http://v3.bootcss.com/examples/dashboard/


三、添加表記錄

1、一對多添加語法

方式1:
   publish_obj=Publish.objects.get(nid=1)
   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",publish=publish_obj)
 
方式2:
   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",publish_id=1)

推薦使用第一種方式 第二種方式在你知道外鍵publish_id確切的值時可以使用

2、多對多添加語法

技術分享
book_obj=Book.objects.create(title="追風箏的人",publishDate="2012-11-12",prince=69,publish_id=1)
 
author_yuan=Author.objects.create(name="yuan",age=23...)
author_egon=Author.objects.create(name="egon",age=32...)
 
book_obj.authorlish.add(author_egon,author_yuan)    #  將某個特定的 model 對象添加到被關聯對象集合中。   =======    book_obj.authors.add(*[])
 
book_obj.authorlish.create()      #創建並保存一個新對象,然後將這個對象加被關聯對象的集合中,然後返回這個新對象。
技術分享

當然我們綁定的關聯也可以解除:

book_obj.authorlish.remove()     # 將某個特定的對象從被關聯對象集合中去除。    ======   book_obj.authors.remove(*[])
book_obj.authorlish.clear()       #清空被關聯對象集合。

3、一對多添加和多對多添加實例

技術分享 View Code

一對一因為沒用用到不做演示 用法與其他兩個關聯相同

4、相關方法演示(例子選自官網)

1)add

把指定的模型對象添加到關聯對象集中。

b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.add(e)

2)create

創建一個新的對象,保存對象,並將它添加到關聯對象集之中。返回新創建的對象。

b = Blog.objects.get(id=1)
e = b.entry_set.create(
    headline=Hello,
    body_text=Hi,
    pub_date=datetime.date(2005, 1, 1)
)

3)remove

從關聯對象集中移除執行的模型對象

b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.remove(e)

4)clear

從關聯對象集中移除一切對象。

b = Blog.objects.get(id=1)
b.entry_set.clear()

四、查詢表記錄

查詢相關API前面的隨筆已經寫到 單表查詢還有雙下劃線查詢0.0

1、雙下劃線單表查詢

技術分享
models.book.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
 
models.book.objects.filter(id__in=[11, 22, 33])   # 獲取id等於11、22、33的數據
models.book.objects.exclude(id__in=[11, 22, 33])  # not in
 
models.book.objects.filter(name__contains="ven")  #模糊匹配
models.book.objects.filter(name__icontains="ven") # icontains大小寫不敏感
 
models.book.objects.filter(id__range=[1, 2])      # 範圍bettwen and
 
startswith,istartswith, endswith, iendswith 
技術分享

2、基於對象的跨表查詢

1)一對多查詢

正向查詢

# 查詢id=1的書籍的出版社所在的城市
book_obj=Book.objects.get(id=1)
print(book_obj.publish.city) 
# book_obj.publish 是id=1的書籍對象關聯的出版社對象

反向查詢

# 查詢 人民出版社出版過的所有書籍
 
publish=Publish.objects.get(name="人民出版社")
book_list=publish.book_set.all()  # 與人民出版社關聯的所有書籍對象集合
for book_obj in book_list:
    print(book_obj.title)

2)多對多查詢

正向查詢

技術分享
# 金瓶眉所有作者的名字
 
book_obj=Book.objects.filter(title="金瓶眉").first()
authors=book_obj.authorlish.all()
 
for author_obj in authors:
    print(author_obj.name)
技術分享

反向查詢

# 查詢egon出過的所有書籍的名字
author_obj=Author.objects.get(name="egon")
book_list=author_obj.book_set.all() #與egon作者相關的所有書籍
 
for book_obj in book_list:
    print(book_obj.title)

3、查詢實例

1)views

技術分享 View Code

2)template——index.html

技術分享 View Code

4、基於雙下劃線的跨表查詢

Django 還提供了一種直觀而高效的方式在查詢中表示關聯關系那就是強大的雙劃線

技術分享
# 練習1:  查詢人民出版社出版過的所有書籍的名字與價格(一對多)
    # 正向查詢 按字段:publish
    queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","price")

    # 反向查詢 按表名:book
    queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__price")

# 練習2: 查詢egon出過的所有書籍的名字(多對多)
    # 正向查詢 按字段:authors:
    queryResult=Book.objects.filter(authors__name="yuan").values_list("title")

    # 反向查詢 按表名:book
    queryResult=Author.objects.filter(name="egon").values_list("book__title","book__price")


# 練習3: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名
    # 正向查詢
    queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
    # 反向查詢
    queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")


# 練習4: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱
queryResult=Book.objects.filter(authors__authorDetail__telephone__regex="151").values_list("title","publish__name")
技術分享

練習四需要在本建表實例上添加一個authorDetail作者詳細信息表將電話號等詳細信息放進去與作者表建立一對一關聯

5、聚合查詢與分組查詢

1)聚合:aggregate()

# 計算所有圖書的平均價格
from django.db.models import Avg
Book.objects.all().aggregate(Avg(price))
#{‘price__avg‘: 34.35}

需要使用什麽函數都要通過import導入 例如常用函數:Avg,Sum,Count,Max,Min

字典的key默認(字段名__函數名)也可以自己起名字average_price

Book.objects.aggregate(average_price=Avg(price‘))

一次也查詢多個可以

Book.objects.aggregate(Avg(price‘), Max(price‘), Min(price‘))

2)分組:annotate() 

#統計每一本書的作者個數
bookList=Book.objects.annotate(authorsNum=Count(authors))
for book_obj in bookList:
    print(book_obj.title,book_obj.authorsNum)

annotate的返回值是querySet

3)練習

技術分享 View Code

五、修改表記錄

修改和以前的一樣還是update比較簡單就不做詳細解釋了直接上實例

技術分享
def editbook(request,id) :
    # 點擊保存POST提交
    if request.method == "POST" :
        # 提取數據
        id = request.POST.get("id")
        title = request.POST.get("title")
        author_name = request.POST.getlist("author")
        publishDate = request.POST.get("publishDate")
        prince = request.POST.get("prince")
        publish_name = request.POST.get("publish")
        # 出版社object
        publish_obj = models.Publish.objects.get(name=publish_name)
        # 移除舊關聯
        book_obj = models.Book.objects.filter(id=id)[0]
        book_obj.authorlish.clear()
        

        # 更新圖書表
        models.Book.objects.filter(id=id).update(title=title, publishDate=publishDate, prince=prince,publish_id=publish_obj)


        book_obj = models.Book.objects.filter(id=id)[0]
        # 添加新關聯
        for i in author_name :
            print(i)
            obj = models.Author.objects.filter(name=i)[0]
            book_obj.authorlish.add(obj)
        return redirect("/index/")
技術分享

雖然修改比較簡單就一句update搞定,可是因為現在圖書表和作者表是多對多連接所以在更新圖書表時需要清楚之前的連鍵和建立新的連接,語法在之前都有講解在代碼中也都標記出來了。


六、刪除表記錄

實例:

def delbook(request,id) :
    # 刪除圖書
    models.Book.objects.filter(id=id).delete()
    return redirect("/index/")

在 Django 刪除對象時,會模仿 SQL 約束 ON DELETE CASCADE 的行為,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。


七、圖書管理小練習(只貼上圖書的增刪改查代碼)

1、model 建表

技術分享 View Code

2、template 模版

技術分享 index.html 技術分享 addbook.html 技術分享 editbook.html 技術分享 searchbook.html

3、url 分發

技術分享 View Code

4、views 視圖函數

技術分享 View Code

5、部分效果圖

1)首頁

技術分享

2)添加圖書

技術分享

3)修改圖書信息

技術分享

4)搜索框搜索圖書

技術分享

django-模型層(model)-多表相關操作(圖書管理練習)