1. 程式人生 > >多表操作——增刪改查

多表操作——增刪改查

關聯欄位與外來鍵約束沒有必然的聯絡(建管理欄位是為了進行查詢,建約束是為了不出現髒資料)

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    # 閱讀數
    # reat_num=models.IntegerField(default=0)
# 評論數 # commit_num=models.IntegerField(default=0) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) authors=models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name
= models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday
= models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField()
View Code
  • 對於外來鍵欄位,Django 會在欄位名上新增"_id" 來建立資料庫中的列名
  • 外來鍵欄位 ForeignKey 有一個 null=True 的設定(它允許外來鍵接受空值 NULL),你可以賦給它空值 None 。

  • 新增表記錄


        # -----一對多新增
        pub=Publish.objects.create(name='egon出版社',email='[email protected]',city='山東')
        print(pub)
    
        # 為book表繫結和publish的關係
        import datetime,time
        now=datetime.datetime.now().__str__()
        now = datetime.datetime.now().strftime('%Y-%m-%d')
        print(type(now))
        print(now)
        # 日期型別必須是日期物件或者字串形式的2018-09-12(2018-9-12),其它形式不行
        Book.objects.create(name='海燕3',price=333.123,publish_date=now,publish_id=2)
        Book.objects.create(name='海3燕3',price=35.123,publish_date='2018/02/28',publish=pub)
        pub=Publish.objects.filter(nid=1).first()
        book=Book.objects.create(name='測試書籍',price=33,publish_date='2018-7-28',publish=pub)
        print(book.publish.name)
        # 查詢出版了紅樓夢這本書出版社的郵箱
        book=Book.objects.filter(name='紅樓夢').first()
        print(book.publish.email)
    一對多新增
      新增記錄
      # 當前生成的書籍物件
           book_obj=Book.objects.create(title="追風箏的  人",price=200,publishDate="2012-11-12",publish_id=1)
     # 為書籍繫結的做作者物件
           yuan=Author.objects.filter(name="yuan").first() # 在Author表中主鍵為2的紀錄
           egon=Author.objects.filter(name="alex").first() # 在Author表中主鍵為1的紀錄
    
    # 繫結多對多關係,即向關係表book_authors中新增紀錄
           book_obj.authors.add(yuan,egon)    #  將某些特定的 model 物件新增到被關聯物件集合中。   =======    book_obj.authors.add(*[])        
    
        book = Book.objects.filter(name='紅樓夢').first()
        egon=Author.objects.filter(name='egon').first()
        lqz=Author.objects.filter(name='lqz').first()
    
    # 1 沒有返回值,直接傳物件
        book.authors.add(lqz,egon)
        
    # 2 直接傳作者id
        book.authors.add(1,3)
        
    # 3 直接傳列表,會打散
        book.authors.add(*[1,2])
        
    # 解除多對多關係
        book = Book.objects.filter(name='紅樓夢').first()
        # 1 傳作者id
        book.authors.remove(1)
        # 2 傳作者物件
        egon = Author.objects.filter(name='egon').first()
        book.authors.remove(egon)
        
    #3 傳*列表
        book.authors.remove(*[1,2])
        
    #4 刪除所有
        book.authors.clear()
        
    # 5 拿到與 這本書關聯的所有作者,結果是queryset物件,作者列表
        ret=book.authors.all()
        # print(ret)
        
    # 6 queryset物件,又可以繼續點(查詢紅樓夢這本書所有作者的名字)
        ret=book.authors.all().values('name')
        print(ret)
        
    # 以上總結:
        # (1)
        # book=Book.objects.filter(name='紅樓夢').first()
        # print(book)
        # 在點publish的時候,其實就是拿著publish_id又去app01_publish這個表裡查資料了
        # print(book.publish)
        # (2)book.authors.all()

    多對多關係其它常用API:

    book_obj.authors.remove()      # 將某個特定的物件從被關聯物件集合中去除。    ======   book_obj.authors.remove(*[])
    book_obj.authors.clear()       #清空被關聯物件集合
    book_obj.authors.set()         #先清空再設定 

    查詢:

    • 不變的規則:
      • -正向查詢按欄位
        -反向查詢按表名小寫
  • (正向:關聯關係所在表————>查詢表)

  • (反向:查詢表---->關係關係所在表)

  • 基於物件的跨表查詢(多次查詢)
    一對一:
      -正向查詢按欄位
           -反向查詢按表名小寫
    一對多:
          -正向查詢按欄位(正向查詢一定會查出一個來)

           #基於name拿到物件再去關聯表author_detail中按欄位addr拿到欄位值
          -反向查詢按  表名  小寫 "_set ".all()(返回結果是queryset物件)

    多對多:
    -正向查詢按欄位.all()(正向查詢一定會查出多個來)
    -反向查詢按表名小寫_set.all()(返回結果是queryset物件)

    基於雙下劃線的跨表查詢 ps:"__"表示連表
    -在filter和values中都可以做連表操作(也就是都可以寫 __)

    關於效率:無論以誰做基表,沒有效率之分(本質都是在一個關係表(外來鍵約束)中查詢)

 

基於物件的跨表查詢

一對多查詢(publish與book):

正向查詢(按欄位:publish)

# 查詢主鍵為1的書籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主鍵為1的書籍物件關聯的出版社物件
print(book_obj.publish.city)

反向查詢(按表名:book_set)

publish=Publish.objects.get(name="蘋果出版社")
#publish.book_set.all() : 與蘋果出版社關聯的所有書籍物件集合
book_list=publish.book_set.all()    
for book_obj in book_list:
       print(book_obj.title)
   # 一對多正向查詢
    book=Book.objects.filter(name='紅樓夢').first()
    print(book.publish)#與這本書關聯的出版社物件
    print(book.publish.name)
    # 一對多反向查詢
    # 人民出版社出版過的書籍名稱
    pub=Publish.objects.filter(name='人民出版社').first()
    ret=pub.book_set.all()
    print(ret)
View Code

一對一查詢(Author 與 AuthorDetail):

正向查詢(按欄位:authorDetail):

egon=Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)

反向查詢(按表名:author):

# 查詢所有住址在北京的作者的姓名
 
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
     print(obj.author.name)
    # 一對一正向查詢
    # lqz的手機號
    lqz=Author.objects.filter(name='lqz').first()
    tel=lqz.author_detail.telephone
    print(tel)
    # 一對一反向查詢
    # 地址在北京的作者姓名
    author_detail=AuthorDatail.objects.filter(addr='北京').first()
    name=author_detail.author.name
    print(name)
View Code

多對多查詢 (Author 與 Book):

正向查詢(按欄位:authors):

# 眉所有作者的名字以及手機號
 
book_obj=Book.objects.filter(title="").first()
authors=book_obj.authors.all()
for author_obj in authors:
     print(author_obj.name,author_obj.authorDetail.telephone)

反向查詢(按表名:book_set):

# 查詢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)
    # 正向查詢----查詢紅樓夢所有作者名稱
    book=Book.objects.filter(name='紅樓夢').first()
    ret=book.authors.all()
    print(ret)
    for auth in ret:
        print(auth.name)
    # 反向查詢 查詢lqz這個作者寫的所有書
    author=Author.objects.filter(name='lqz').first()
    ret=author.book_set.all()
    print(ret)
View Code

注意:

你可以通過在 ForeignKey() 和ManyToManyField的定義中設定 related_name 的值來覆寫 FOO_set 的名稱。例如,如果 Article model 中做一下更改:

publish = ForeignKey(Book, related_name='bookList')

那麼接下來就會如我們看到這般:

# 查詢 人民出版社出版過的所有書籍
 
publish=Publish.objects.get(name="人民出版社")
book_list=publish.bookList.all()  # 與人民出版社關聯的所有書籍物件集合

基於雙下劃線的跨表查詢

一對多查詢:

# 練習:  查詢蘋果出版社出版過的所有書籍的名字與價格(一對多)

    # 正向查詢 按欄位:publish

    queryResult=Book.objects
            .filter(publish__name="蘋果出版社")
            .values_list("title","price")

    # 反向查詢 按表名:book

    queryResult=Publish.objects
              .filter(name="蘋果出版社")
              .values_list("book__title","book__price")
查詢的本質一樣,就是select from的表不一樣

 # 正向查詢按欄位,反向查詢按表名小寫
    # 查詢紅樓夢這本書出版社的名字
    # select * from app01_book inner join app01_publish
    # on app01_book.publish_id=app01_publish.nid
    ret=Book.objects.filter(name='紅樓夢').values('publish__name')
    print(ret)
    ret=Publish.objects.filter(book__name='紅樓夢').values('name')
    print(ret)
一對多
# 練習: 查詢alex出過的所有書籍的名字(多對多)

    # 正向查詢 按欄位:authors:
    queryResult=Book.objects
            .filter(authors__name="yuan")
            .values_list("title")

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

    # 正向查詢按欄位,反向查詢按表名小寫
    # 查詢紅樓夢這本書出版社的名字
    # select * from app01_book inner join app01_publish
    # on app01_book.publish_id=app01_publish.nid
    ret=Book.objects.filter(name='紅樓夢').values('publish__name')
    print(ret)
    ret=Publish.objects.filter(book__name='紅樓夢').values('name')
    print(ret)
    # sql 語句就是from的表不一樣
    # -------多對多正向查詢
    # 查詢紅樓夢所有的作者
    ret=Book.objects.filter(name='紅樓夢').values('authors__name')
    print(ret)
    # ---多對多反向查詢
    ret=Author.objects.filter(book__name='紅樓夢').values('name')
    ret=Author.objects.filter(book__name='紅樓夢').values('name','author_detail__addr')
    print(ret)
多對多查詢
# 練習: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名


    # 正向查詢
    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")


# 練習: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱


    # 方式1:
    queryResult=Book.objects
            .filter(authors__authorDetail__telephone__regex="151")
            .values_list("title","publish__name")
    # 方式2:    
    ret=Author.objects
              .filter(authordetail__telephone__startswith="151")
              .values("book__title","book__publish__name")
進階練習(連續跨表)  另外:https://www.cnblogs.com/liuqingzheng/articles/9499252.html