1. 程式人生 > 實用技巧 >django學習第八天

django學習第八天

orm多條操作

刪除和修改

  • 修改
      在一對一和一對多關係時,和單表操作是一樣的
      一對一  一個作者對應一個資訊
      ad_obj = models.AuthorDetail.objects.get(id=1)
      models.Author.objects.filter(id=1).update(name='xx',屬性名=模型類物件)
      models.Author.objects.filter(id=1).update(name='xx',ad=ad_obj)
      models.Author.objects.filter(id=1).update(name='xx',欄位名=id欄位值)
      models.Author.objects.filter(id=1).update(name='xx',ad_id=1)

      一對多 一個出版社出多本書
      pub_obj = models.Publish.objects.get(id=2)
      models.Book.objects.filter(id=1).update(title='水滸',屬性名=模型類物件)
      models.Book.objects.filter(id=1).update(title='水滸',pub=pub_obj)
      models.Book.objects.filter(id=2).update(title='三國',欄位名=id欄位值)
      models.Book.objects.filter(id=2).update(title='三國',pub_id=2)

      多對多修改
      book_obj = models.Book.objcets.get(id=4)
      #用book_obj模型類物件,然後點屬性(.authors)的方式操作第三張表
      book_obj.authors.set('3')#引數要是可迭代型別資料
      book_obj.authors.set([3,])#更新多個記錄
      set執行的步驟:
      1.先執行clear清空
      2.再執行add新增
      book_obj = models.Book.objects.get(id=1)
      book_obj.authors.set([4,])
      
  • 刪除
      一對一和一對多刪除一樣
      delete方法
      models.Author.objects.filter(id=1).delete()
      models.AuthorDetail.objects.filter(id=1).delete()

      多對多刪除remove
      book_obj = models.Book.objects.get(id=1)
      author_obj = models.Author.objects.get(id=2)
      下面orm語句意思為在多對多關係表中刪除了書籍id為1的,作者id為2的記錄
      #通過Book得到的模型類物件點屬性(.authors)操作第三張表
      book_obj.authors.remove(2) #刪除單條
      book_obj.authors.remove(2,3)#刪除多條
  • 清空
      多對多
      #將當前書籍對應的所有作者在多對多關係表中的關係記錄,全部刪除
      book_obj = models.Book.objects.get(id=1)
      book_obj.authors.clear()

子查詢和連表查詢

基於物件的跨表查詢(子查詢)

      一對一查詢
      正向查詢
      關係屬性寫在哪個表裡面,那麼通過這個表的資料,去查詢關聯的另外一張表的資料,就叫作正向查詢,反之就是反向查詢
      
      #正向查詢使用關聯屬性名稱
      #查詢一下王振這個作者的手機號
      author_obj = models.Author.objects.get(name='王振')
      author_obj.ad #找到了author_obj關聯的作者詳細資訊表裡面的對應記錄
      主表模型類物件(author_obj).主表的關聯屬性名稱(ad).從表屬性名(telephone)
      print(author_obj.ad.telephone) 

      #反向查詢
      反向查詢用關聯它的模型類的名稱小寫
      查詢一下地址在上海的那個作者是誰
      從表->主表
      author_detail_obj = models.AuthorDetail.objects.filter(address='上海').first() #filter過濾後的是quertset型別,用first取第一個模型類物件
      從表的模型類物件.主表的模型類名稱小寫.主表屬性名
      print(author_detail_obj.author.name)


      ##########一對多#########
      #正向查詢
      #使用關聯屬性查詢
      #查詢一下少年阿賓是哪個出版社出版的
      book_obj = models.Book.objects.get(title='少年阿賓')
      Book類的模型類物件.關聯屬性.name
      print(book_obj.pub.name)

      #反向查詢
      #模型類小寫_set
      #查詢一下偉哥出版社出版了哪些書
      pub_obj = models.Publish.objects.get(name='偉哥出版社')
      pub_obj.book_set #可能為多條記錄,所以模型類名小寫_set
      #類似於objects控制器
      print(pub_obj.book_set.all().values('title'))
      #查詢結果不會自動去重

      
      ######多對多######
      #正向查詢
      #使用屬性來查
      #查詢一下金陵第二步這本書誰寫的
      book_obj = models.Book.objects.get(title='金陵第二部')
      Book類的模型類物件.關聯屬性名稱.all().values('name')
      print(book_obj.authors.all().values('name'))

      #反向查詢
      #使用模型類名小寫_set
      查詢一下謝晨寫了哪些書
      author_obj = models.Author.objects.get(name='謝晨')
      print(author_obj.book_set.all().values('title'))

檢視原生sql的方式

  • 1.query 適用於大部分
  • 2.在settings配置檔案中寫上如下內容,就能夠自動打印出我們執行orm語句對應的sql
     LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
	} 
  • 3.通過django配置的連線mysql的管道來檢視(pymysql)
      from app01 import models
      def add_book(request):
            book_obj = models.Book(title='python',price=123)
            book_obj.save()
            from django.db import connection #通過這種方式也能檢視sql語句
            print(connection.queries)
            return HttpResponse('OK')

基於雙下劃線的跨表查詢(連表操作)

      原生sql寫法  哪個表在前哪個表在後沒區別
      select * from t2 inner join t1 on t1.t2_id = t2.id;
      select * from t1 inner join t2 on t1.t2_id = t2.id;
  • 一對一
      查詢一下謝思敏這個作者的家庭地址
      正向操作,使用屬性
      ret = models.Author.objects.filter(過濾條件).values('主表屬性名__從表屬性名')
      ret = models.Author.objects.filter(name='謝思敏').values('ad__address') #<QuerySet [{'ad__address': '美國'}]>型別

      反向操作,使用表名小寫
      ret = models.AuthorDetail.objects.filter(主表表名小寫__過濾條件).values('從表屬性名')
      ret = models.AuthorDetail.objects.filter(author__name='謝思敏').values('address') #<QuerySet [{'address': '美國'}]>型別
  • 一對多
      查詢一下少年阿賓是哪個出版社出版的
      正向操作 使用關聯屬性
      #這類的正向操作,注意看關聯的屬性名在哪個表裡,哪個表就是主表
      ret = models.Book.objects.filter(過濾條件).values('關聯屬性名__從表屬性名')
      ret = models.Book.objects.filter(title='少年阿賓').values('pub__name')#<QuerySet [{'pub__name': '橘子成人出版社'}]>

      反向操作
      ret = models.Publish.objects.filter(主表類名小寫__過濾條件).values('從表屬性名')
      ret = models.Publish.objects.filter(book__title='少年阿賓').values('name')#<QuerySet [{'name': '橘子成人出版社'}]>
  • 多對多
      查詢一下金陵第二部這本書誰寫的
      正向操作  使用關聯屬性
      ret = models.Book.objects.filter(title='金陵第二部').values('Book類模型關聯屬性__author表屬性名')
      ret = models.Book.objects.filter(title='金陵第二部').values('authors__name')
      #<QuerySet [{'authors__name': '謝思敏'}, {'authors__name': '謝晨'}]>
      反向操作 使用類名小寫
      ret = models.Author.objects.filter(主表類名小寫__過濾條件).values('從表屬性名')
      ret = models.Author.objects.filter(book__title='金陵第二部').values('name')
      #<QuerySet [{'name': '謝思敏'}, {'name': '謝晨'}]>

聚合查詢(aggregate)

      ##########聚合查詢aggregate###########
      統計一下所有書籍的平均價格 max min avg count sum 
      需要先匯入
      from django.db.models import Max,Min,Avg,Count,Sum
      ret = models.Book.objects.aggregate(Avg('price'))
      print(ret)#普通字典型別{'price__avg': 43.925}
      ret = models.Book.objects.all().aggregate(a=Avg('price'),b=Max('price'))
      print(ret)#{'price__avg': 43.925, 'price__max': Decimal('88.88')} , {'a': 43.925, 'b': Decimal('88.88')}
      #aggregate方法可以看為是orm語句的結束語句,結果為普通字典型別,不能繼續呼叫queryset或者模型類物件提供的方法了,也就是aggregate必須放在最後,另外裡面的聚合函式可以賦值給變數

分組查詢(annotate)

      ###########分組查詢###########
      查詢一下每個出版社出版書的平均價格
      ret = models.Book.objects.values('要分組的欄位名').annotate(聚合函式)
      ret = models.Book.objects.values('pub_id').annotate(a=Avg('price'))#只能獲取到values指定的欄位和統計結果資料
      ret = models.Book.objects.values('pub_id','id').annotate(a=Avg('price'))#多條件分組pub_id和id值相同的算為一組

      values('pub__name')#就是通過Book類的屬性名跨表操作另外一張表的name
      ret = models.Book.objects.values('pub__name').annotate(a=Avg('price'))#以出版社名稱分組

      #推薦使用下面的因為獲取到模型類物件就可以用它所有的屬性資料
      ret = models.Publish.objects.annotate(變數a=聚合函式Avg('要關聯的另外一張表的類名小寫__要操作的屬性'))
      ret = models.Publish.objects.annotate(a=Avg('book__price'))#返回結果是Publish的模型類物件,這個模型類物件裡面包含了Publish的所有屬性資料,還有annotate的統計結果資料
      ret = models.Publish.objects.annotate(a=Avg('book__price')).values('name','a')

      原生sql,虛擬碼
      select publish.name,Avg(book.price) from publish inner join book on publish.id = book.pub_id group by publish.id.
      select avg(price) from book group by pub_id;

F查詢 主要針對本表的多個欄位進行比較時使用

       ########F查詢#########
      from django.db.models import F
      #查詢一下點贊數在於評論數的書籍
      models.Book.objects.filter(dianzan__gt=comment)
      obj_list = models.Book.objects.all().values()
      a = []
      for i in obj_list:
            if i.dianzan > i.comment:
                  a.append(i)
      print(a)
      #上面寫法太麻煩了

      F查詢可以用來做本表不同欄位之間的一個比較
      ret = models.Book.objects.filter(dianzan__gt=F('comment'))
      print(ret)
      F可以用來對本表資料進行一些同一操作(四則執行都支援)
      將所有的書籍上調10塊錢
      models.Book.objects.all().update(price=F('price')+10)

Q查詢 可以進行多條件查詢,查詢關係可以是 或與非

      from django.db.models import F
      #查詢書名中包含少年兩個字的並且評論數大於20的書籍
      ret = models.Book.objects.filter(title__contains='少年',comment__ge=20)
      #filter中逗號分隔的條件,預設是and的關係
      print(ret)#<QuerySet [<Book: 少年阿賓2>]>

      #想進行或的關係查詢需要藉助到我們Q查詢Q
      查詢書名中包含少年兩個字的或者評論數大於20的書籍
      ret = models.Book.objects.filter(Q(title__contains='少年')|Q(comment__gt=20))

      查詢書名中包含少年兩個字的或者評論數大於20的,並且點贊數大於等於80的
      ret = models.Book.objects.filter(Q(title__contains='少年')|Q(comment__gt=20),dianzan__gte=80)
      #注意,如果結合逗號來進行and的關係查詢,那麼必須將沒有Q包裹的查詢條件放在Q包裹的查詢條件後面
      
      下面這張方式也可以,Q查詢可以多層巢狀使用
      #    ~取反  &and關係  |or關係
      ret = models.Book.objects.filter(Q(Q(title__contains='少年')|Q(comment__gt=20)) & ~Q(dianzan__gte=80))