1. 程式人生 > 其它 >Django微講解(七)

Django微講解(七)

Django微講解(七)

聚合查詢

	我們在講資料庫的聚合查詢的時候,講了資料庫的聚合函式,常用就是最大值'max'、最小值'min'、求和'sum'、計數'count'、
平均值'avg',我們的Django ORM聚合查詢使用的也是這些關鍵字,只不過資料庫的聚合函式是需要分組之後才可以使用的,而Django ORM
的聚合函式沒有分組也可以使用聚合函式,預設整體的一個表就是一組。
    from django.db.models import Max,Min,Count,Sum,Avg
    res = models.Book.objects.aggregate(Max('price'))
    print(res)
    使用聚合查詢的關鍵字是'aggregate'

分組查詢

	資料庫的分組查詢使用的是group by關鍵字,Django ORM使用的關鍵字是'annotate',ORM在執行分組操作的時候,有的計算機
會報錯,報錯的話可以去修改'sql_mode',移除'only_full_group_by'即可。
# 1.統計每本書的作者個數
	res = models.Book.objects.annotate(auhtor_num=Count('authors__pk')).values('title','auhtor_num')
    print(res)
# 2.統計每個出版社賣的最便宜的書的價格
    res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    print(res)
# 3.統計不止一個作者的圖書
    res = models.Book.objects.annotate(author_count=Count('authors__pk')).filter(author_count__gte=2).values('title','author_count')
    print(res)
# 4.統計每個作者出的書的總價格
	res = models.Author.objects.annotate(price_num=Sum('book__price')).values('name','price_num')
    print(res)
# 5.統計每個出版社主鍵值對應的書籍個數
'''
上述四個練習題都是以表為單位分組的,如果想要以表中的某個欄位分組,只需要在'annotate'關鍵字前面點'values'給某個欄位進行分組即可
'''
	res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
    print(res)

往已經存在資料的表中新增欄位

    當表中已經存在資料的情況下,想要在新增額外欄位,就需要指定該欄位的預設值,或者指定該欄位的值可以為null
    方式一:
		可以給額外新增的欄位加一個預設值,關鍵字是'default'
        示例:age = models.IntegerField(default=25)
	方式二:
        設定額外新增欄位的值可以為null
        示例:age = models.IntegerField(null=True)
	方式三:
        可以在遷移命令的提示中直接給預設值

F查詢

	 F可以幫我們取到表中某個欄位對應的值來當做我們的篩選條件,而不是自定義常量的條件,實現了動態比較的效果,Django還支
持F物件之間以及F物件與常數之間的加減乘除和取模的操作。
# 1.查詢庫存大於銷量的書籍
	from django.db.models import F
	res = models.Book.objects.filter(kucun__gt=F('xiaoliang'))
	print(res)
# 2.將所有書的價格提升1000塊
    res = models.Book.objects.update(price=F('price') + 1000)
    print(res)
# 3.將所有書的名稱後面加上_爆款字尾
'''
想要修改char欄位的值,不可以用上述的方法,可以使用下面ORM專門提供的方法
'''
	from django.db.models.functions import Concat
    from django.db.models import Value,F
    models.Book.objects.update(title=Concat(F('title'),Value('_iii')))

Q查詢

	filter()方法中逗號隔開的條件是'and'的關係,是沒有辦法直接修改的,所以我們就可以使用Q物件,支援邏輯運算子,'管道
符'(|)就是'or'關係,在Q物件前面加'~'就是'not'的關係。
# 1.查詢價格大於20000或者賣出大於1000的書籍
	from django.db.models import Q
    res = models.Book.objects.filter(Q(price__gt=20000)|Q(xiaoliang__gt=1000))
    print(res)  # 管道符是or關係
# 2.查詢價格小於20000或者庫存小於1000的書籍
	res = models.Book.objects.filter(~Q(price__gte=20000)|~Q(kucun__gte=1000))
    print(res)  # ~是not關係
# 3.Q物件進階用法
	q_obj = Q()  # Q方法其實是一個類,我們先產生一個q_obj物件
    q_obj.connector = 'or'  # 預設是and關係,可以改沒or
    q_obj.children.append(('price__gt',20000))
    q_obj.children.append(('kucun__gt',1000))
    res = models.Book.objects.filter(q_obj)
    print(res)

ORM查詢優化

	ORM查詢預設都是惰性查詢,能不消耗資料庫資源就不消耗,ORM查詢預設自帶分頁功能,儘量減輕單次查詢資料的壓力
# only
	only會產生物件結果集,物件點括號內出現的欄位不會再次查詢資料庫
    res = models.Book.objects.only('title','price')
    for obj in res:
        print(obj.title)
        print(obj.price)
        # print(obj.xiaoliang)  # 也可以點括號以外的,但是會再次查詢資料庫,增加了資料庫的壓力
# defer
	defer也會產生物件結果集,物件點括號之外的欄位不會再次查詢資料庫
    res = models.Book.objects.defer('title','price')
    for obj in res:
        print(obj.xiaoliang)
        # print(obj.price)  # 也可以點括號內的,但是會再次查詢資料庫,增加資料庫的壓力
# select_related
	select_related括號內只能傳外來鍵欄位,只能傳一對一和一對多欄位,不能傳多對多欄位,內部原理就是直接連表,然後將連
接之後的表中所有的資料全部封裝到資料物件中,然後物件就可以通過正反向查詢,內部不會再次查詢資料庫,不會增加資料庫的壓力。
    res = models.Book.objects.select_related('publish')
    for obj in res:
        print(obj.title)
        print(obj.price)
        print(obj.publish.name)
        print(obj.publish.addr)
# prefetch_related
	prefetch_related括號內只能傳外來鍵欄位,只能傳一對一和一對多欄位,不能傳多對多欄位,內部原理是將多次查詢之後的結
果封裝到資料物件當中,然後物件就可以通過正反向查詢,內部不會再次查詢資料庫,不會增加資料庫的壓力。
    res = models.Book.objects.prefetch_related('publish')
    for obj in res:
        print(obj.title)
        print(obj.price)
        print(obj.publish.name)
        print(obj.publish.addr)

ORM常見欄位

# 1.AutoField
	int自增列,必須填入引數 primary_key=True。當model中如果沒有自增列,則自動會建立一個列名為id的列。
# 2.IntegerField
	整型int
# 3.CharField
	字元型別,必須提供max_length引數, max_length表示字元長度,對應的是資料庫中的varchar型別,沒有設定對應char型別
的欄位,但是Django允許我們自定義新的欄位。
# 4.DecimalField
	10進位制小數
# 5.DateField
	日期欄位,日期格式  YYYY-MM-DD,相當於Python中的datetime.date()例項。
# 6.DateTimeField
	日期時間欄位,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()例項。
# 7.BigIntergerField
	整型bigint
# 8.BooleanField
	傳佈爾值,對應的是0和1
# 9.TextField
	儲存大段文字
# 10.FileField
	傳檔案自動儲存到指定位置並存檔案路徑
# 11.EmailField
	本質還是varchar型別 

ORM重要引數

# 1.primary_key
	主鍵
# 2.max_length
	欄位最大長度
# 3.verbose_name
	註釋
# 4.null
	是否允許為空
# 5.default
	設定預設值
# 6.max_digits
	小數總長度
# 7.decimal_places
	小數位長度
# 8.unique
	如果設定為unique=True 則該欄位在此表中必須是唯一的 。
# 9.db_index
	如果db_index=True 則代表著為此欄位設定索引。
# 10.auto_now
	配置上auto_now=True,每次更新資料記錄的時候會更新該欄位。
# 11.auto_now_add
	配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫。
# 12.choices
	用於可以被例舉完全的資料
# 13.to
	設定要關聯的表
# 14.to_field
	設定要關聯的表的欄位
# 15.db_constraint
	是否在資料庫中建立外來鍵約束,預設為True。
'''
外來鍵欄位中使用related_name引數可以修改正向查詢的欄位名
'''
choices示例:
    models.py檔案:
        class Info(models.Model):
            username = models.CharField(max_length=255)
            password = models.IntegerField()
            gender_choies = (
                (1,'nan'),
                (2,'nv'),
                (3,'bian')
            )
            gender = models.IntegerField(choices=gender_choies)
    test.py檔案:
        res = models.Info.objects.filter(pk=1).first()
    	print(res.get_gender_display())

事務操作

# MySQL事務四大特性
	原子性、一致性、永續性、獨立性
# MySQL事務的關鍵字
	開啟事務:start transcation
	事務回滾:rollback
	確認事務:commit
# ORM事務操作
	from django.db import transaction
    try:
        with transaction.atomic():  # with語句結束,事務結束
            pass  # 事務程式碼
    except Exception:
        pass

ORM執行原生SQL

# 方式1
from django.db import connection, connections
cursor = connection.cursor()  
cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
cursor.fetchone()

# 方式2
models.UserInfo.objects.extra(
                    select={'newid':'select count(1) from app01_usertype where id>%s'},
                    select_params=[1,],
                    where = ['age>%s'],
                    params=[18,],
                    order_by=['-age'],
                    tables=['app01_usertype']
                )

多對多建立方式

# 1.全自動
	全自動就是ORM自動建立第三張表,但是沒有辦法擴充套件第三張表的欄位
    示例:authors = models.ManyToManyField(to='Author')
# 2.全手動
	第三張表可以完全自定義,擴充套件性高,但是不能使用外來鍵方法和正反向查詢
    示例:
        class Book(models.Model):
        	title = models.CharField(max_length=32)
       class Author(models.Model):
        	name = models.CharField(max_length=32)
       class Book2Author(models.Model):
            book_id = models.ForeignKey(to='Book')
            author_id = models.ForeignKey(to='Author')
# 3.半自動
	可以使用正反向查詢,第三張表還可以擴充套件,但是不能使用add、set、remove、clear這四種方法
    示例:
'''
多對多建在任意一方都可以,如果建在Author表,欄位順序互換即可
'''
        class Book(models.Model):
            title = models.CharField(max_length=32)
            authors = models.ManyToManyField(
                                    to='Author',
                                    through='Book2Author',  # 指定表
                                    through_fields=('book','author')  # 指定欄位
            					)
      class Author(models.Model):
            name = models.CharField(max_length=32)
      class Book2Author(models.Model):
            book = models.ForeignKey(to='Book')
            author = models.ForeignKey(to='Author')

這裡是IT小白陸祿緋,歡迎各位大佬的指點!!!