天天看點

Django之資料庫ORM基礎到進階操作一、準備工作二、ORM基本操作三、ORM進階操作補充:四、Django中的常用代碼段:

一、準備工作

表結構如下:

from django.db import models


class Person(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    birth = models.DateField(auto_now = True)

    def __str__(self):
        return f'<Person obj:{self.id}{self.name}>'

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

    def __str__(self):
        return f'<Publisher obj:{self.id}{self.name}>'

class Book(models.Model):
    name = models.CharField(max_length = 32)
    price = models.DecimalField(max_digits=6,decimal_places=2)
    sale = models.IntegerField(default=-1)
    stock = models.IntegerField(default=-1)

    publisher = models.ForeignKey(to='Publisher')

    def __str__(self):
        return f'<Book obj:{self.id}{self.name}>'


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

    books = models.ManyToManyField('Book')

    def __str__(self):
        return f'<Author obj:{self.id}{self.name}>'
           

二、ORM基本操作

1. 查詢
  • 查詢所有的出版社對象的集合
    models.Publisher.objects.all() 
               
  • 傳回與所給篩選條件相比對的對象,傳回結果有且隻有一個,如果符合篩選條件的對象超過一個或者沒有都會抛出錯誤。
    models.Publisher.objects.get(id=1)   
               
  • 查詢滿足條件的所有對象,傳回對象清單
    models.Publisher.objects.filter(id=1,name='sss')  
               
  • 排序
    models.Publisher.objects.all().order_by('id')    
               
2.屬性查詢:

- 無外鍵、多對多:

pub_obj.id
pub_obj.name
           
- 外鍵:
book_obj.publisher         //book所關聯的出版社對象
book_obj.publisher.id      //book所關聯的出版社對象id
book_obj.publisher_id     //book所關聯的出版社對象id
           

- 多對多:

author_obj.books         //django封裝的管理對象
author_obj.books.all()  //作者管理的所有書籍的對象清單
           
3. 增加

- 普通添加:

models.Publisher.objects.create(name='新的出版社')
           
models.Bookj.objects.create(name='新的書名',publisher_id=1)  //添加關聯對象id
models.Bookj.objects.create(name='新的書名',publisher=pub_obj)  //添加關聯對象
           
autho_obj = models.Author.objects.create(name='新的作者')
autho_obj.books.set([1,2])  //關聯對象id清單
           
4. 删除
models.Publisher.objects.get(id=1).delele()  //删除特定對象
models.Publisher.objects.filter(name='xxx').delele()  //批量删除
           
5. 修改

- 普通修改:

pub_obj.name = '新的名字'
pub_obj.save()   //這種修改方式在資料庫操作上會對所有字段重新指派
           
book_obj.name = '新的書名'
book_obj.publisher = pub_obj  //基于對象添加
# book_obj.publisher_id = pub_obj.id  //基于關聯對象id添加
book_obj.save()
           
author_obj.name='新的作者名'  //修改字段
author_obj.save()
author_obj.books.set([1,2,3])  //修改多對多關系
           

三、ORM進階操作

1. 一般操作

  • 必知必會13條:

    1、all()查詢所有

    ret = models.Person.objects.all()

    2、get()傳回與所給篩選條件相比對的對象,傳回結果有且隻有一個,如果符合篩選條件的對象超過一個或者沒有都會抛出錯誤。

    ret = models.Person.objects.get(id= 2)

    3、filter()它包含了與所給篩選條件相比對的對象

    ret = models.Person.objects.filter(name='王計飛')

    ret = models.Person.objects.filter(name='哈哈')

    4、exclude()它包含了與所給篩選條件不比對的對象

    ret = models.Author.objects.exclude(id=1)

    5、values()傳回一個ValueQuerySet——一個特殊的QuerySet,運作後得到的并不是一系列model的執行個體化對象,而是一個可疊代的字典序列

    ret = models.Publisher.objects.values('id','name')

    6、values_list()它與values()非常相似,它傳回的是一個元組序列,values傳回的是一個字典序列

    ret = models.Book.objects.values_list('id','name','price','sale','stock','publisher_id')

    7、order_by()對查詢結果排序

    ret = models.Book.objects.all().order_by('sale')

    8、reverse()對查詢結果反向排序,請注意reverse()通常隻能在具有已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法)。

    ret = models.Book.objects.all().order_by('price').reverse()

    9、distinct()從傳回結果中剔除重複紀錄(如果你查詢跨越多個表,可能在計算QuerySet時得到重複的結果。此時可以使用distinct(),注意隻有在PostgreSQL中支援按字段去重。)

    ret = models.Book.objects.values().distinct()

    10、count()傳回資料庫中比對查詢(QuerySet)的對象數量。

    ret = models.Publisher.objects.all().count()

    11、first()傳回第一條

    ret = models.Book.objects.first()

    12、last()傳回最後一條

    ret = models.Book.objects.last()

    13、exists()如果QuerySet包含資料,就傳回True,否則傳回False

    ret = models.Book.objects.filter(name='awefefe').exists()

2、必知必會13條結果總結:

- 傳回QuerySet對象的方法有(6)
all()
filter()
exclude()
order_by()
reverse()
distinct()
           
- 特殊的QuerySet (2)
values() 傳回一個可疊代的字典序列
values_list() 傳回一個可疊代的元祖序列
           
- 傳回具體對象的 (3)
get()
first()
last()
           
- 傳回布爾值的方法有:(1)
exists()
           
- 傳回數字的方法有(1)
count()
           

3、單表查詢之神奇的雙下劃線

ret = models.Book.objects.filter(price__lt=50,price__gt=20) <大于小于>
ret = models.Book.objects.filter(price__in=[66]) <等于>
ret = models.Book.objects.exclude(price__in=[66]) <不等于>
ret = models.Book.objects.filter(name__contains='飛') <包含>
ret = models.Book.objects.filter(name__icontains='飛') <不區分大小寫>
ret = models.Book.objects.filter(sale__range=[50,100]) <範圍>
ret = models.Person.objects.filter(birth__year=1993) <date字段>
類似的還有:startswith,istartswith, endswith, iendswith 
           

4、ForeignKey操作(Book表中設定對Publisher表的外鍵連接配接)

- 正向查詢

對象查找(跨表查詢)

文法>>>(對象.關聯字段.字段) 
ret = models.Book.objects.first().publisher
ret = models.Book.objects.first().publisher.id
ret = models.Book.objects.first().publisher.name
           

字段查找(跨表查詢)

文法>>>(關聯字段__字段)
ret = models.Book.objects.values('publisher__id','publisher__name')
ret = models.Book.objects.values_list('publisher__id','publisher__name')
           
- 反向查詢
文法>>>(obj.表名_set)
//在Book表中建立外鍵時沒有指定related_name
ret = models.Publisher.objects.get(id = 3).book_set.all()
ret = models.Publisher.objects.filter(id = 3)[0].book_set.all()

//在Book表中建立外鍵時指定related_name='books'
ret = models.Publisher.objects.get(id = 3).books.all()
           
文法>>>(表名__字段)
ret = models.Publisher.objects.values('name','book__name')
ret = models.Publisher.objects.values_list('name','book__name')
           

5、 ManyToManyField操作(Book表中設定對Publisher表的外鍵連接配接)

- class RelatedManager --->關聯管理器

概念:"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。它存在于下面兩種情況:1、外鍵關系的反向查詢。 2、多對多關聯關系。簡單來說就是當 點後面的對象 可能存在多個的時候就可以使用以下的方法。

幾種常用的方法:
- create()---->建立一個新的對象,儲存對象,并将它添加到關聯對象集之中,傳回新建立的對象。
ret = models.Book.objects.create(name='跟幫政掃黃',price=34,publisher_id=4)
ret = models.Author.objects.first().books.create(name = '追風筝的人',publisher_id =1,price = 56)
           
- add()--->把指定的model對象添加到關聯對象集中。
添加對象>>> author_objs = models.Author.objects.filter(id__lt=3)
添加對象>>> models.Book.objects.first().authors.add(*author_objs)
添加id>>> models.Book.objects.first().authors.add(*[1, 2])
           
- set()--->更新model對象的關聯對象。
book_obj = models.Book.objects.first()
book_obj.authors.set([2, 3])
           
- remove()--->從關聯對象集中移除執行的model對象
book_obj = models.Book.objects.first()
book_obj.authors.remove(3)
           
- clear()--->從關聯對象集中移除一切對象。
book_obj = models.Book.objects.first()
book_obj.authors.clear()
           
重點注意:

- 1、對于ForeignKey對象,clear()和remove()方法僅在null=True時存在。

- 2、對于所有類型的關聯字段,add()、create()、remove()和clear(),set()都會馬上更新資料庫。換句話說,在關聯的任何一端,都不需要再調用save()方法。

6、聚合查詢和分組查詢

- 聚合查詢

aggregate()是QuerySet 的一個終止子句,意思是說,它傳回一個包含一些鍵值對的字典。鍵的名稱是聚合值的辨別符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。

用到的内置函數:from django.db.models import Avg, Sum, Max, Min, Count
ret = models.Book.objects.aggregate(Sum('price'),Count('id'),Max('price'),Min('price'),average = Avg('price'))
           
- 分組查詢
  • 統計每一本書的作者個數
ret = models.Book.objects.all().annotate(author_num = Count('author')) for i in ret: print([i.name](http://i.name),i.author_num)
           
  • 統計出每個出版社買的最便宜的書的價格
方法一:
ret = models.Publisher.objects.all().annotate(cheaper = Min('book__price')).values('name','cheaper')

方法二:
ret = models.Book.objects.values_list('publisher__name').annotate(cheaper = Min('price'))
           
  • 統計不止一個作者的圖書
ret = models.Book.objects.all().annotate(num = Count('author')).filter(num__gt =1)
           
  • 根據一本圖書作者數量的多少對查詢集 QuerySet進行排序
ret = models.Book.objects.all().annotate(num = Count('author')).order_by('-num')
           

查詢各個作者出的書的總價格

ret = models.Author.objects.annotate(sum_price = Sum('books__price')).values_list('name','sum_price')
           

- F查詢和Q查詢

1.F查詢:

Django 提供 F() 來做對兩個字段的值的比較。F() 的執行個體可以在查詢中引用字段,來比較同一個 model 執行個體中兩個不同字段的值。

- 查詢書籍銷量大于庫存的

ret = models.Book.objects.filter(sale__gt=F('stock')).values('name','sale','stock')
           

- 将所有書籍的庫存加50

ret = models.Book.objects.all().update(price = F('stock')+50)
           

- 延伸到對char字段的操作-->在所有書名後面加上(第一版)

from django.db.models.functions import Concat
from django.db.models import Value

ret = models.Book.objects.all().update(name = Concat(F('name'),Value('(第一版)')))

           
2.Q查詢

filter() 等方法中的關鍵字參數查詢都是一起進行“AND” 的。 如果你需要執行更複雜的查詢(例如OR語句),你可以使用Q對象。

- 作者名是王計飛或劉德凱的書

ret = models.Book.objects.all().filter(Q(author__name='王計飛')|Q(author__name='劉德凱')).values('name','author__name')
           

- 比較一下兩者的差別(一本書的查詢)

ret = models.Book.objects.all().filter(author__name = '王計飛')
           

補充:

  • limit_choices_to的作用是設定篩選條件,在admin中隻顯示篩選後的内容。

四、Django中的常用代碼段:

1、事務操作的代碼格式:

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()
    import datetime
    from app01 import models
     
    try:
        from django.db import transaction
        with transaction.atomic():
            操作内容
    except Exception as e:
        print(str(e))
           

2、Django終端列印SQL語句

在Django項目的settings.py檔案中,在最後複制粘貼如下代碼:

​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、在Python腳本中調用Django環境:

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()
    from app01 import models
    books = models.Book.objects.all()
    print(books)