Django ORM 查詢補充

數據庫如何高級快速的查詢是必須掌握的技能之一,除去通常的增刪改掌握高級語法可讓你更加快速有效的獲取你想要的數據python


model(準備測試模型):

from django.db import models

class Publisher(models.Model):
    id = models.AutoField(primary_key=True)

    name = models.CharField(max_length=32)

    addr = models.CharField(max_length=32)

    phone = models.IntegerField

    def __str__(self):
        return self.name


# 做者查書,設計到做者裏面
class Author(models.Model):
    id = models.AutoField(primary_key=True)

    name = models.CharField(max_length=16)

    author_detail = models.OneToOneField("AuthorDetail")

    # 多對多
    books = models.ManyToManyField(to="Book")

    def __str__(self):
        return self.name


class Book(models.Model):
    id = models.AutoField(primary_key=True)

    title = models.CharField(max_length=6)

    price = models.DecimalField(max_digits=5, decimal_places=2)

    publish_day = models.DateField(auto_now_add=True)

    # 書-出版社 多對一關聯
    publisher = models.ForeignKey(to="Publisher", to_field="id")

    def __str__(self):
        return self.title


class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)

    city = models.CharField(max_length=32)

    email = models.EmailField()

    def __str__(self):
        return self.city
複製代碼

1.聚合查詢

  • aggregate()是查詢的終止子句,查詢結果是返回一個鍵值對的字典數據,生成的鍵名能夠自動生成,也能夠人爲指定

例如:git

queryset = Book.objects.all().aggreate(Avg("price"))
{'price__avg': 192.593333} # 查詢結果(未指定鍵名)

models.Book.objects.all().aggregate(avg_price=Avg("price"))
{'avg_price': 192.593333} # 查詢結果(指定鍵名)

# 若是要指定多個鍵值對能夠增長參數
models.Book.objects.all().aggregate(Avg('price'), Min('price'), Sum('price'))

{'price__avg': 192.593333, 'price__max': Decimal('233.33'), 'price__min': Decimal('111.12'), 'price__sum': Decimal('577.78')} 

複製代碼

2.分組查詢

  • 爲調用的QuerySet中每個對象都生成一個獨立的統計值

2.1 統計每一本書的做者個數

models.Book.objects.all().annotate(authorNum=Count("author"))
Output: <QuerySet [<Book: 書一>, <Book: 書二>, <Book: 書三>]>
book_list = models.Book.objects.all().annotate(authorNum=Count("author"))
for i in book_list:
    print(i.authorNum)
OutPut:
	2
	2
	1
複製代碼

2.2 統計每一個出版社賣的最便宜的書

# 注意在反向查詢字段須要雙下劃線
models.Publisher.all().annotate(min_price=Min("book__price")) 
for i in queryset:
	print(i.min_price)

Output:
	111.12
	12.00
	456.00
	785.00
	

# 當須要篩選其餘的字段或者須要返回特定的字段值
models.Publisher.filter(name='zhan').values('phone','book__author').annotate(min_price=Min("book__price"))
for i in queryset:
	print(i)
Output:
	{'phone': 18895309883, 'book__author': 'zhan', 'book__price': 111.11 }

	
複製代碼

2.3 統計不僅有一個做者的圖書

# ps:gt在數據庫篩選表示大於等於,lt小於等於
models.objects.all().annotate(au=Count("author")).filter(au__gt=1)

Output:
[queryset <book1> <book2>] # 本身看的懂就行

# 能夠對上面的查詢語句進行oder_by下
models.objects.all().annotate(au=Count("author")).filter(au_gt=1).oder_by(au)
複製代碼

2.4 查詢做者出的書的總價格

# 查詢語句中name是指做者的名字,結果仍是會以鍵值對展現
models.Author.objects.all().annotate(total=Sum("book_price")).values("name", 
"total")
複製代碼

3. F查詢

  • 上述的聚合查詢,分組查詢都是讓數據庫中的數據與限制的常量比較,可是若是在同一張表或者關聯表之間的字段比較或者加入字段的加、減、乘、除的運算,上述幾種方法實現有難度,因此要引用F查詢。

3.1書本中的價格須要與書本的id進行比較(實際不存在這種場景)

# 查詢結果爲querysetfile:/Users/zhanlingjie/Documents/mypython/SZKJ/eyaos_vm/server/organization/urls.py
models.Book.objects.filter(id__gt= F('price')/2)

複製代碼

4. Q查詢

  • 當須要對同一個字段有不一樣的條件進行篩選時,多者屬於or關係

4.1 查詢做者的名字(小三或者 小一)

models.Author.objects.filter(Q(name="小一") | Q(name="小三"))
<QuerySet [<Author: 小一>, <Author: 小三>]>
Output:
	1
	2
	3

複製代碼

總結

ORM 跨表查詢
    class Book(models.Model):   
        title = models.CharField( max_length=32)

        publish=models.ForeignKey(to="Publish",to_field="id")
        authors=models.ManyToManyField(to='Author',related_name='bookList')&emsp;

    class Publish(models.Model):
        name=models.CharField( max_length=32)


    class Author(models.Model):
        name=models.CharField( max_length=32)
        ad=models.OneToOneField("AuthorDetail")

    class AuthorDetail(models.Model):

        telephone=models.BigIntegerField()


    基於對象查詢(sql:子查詢)


          一對多的關係  (Publish--Book)
                  正向查詢,按字段:

                  查詢python這本書的出版社所在的名稱
                  book_obj=Book.objects.filter(title="python").first()
                  #print(book_obj.publish.name)

                  反向查詢,按表名小寫_set:

                  人民出版社出版過的全部書籍名稱

                  publish_obj=Publish.objects.filter(name="人民出版社出版").first()
                  print(publish_obj.book_set.all())  
                  for obj in publish_obj.book_set.all():
                       print(obj.title)


          多對多的關係
                正向查詢,按字段:
                    python這本書全部做者的名字
                        book_obj=Book.objects.filter(title="python").first()
                        book_obj.authors.all()

                反向查詢,按表名小寫_set:
                    alex出版過的全部書籍名稱
                    alex=Author.objects.filter(name="alex").first()
                    alex.bookList.all()

          一對一的關係
                正向查詢,按字段:
                    查詢alex的手機號
                    alex=Author.objects.filter(name="alex").first()
                    alex.ad.telephone

                反向查詢:按表名小寫
                    以151開頭的手機號的做者的名字
                    ad=AuthorDetail.objects.get(telephone__startswith="151")
                    ad.author.name      


    基於Queryset和 __(sql:join語句):

          正向查詢,按字段
          反向查詢,按表名小寫

          一對多的關係  (Publish--Book)


                  查詢python這本書的所在出版社的名稱
                  Book.objects.filter(title="python").values("publish__name")
                  for obj in Book.objects.filter(title="python"):
                      temp={}
                      temp["publish__name"]=obj.publish.name

                  人民出版社出版過的全部書籍名稱         
                  Publish.objects.filter(name="人民出版社出版").values("book__title")



          多對多的關係

                    python這本書全部做者的名字
                        Book.objects.filter(title="python").values("authors__name")


                    alex出版過的全部書籍名稱
                        Author.objects.filter(name="alex").values("book__title")


          一對一的關係

                    查詢alex的手機號
                        Author.objects.filter(name="alex").values("ad__telephone")

                    以151開頭的手機號的做者的名字
                    AuthorDetail.objects.filter(telephone__startswith="151").values("author__name")

         擴展:
                練習1:
                查詢python這本書的所在出版社的名稱
                Book.objects.filter(title="python").values("publish__name")          
                Publish.objects.filter(book__title="python").values("name")

                練習2:
                手機號以151開頭的做者出版過的全部書籍名稱以及出版社名稱
                Book.objects.filter(authors__ad__telephone__startswith="151").values("title","publish__name")

    分組查詢:
            查詢每個出版社出版過的書籍個數    
            Publish.objects.annotate(Count("book__id"))
            select count(*) from publish  group by id
複製代碼
相關文章
相關標籤/搜索