Django教程五

聚合查詢

  • 聚合查詢是指對(duì)一個(gè)數(shù)據(jù)表中的一個(gè)字段的數(shù)據(jù)進(jìn)行部分或全部進(jìn)行統(tǒng)計(jì)查詢,查bookstore_book數(shù)據(jù)表中的全部書(shū)的平均價(jià)格,查詢所有書(shū)的總個(gè)數(shù)等,都要使用聚合查詢
  1. 不帶分組聚合

    • 不帶分組的聚合查詢是指導(dǎo)將全部數(shù)據(jù)進(jìn)行集中統(tǒng)計(jì)查詢

    • 聚合函數(shù):

      • 定義模塊: django.db.models
      • 用法: from django.db.models import *
      • 聚合函數(shù):
        • Sum, Avg, Count, Max, Min
    • 語(yǔ)法:

      • MyModel.objects.aggregate(結(jié)果變量名=聚合函數(shù)('列'))
    • 返回結(jié)果:

      • 由 結(jié)果變量名和值組成的字典
      • 格式為:
        • {"結(jié)果變量名": 值}
    • 示例:

      # 得到所有書(shū)的平均價(jià)格
      from bookstore import models
      from django.db.models import Count
      result = models.Book.objects.aggregate(myAvg=Avg('price'))
      print("平均價(jià)格是:", result['myAvg'])
      print("result=", result)  # {"myAvg": 58.2}
      
      # 得到數(shù)據(jù)表里有多少本書(shū)
      from django.db.models import Count
      result = models.Book.objects.aggregate(mycnt=Count('title'))
      print("數(shù)據(jù)記錄總個(gè)數(shù)是:", result['mycnt'])
      print("result=", result)  # {"mycnt": 10}
      
      
  2. 分組聚合

    • 分組聚合是指通過(guò)計(jì)算查詢結(jié)果中每一個(gè)對(duì)象所關(guān)聯(lián)的對(duì)象集合砍聊,從而得出總計(jì)值(也可以是平均值或總和),即為查詢集的每一項(xiàng)生成聚合艾蓝。

    • 語(yǔ)法:

      • QuerySet.annotate(結(jié)果變量名=聚合函數(shù)('列'))
    • 用法步驟:

      1. 通過(guò)先用查詢結(jié)果MyModel.objects.value. 查找查詢要分組聚合的列

        • MyModel.objects.value('列1', '列2')

        • 如:

          pub_set = models.Book.objects.values('pub')
          print(books)  # <QuerySet [{'pub': '清華大學(xué)出版社'}, {'pub': '清華大學(xué)出版社'}, {'pub_hou {'pub': '機(jī)械工業(yè)出版社'}, {'pub': '清華大學(xué)出版社'}]>
          
          
      2. 通過(guò)返回結(jié)果的 QuerySet.annotate 方法分組聚合得到分組結(jié)果

        • QuerySet.annotate(名=聚合函數(shù)('列'))

        • 返回 QuerySet 結(jié)果集,內(nèi)部存儲(chǔ)結(jié)果的字典

        • 如:

          pub_count_set = pub_set.annotate(myCount=Count('pub'))
          print(pub_count_set)  # <QuerySet [{'pub': '清華大學(xué)出版社', 'myCount': 7}, {'pub': '機(jī)械工業(yè)出版社', 'myCount': 3}]>
          
          
      • .values('查詢列名')
    • 示例:

      • 得到哪兒個(gè)出版社共出版多少本書(shū)
      def test_annotate(request):
         - from django.db.models import Count
          from . import models
      
          # 得到所有出版社的查詢集合QuerySet
          pub_set = models.Book.objects.values('pub')
          # 根據(jù)出版社查詢分組摹量,出版社和Count的分組聚合查詢集合
          pub_count_set = pub_set.annotate(myCount=Count('pub'))  # 返回查詢集合
          for item in pub_count_set:
              print("出版社:", item['pub'], "圖書(shū)有:", item['myCount'])
          return HttpResponse('請(qǐng)查看服務(wù)器端控制臺(tái)獲取結(jié)果')
      
      

F對(duì)象

  • 一個(gè)F對(duì)象代表數(shù)據(jù)庫(kù)中某個(gè)字段的信息
  • F對(duì)象通常是對(duì)數(shù)據(jù)庫(kù)中的字段值在不加載到內(nèi)存中的情況下直接在數(shù)據(jù)庫(kù)服務(wù)器端進(jìn)行操作
  • F對(duì)象在 數(shù)據(jù)包 django.db.models 中.使用時(shí)需要通過(guò)如下語(yǔ)句進(jìn)行加載
    • from django.db.models import F
  1. 作用:

    • 用于類(lèi)屬性(字段)之間的比較。
    • 當(dāng)同時(shí)對(duì)數(shù)據(jù)庫(kù)中兩個(gè)字段的值進(jìn)行比較獲取 QuerySet 數(shù)據(jù)集時(shí)潮改,可以便用F對(duì)象
  2. 說(shuō)明:

    • 一個(gè) F() 對(duì)象代表了一個(gè)model的字段的值
  3. 使用它就可以直接參考model的field和執(zhí)行數(shù)據(jù)庫(kù)操作而不用再把它們(model field)查詢出來(lái)放到python內(nèi)存中誉尖。

  4. 語(yǔ)法:

    from django.db.models import F
    F('列名')
    
    
  5. 示例1

    • 更新Book實(shí)例中所有的零售價(jià)漲10元
    models.Book.objects.all().update(market_price=F('market_price')+10)
    # 以下做法好于如下代碼
    books = models.Book.objects.all()
    for book in books:
        book.update(market_price=book.marget_price+10)
        book.save()
    
    
  6. 示例2

    • 對(duì)數(shù)據(jù)庫(kù)中兩個(gè)字段的值進(jìn)行比較罪既,列出哪兒些書(shū)的零售價(jià)高于定價(jià)?
    from django.db.models import F
    from bookstore import models
    books = models.Book.objects.filter(market_price__gt=F('price'))
    for book in books:
        print(book.title, '定價(jià):', book.price, '現(xiàn)價(jià):', book.market_price)
    
    

Q對(duì)象 - Q()

  • 當(dāng)在獲取查詢結(jié)果集 使用復(fù)雜的邏輯或 | 、 邏輯非 ~ 等操作時(shí)可以借助于 Q對(duì)象進(jìn)行操作

  • 如: 想找出定價(jià)低于20元 或 清華大學(xué)出版社的全部書(shū)铡恕,可以寫(xiě)成

    models.Book.objects.filter(Q(price__lt=20)|Q(pub="清華大學(xué)出版社"))
    
    
  • Q對(duì)象在 數(shù)據(jù)包 django.db.models 中萝衩。需要先導(dǎo)入再使用

    • from django.db.models import Q
  1. 作用

    • 在條件中用來(lái)實(shí)現(xiàn)除 and(&) 以外的 or(|) 或 not(~) 操作
  2. 運(yùn)算符:

    • & 與操作
    • | 或操作
    • ? 非操作
  3. 語(yǔ)法

    from django.db.models import Q
    Q(條件1)|Q(條件2)  # 條件1成立或條件2成立
    Q(條件1)&Q(條件2)  # 條件1和條件2同時(shí)成立
    Q(條件1)&~Q(條件2)  # 條件1成立且條件2不成立
    ...
    
    
  4. 示例

    from django.db.models import Q
    # 查找清華大學(xué)出版社的書(shū)或價(jià)格低于50的書(shū)
    models.Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清華大學(xué)出版社'))
    # 查找不是機(jī)械工業(yè)出版社的書(shū)且價(jià)格低于50的書(shū)
    models.Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='機(jī)械工業(yè)出版社'))
    
    

原生的數(shù)據(jù)庫(kù)操作方法

使用MyModel.objects.raw()進(jìn)行 數(shù)據(jù)庫(kù)查詢操作查詢
  • 在django中,可以使用模型管理器的raw方法來(lái)執(zhí)行select語(yǔ)句進(jìn)行數(shù)據(jù)查詢
  1. 語(yǔ)法:

    • MyModel.objects.raw(sql語(yǔ)句)
  2. 用法

    • MyModel.objects.raw('sql語(yǔ)句')
  3. 返回值:

    • QuerySet 集合對(duì)象
  4. 示例

    books = models.Book.objects.raw('select * from bookstore_book')
    
    for book in books:
        print(book)
    
    
使用django中的游標(biāo)cursor對(duì)數(shù)據(jù)庫(kù)進(jìn)行 增刪改操作
  • 在Django中可以使用 如UPDATE,DELETE等SQL語(yǔ)句對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作没咙。

  • 在DJaogo中使用上述非查詢語(yǔ)句必須使用游標(biāo)進(jìn)行操作

  • 使用步驟:

    1. 導(dǎo)入cursor所在的包
      • Django中的游標(biāo)cursor定義在 django.db.connection包中猩谊,使用前需要先導(dǎo)入
      • 如:
        • from django.db import connection
    2. 用創(chuàng)建cursor類(lèi)的構(gòu)造函數(shù)創(chuàng)建cursor對(duì)象,再使用cursor對(duì)象,為保證在出現(xiàn)異常時(shí)能釋放cursor資源,通常使用with語(yǔ)句進(jìn)行創(chuàng)建操作
      • 如:

        from django.db import connection
        with connection.cursor() as cur:
            cur.execute('執(zhí)行SQL語(yǔ)句')
        
        
    • 示例

      # 用SQL語(yǔ)句將id 為 10的 書(shū)的出版社改為 "XXX出版社"
      from django.db import connection
      with connection.cursor() as cur: 
          cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;')
      
      with connection.cursor() as cur:
          # 刪除 id為1的一條記錄
          cur.execute('delete from bookstore_book where id=10;')
      
      

admin 后臺(tái)數(shù)據(jù)庫(kù)管理

  • django 提供了比較完善的后臺(tái)管理數(shù)據(jù)庫(kù)的接口祭刚,可供開(kāi)發(fā)過(guò)程中調(diào)用和測(cè)試使用
  • django 會(huì)搜集所有已注冊(cè)的模型類(lèi)牌捷,為這些模型類(lèi)提拱數(shù)據(jù)管理界面,供開(kāi)發(fā)者使用
  • 使用步驟:
    1. 創(chuàng)建后臺(tái)管理帳號(hào):

      • 后臺(tái)管理--創(chuàng)建管理員帳號(hào)

        • $ python3 manage.py createsuperuser
        • 根據(jù)提示完成注冊(cè),參考如下:
        $ python3 manage.py createsuperuser
        Username (leave blank to use 'tarena'): tarena  # 此處輸入用戶名
        Email address: weimz@tedu.cn  # 此處輸入郵箱
        Password: # 此處輸入密碼(密碼要復(fù)雜些涡驮,否則會(huì)提示密碼太簡(jiǎn)單)
        Password (again): # 再次輸入重復(fù)密碼
        Superuser created successfully.
        $ 
        
        
    2. 用注冊(cè)的帳號(hào)登陸后臺(tái)管理界面

自定義后臺(tái)管理數(shù)據(jù)表

  • 若要自己定義的模型類(lèi)也能在 /admin 后臺(tái)管理界中顯示和管理暗甥,需要將自己的類(lèi)注冊(cè)到后臺(tái)管理界面
  • 添加自己定義模型類(lèi)的后臺(tái)管理數(shù)據(jù)表的,需要用admin.site.register(自定義模型類(lèi)) 方法進(jìn)行注冊(cè)
    • 配置步驟如下:

      1. 在應(yīng)用app中的admin.py中導(dǎo)入注冊(cè)要管理的模型models類(lèi), 如:

        from . import models
        
        
      2. 調(diào)用 admin.site.register 方法進(jìn)行注冊(cè),如:

        from django.contrib import admin
        admin.site.register(自定義模型類(lèi))
        
        
    • 如: 在 bookstore/admin.py 添加如下代碼對(duì)Book類(lèi)進(jìn)行管理

    • 示例:

      # file: bookstore/admin.py
      from django.contrib import admin
      # Register your models here.
      
      from . import models
      ...
      admin.site.register(models.Book)  # 將Book類(lèi)注冊(cè)為可管理頁(yè)面
      
      

修改后臺(tái)Models的展現(xiàn)形式

  • 在admin后臺(tái)管理數(shù)據(jù)庫(kù)中對(duì)自定義的數(shù)據(jù)記錄都展示為 XXXX object 類(lèi)型的記錄,不便于閱讀和判斷

  • 在用戶自定義的模型類(lèi)中可以重寫(xiě) def __str__(self): 方法解決顯示問(wèn)題,如:

    • 在 自定義模型類(lèi)中重寫(xiě) str(self) 方法返回顯示文字內(nèi)容:
    class Book(models.Model):
        ...
        def __str__(self):
            return "書(shū)名" + self.title
    
    

模型管理器類(lèi)

  • 作用:

    • 為后臺(tái)管理界面添加便于操作的新功能捉捅。
  • 說(shuō)明:

    • 后臺(tái)管理器類(lèi)須繼承自 django.contrib.admin 里的 ModelAdmin 類(lèi)
  • 模型管理器的使用方法:

    1. <應(yīng)用app>/admin.py 里定義模型管理器類(lèi)

      class XXXX_Manager(admin.ModelAdmin):
          ......
      
      
    2. 注冊(cè)管理器與模型類(lèi)關(guān)聯(lián)

      from django.contrib import admin
      from . import models
      admin.site.register(models.YYYY, XXXX_Manager) # 注冊(cè)models.YYYY 模型類(lèi)與 管理器類(lèi) XXXX_Manager 關(guān)聯(lián)
      
      
    • 示例:

      # file : bookstore/admin.py
      from django.contrib import admin
      from . import models
      
      class BookAdmin(admin.ModelAdmin):
          list_display = ['id', 'title', 'price', 'market_price']
      
      admin.site.register(models.Book, BookAdmin)
      
      
  • 模型管理器類(lèi)ModelAdmin中實(shí)現(xiàn)的高級(jí)管理功能

    1. list_display 去控制哪些字段會(huì)顯示在Admin 的修改列表頁(yè)面中撤防。
    2. list_display_links 可以控制list_display中的字段是否應(yīng)該鏈接到對(duì)象的“更改”頁(yè)面。
    3. list_filter 設(shè)置激活A(yù)dmin 修改列表頁(yè)面右側(cè)欄中的過(guò)濾器
    4. search_fields 設(shè)置啟用Admin 更改列表頁(yè)面上的搜索框棒口。
    5. list_editable 設(shè)置為模型上的字段名稱(chēng)列表寄月,這將允許在更改列表頁(yè)面上進(jìn)行編輯。
    6. 其它參見(jiàn)https://docs.djangoproject.com/en/1.11/ref/contrib/admin/

數(shù)據(jù)庫(kù)表管理

  1. 修改模型類(lèi)字段的顯示名字

    • 模型類(lèi)各字段的第一個(gè)參數(shù)為 verbose_name,此字段顯示的名字會(huì)在后臺(tái)數(shù)據(jù)庫(kù)管理頁(yè)面顯示

    • 通過(guò) verbose_name 字段選項(xiàng),修改顯示名稱(chēng)示例如下:

      title = models.CharField(
          max_length = 30,
          verbose_name='顯示名稱(chēng)'
      )
      
      
  2. 通過(guò)Meta內(nèi)嵌類(lèi) 定義模型類(lèi)的屬性及展現(xiàn)形式

    • 模型類(lèi)可以通過(guò)定義內(nèi)部類(lèi)class Meta 來(lái)重新定義當(dāng)前模型類(lèi)和數(shù)據(jù)表的一些屬性信息

    • 用法格式如下:

      class Book(models.Model):
          title = CharField(....)
          class Meta:
              1. db_table = '數(shù)據(jù)表名'
                  - 該模型所用的數(shù)據(jù)表的名稱(chēng)无牵。(設(shè)置完成后需要立馬更新同步數(shù)據(jù)庫(kù))
              2. verbose_name = '單數(shù)名'
                  - 給模型對(duì)象的一個(gè)易于理解的名稱(chēng)(單數(shù)),用于顯示在/admin管理界面中
              3. verbose_name_plural = '復(fù)數(shù)名'
                  - 該對(duì)象復(fù)數(shù)形式的名稱(chēng)(復(fù)數(shù)),用于顯示在/admin管理界面中
      
      
    • 示例:

      class Meta:
          db_table = 'book_table'  # 將原數(shù)據(jù)表名"bookstore_book" 換為 "book_table",請(qǐng)查看數(shù)據(jù)表
          verbose_name = 'booooook'
          verbose_name_plural = 'booksssssss'  # 去127.0.0.1:8000/admin下看看哪兒變化了?
      
      
  • 練習(xí):
    • 將Book模型類(lèi) 和 Author 模型類(lèi)都加入后臺(tái)管理
    • 制作一個(gè)AuthorManager管理器類(lèi)漾肮,讓后臺(tái)管理Authors列表中顯示作者的ID、姓名茎毁、年齡信息
    • 用后臺(tái)管理程序 添加三條 Author 記錄
    • 修改其中一條記錄的年齡
    • 刪除最后一條添加的記錄
    • 將bookstore_author 數(shù)名表名稱(chēng)改為myauthor (需要重新遷移數(shù)據(jù)庫(kù))

數(shù)據(jù)表關(guān)聯(lián)關(guān)系映射 Relationship Map

  • 在關(guān)系型數(shù)據(jù)庫(kù)中克懊,通常不會(huì)把所有數(shù)據(jù)都放在同一張表中,這樣做會(huì)額外占用內(nèi)存空間,
  • 在關(guān)系列數(shù)據(jù)庫(kù)中通常用表關(guān)聯(lián)來(lái)解決數(shù)據(jù)庫(kù)谭溉。
  • 常用的表關(guān)聯(lián)方式有三種:
    1. 一對(duì)一映射
      • 如: 一個(gè)身份證對(duì)應(yīng)一個(gè)人
    2. 一對(duì)多映射
      • 如: 一個(gè)班級(jí)可以有多個(gè)學(xué)生
    3. 多對(duì)多映射
      • 如: 一個(gè)學(xué)生可以報(bào)多個(gè)課程墙懂,一個(gè)課程可以有多個(gè)學(xué)生學(xué)習(xí)

一對(duì)一映射

  • 一對(duì)一是表示現(xiàn)實(shí)事物間存在的一對(duì)一的對(duì)應(yīng)關(guān)系。
  • 如:一個(gè)家庭只有一個(gè)戶主扮念,一個(gè)男人有一個(gè)妻子垒在,一個(gè)人有一個(gè)唯一的指紋信息等
  1. 語(yǔ)法

    在關(guān)聯(lián)的兩個(gè)類(lèi)中的任何一個(gè)類(lèi)中:
    class A(model.Model):
        ...
    
    class B(model.Model):
        屬性 = models.OneToOneField(A)
    
    
  2. 用法示例

    1. 創(chuàng)建作家和作家妻子類(lèi)

      # file : xxxxxxxx/models.py
      from django.db import models
      
      class Author(models.Model):
          '''作家模型類(lèi)'''
          name = models.CharField('作家', max_length=50)
      
      class Wife(models.Model):
          '''作家妻子模型類(lèi)'''
          name = models.CharField("妻子", max_length=50)
          author = models.OneToOneField(Author)  # 增加一對(duì)一屬性
      
      
    2. 查詢

      • 在 Wife 對(duì)象中,通過(guò) author 屬性找到對(duì)應(yīng)的author對(duì)象
      • 在 Author 對(duì)象中,通過(guò) wife 屬性找到對(duì)應(yīng)的wife對(duì)象
    3. 創(chuàng)始一對(duì)一的數(shù)據(jù)記錄

      from . import models
      author1 = models.Author.objects.create(name='王老師')
      wife1 = models.Wife.objects.create(name='王夫人', author=author1)  # 關(guān)聯(lián)王老師
      author2 = models.Author.objects.create(name='小澤老師')  # 一對(duì)一可以沒(méi)有數(shù)據(jù)對(duì)應(yīng)的數(shù)據(jù) 
      
      
    4. 一對(duì)一數(shù)據(jù)的相互獲取

      1. 正向查詢

        • 直接通過(guò)關(guān)聯(lián)屬性查詢即可
        # 通過(guò) wife 找 author
        from . import models
        wife = models.Wife.objects.get(name='王夫人')
        print(wife.name, '的老公是', wife.author.name)
        
        
      2. 反向查詢

        • 通過(guò)反向引用屬性查詢
        • 反向引用屬性為實(shí)例對(duì)象.引用類(lèi)名(小寫(xiě)),如作家的反向引用為作家對(duì)象.wife
        • 當(dāng)反向引用不存在時(shí)扔亥,則會(huì)觸發(fā)異常
        # 通過(guò) author.wife 引用屬性 找 wife,如果沒(méi)有對(duì)應(yīng)的wife剛觸發(fā)異常
        author1 = models.Author.objects.get(name='王老師')
        print(author1.name, '的妻子是', author1.wife.name)
        author2 = models.Author.objects.get(name='小澤老師')
        try:
            print(author2.name, '的妻子是', author2.wife.name)
        except:
            print(author2.name, '還沒(méi)有妻子')
        
        
  • 作用:

    • 主要是解決常用數(shù)據(jù)不常用數(shù)據(jù)的存儲(chǔ)問(wèn)題,把經(jīng)常加載的一個(gè)數(shù)據(jù)放在主表中,不常用數(shù)據(jù)放在另一個(gè)副表中谈为,這樣在訪問(wèn)主表數(shù)據(jù)時(shí)不需要加載副表中的數(shù)據(jù)以提高訪問(wèn)速度提高效率和節(jié)省內(nèi)存空間,如經(jīng)常把書(shū)的內(nèi)容和書(shū)名建成兩張表旅挤,因?yàn)樵诰W(wǎng)站上經(jīng)常訪問(wèn)書(shū)名等信息,但不需要得到書(shū)的內(nèi)容伞鲫。
  • 練習(xí):

    1. 創(chuàng)建一個(gè)Wife模型類(lèi),屬性如下
      1. name
      2. age
    2. 在Wife類(lèi)中增加一對(duì)一關(guān)聯(lián)關(guān)系,引用 Author
    3. 同步回?cái)?shù)據(jù)庫(kù)并觀察結(jié)果

一對(duì)多映射

  • 一對(duì)多是表示現(xiàn)實(shí)事物間存在的一對(duì)多的對(duì)應(yīng)關(guān)系粘茄。
  • 如:一個(gè)學(xué)校有多個(gè)班級(jí),一個(gè)班級(jí)有多個(gè)學(xué)生, 一本圖書(shū)只能屬于一個(gè)出版社,一個(gè)出版社允許出版多本圖書(shū)
  1. 用法語(yǔ)法

    • 當(dāng)一個(gè)A類(lèi)對(duì)象可以關(guān)聯(lián)多個(gè)B類(lèi)對(duì)象時(shí)
    class A(model.Model):
        ...
    
    class B(model.Model):
        屬性 = models.ForeignKey(多對(duì)一中"一"的模型類(lèi), ...)
    
    
  2. 外鍵類(lèi)ForeignKey

    • 構(gòu)造函數(shù):

      ForeignKey(to, on_delete, **options)
      
      
    • 常用參數(shù):

      • on_delete
        1. models.CASCADE 級(jí)聯(lián)刪除。 Django模擬SQL約束ON DELETE CASCADE的行為秕脓,并刪除包含F(xiàn)oreignKey的對(duì)象柒瓣。
        2. models.PROTECT 拋出ProtectedError 以阻止被引用對(duì)象的刪除;
        3. SET_NULL 設(shè)置ForeignKey null;只有null是True才有可能吠架。
        4. SET_DEFAULT 將ForeignKey設(shè)置為其默認(rèn)值芙贫;必須設(shè)置ForeignKey的默認(rèn)值。
        5. ... 其它參請(qǐng)參考文檔 https://docs.djangoproject.com/en/1.11/ref/models/fields/#foreignkey ForeignKey部分
      • **options 可以是常用的字段選項(xiàng)如:
        1. null
        2. unique等
        3. ...
  3. 示例

    • 有二個(gè)出版社對(duì)應(yīng)五本書(shū)的情況.
      1. 清華大學(xué)出版社 有書(shū)

        1. C++
        2. Java
        3. Python
      2. 北京大學(xué)出版社 有書(shū)

        1. 西游記
        2. 水滸
    1. 定義一對(duì)多類(lèi)

      # file: myorm/models.py
      from django.db import models
      class Publisher(models.Model):
          '''出版社'''
          name = models.CharField('名稱(chēng)', max_length=50, unique=True)
      
      class Book(models.Model):
          title = models.CharField('書(shū)名', max_length=50)
          publisher = models.ForeignKey(Publisher, null=True)
      
      
    • 創(chuàng)建一對(duì)多的對(duì)象

      # file: xxxxx/views.py
      from . import models
      pub1 = models.Publisher.objects.create(name='清華大學(xué)出版社')
      models.Book.objects.create(title='C++', publisher=pub1)
      models.Book.objects.create(title='Java', publisher=pub1)
      models.Book.objects.create(title='Python', publisher=pub1)
      
      pub2 = models.Publisher.objects.create(name='北京大學(xué)出版社')
      models.Book.objects.create(title='西游記', publisher=pub2)
      models.Book.objects.create(title='水滸', publisher=pub2)
      
      
    • 查詢:

      • 通過(guò)多查一
      # 通過(guò)一本書(shū)找到對(duì)應(yīng)的出版社
      abook = models.Book.objects.get(id=1)
      print(abook.title, '的出版社是:', abook.publisher.name)
      
      
      • 通過(guò)一查多
      # 通過(guò)出版社查詢對(duì)應(yīng)的書(shū)
      pub1 = models.Publisher.objects.get(name='清華大學(xué)出版社')
      books = pub1.book_set.all()  # 通過(guò)book_set 獲取pub1對(duì)應(yīng)的多個(gè)Book數(shù)據(jù)對(duì)象
      # books = models.Book.objects.filter(publisher=pub1)  # 也可以采用此方式獲取
      print("清華大學(xué)出版社的書(shū)有:")
      for book in books:
          print(book.title)
      
      
  • 練習(xí):
    1. 完成Book 和 Publisher 之間的一對(duì)多
    2. 查看數(shù)據(jù)庫(kù)效果
    3. 登錄到后臺(tái),查看Book實(shí)體
  1. 數(shù)據(jù)查詢
    1. 通過(guò) Book 查詢 Publisher

      通過(guò) publisher 屬性查詢即可
      練習(xí):
          查詢 西游記 對(duì)應(yīng)的出版社信息,打印在終端上
      
      
    2. 通過(guò) Publisher 查詢 對(duì)應(yīng)的所有的 Books

      Django會(huì)在Publisher中增加一個(gè)屬性來(lái)表示對(duì)對(duì)應(yīng)的Book們的查詢引用
      屬性:book_set(MyModel.objects)
      
      

多對(duì)多映射

  • 多對(duì)多表達(dá)對(duì)象之間多對(duì)多復(fù)雜關(guān)系傍药,如: 每個(gè)人都有不同的學(xué)校(小學(xué)磺平,初中,高中,...),每個(gè)學(xué)校都有不同的學(xué)生...
  1. 語(yǔ)法

    在關(guān)聯(lián)的兩個(gè)類(lèi)中的任意一個(gè)類(lèi)中,增加:
    屬性 = models.ManyToManyField(MyModel)
    
    
  2. 示例

    一個(gè)作者可以出版多本圖書(shū)
    一本圖書(shū)可以被多名作者同時(shí)編寫(xiě)
    
    class Author(models.Model):
        xxxx xxxx
    
    class Book(models.Model):
        xxxx xxxx
    
        authors = models.ManyToManyField(Author)
    
    
  3. 數(shù)據(jù)查詢

    1. 通過(guò) Book 查詢對(duì)應(yīng)的所有的 Authors

      可以通過(guò)authors表示對(duì)應(yīng)所有Author的查詢對(duì)象
      
      book.authors.all() -> 獲取 book 對(duì)應(yīng)的所有的author的信息
      
      book.authors.filter(age__gt=80) -> 獲取book對(duì)應(yīng)的作者中年齡大于80歲的作者的信息
      
      
    2. 通過(guò) Author 查詢對(duì)應(yīng)的所有的Books

      Django會(huì)生成一個(gè)屬性 book_set 用于表示對(duì)對(duì)應(yīng)的book的查詢對(duì)象相關(guān)操作?
      author.book_set.all()
      author.book_set.filter()
      author.book_set.create(...)  # 創(chuàng)建新書(shū)并聯(lián)作用author
      author.book_set.add(book)   # 添加已有的書(shū)為當(dāng)前作者author
      author.book_set.clear()  # 刪除author所有并聯(lián)的書(shū)
      author.book_set.remove()  # 刪除所author所有并聯(lián)的書(shū)
      
      
  4. 示例:

    • 多對(duì)多模型
    class Author(models.Model):
        '''作家模型類(lèi)'''
        name = models.CharField('作家', max_length=50)
        def __str__(self):
            return self.name
    class Book(models.Model):
        title = models.CharField('書(shū)名', max_length=50)
        author = models.ManyToManyField(Author, null=True)
        def __str__(self):
            return self.title
    
    
    • 多對(duì)多視圖操作
    from django.http import HttpResponse
    
    from . import models
    
    def many2many_init(request):
        # 創(chuàng)建兩人個(gè)作者
        author1 = models.Author.objects.create(name='呂澤')
        author2 = models.Author.objects.create(name='魏老師')
    
        # 呂擇和魏老師同時(shí)寫(xiě)了一本Python
        book11 = author1.book_set.create(title="Python")
        author2.book_set.add(book11)  #
    
        # 魏老師還寫(xiě)了兩本書(shū)
        book21 = author2.book_set.create(title="C")  # 創(chuàng)建一本新書(shū)"C"
        book22 = author2.book_set.create(title="C++")  # 創(chuàng)建一本新書(shū)"C++"
    
        return HttpResponse("初始化成功")
    
    def show_many2many(request):
        authors = models.Author.objects.all()
        for auth in authors:
            print("作者:", auth.name, '發(fā)出版了', auth.book_set.count(), '本書(shū): ')
            for book in books:
                print('    ', book.title)
        print("----顯示書(shū)和作者的關(guān)系----")
        books = models.Book.objects.all()
        for book in books:
            auths = book.author.all()
            print(book.title, '的作者是:', '拐辽、'.join([str(x.name) for x in auths]))
        return HttpResponse("顯示成功拣挪,請(qǐng)查看服務(wù)器端控制臺(tái)終端")
    
    
    • 多對(duì)多最終的SQL結(jié)果
    mysql> select * from myorm2_author;
    +----+-----------+
    | id | name      |
    +----+-----------+
    | 11 | 呂澤      |
    | 12 | 魏老師    |
    +----+-----------+
    2 rows in set (0.00 sec)
    
    mysql> select * from myorm2_book;
    +----+--------+
    | id | title  |
    +----+--------+
    | 13 | Python |
    | 14 | C      |
    | 15 | C++    |
    +----+--------+
    3 rows in set (0.00 sec)
    
    mysql> select * from myorm2_book_author;
    +----+---------+-----------+
    | id | book_id | author_id |
    +----+---------+-----------+
    | 17 |      13 |        11 |
    | 20 |      13 |        12 |
    | 18 |      14 |        12 |
    | 19 |      15 |        12 |
    +----+---------+-----------+
    4 rows in set (0.00 sec)
    
    
    • 示例示意圖 [圖片上傳失敗...(image-ed69a-1563362158182)]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市俱诸,隨后出現(xiàn)的幾起案子菠劝,更是在濱河造成了極大的恐慌,老刑警劉巖睁搭,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赶诊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡园骆,警方通過(guò)查閱死者的電腦和手機(jī)甫何,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)遇伞,“玉大人辙喂,你說(shuō)我怎么就攤上這事。” “怎么了巍耗?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵秋麸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我炬太,道長(zhǎng)灸蟆,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任亲族,我火速辦了婚禮炒考,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霎迫。我一直安慰自己斋枢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布知给。 她就那樣靜靜地躺著瓤帚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涩赢。 梳的紋絲不亂的頭發(fā)上戈次,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音筒扒,去河邊找鬼怯邪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛花墩,可吹牛的內(nèi)容都是我干的擎颖。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼观游,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼搂捧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起懂缕,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤允跑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后搪柑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體聋丝,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年工碾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弱睦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渊额,死狀恐怖况木,靈堂內(nèi)的尸體忽然破棺而出垒拢,到底是詐尸還是另有隱情,我是刑警寧澤火惊,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布求类,位于F島的核電站,受9級(jí)特大地震影響屹耐,放射性物質(zhì)發(fā)生泄漏尸疆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一惶岭、第九天 我趴在偏房一處隱蔽的房頂上張望寿弱。 院中可真熱鬧,春花似錦按灶、人聲如沸症革。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嗜浮,卻和暖如春羡亩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背危融。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工畏铆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吉殃。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓辞居,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛋勺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓦灶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容