一、創建模型類
models.py文件中設置ORM字段。
介紹:
Django提供了很多字段類型,比如URL/Email/IP/ ,但是mysql數據沒有這些類型,這類型存儲到數據庫上本質是字符串數據類型,其主要目的是爲了封裝底層SQL語句;
類型:
1、字符串類
models.CharField 對應的是MySQL的varchar數據類型
char 和 varchar的區別 :
共同點,是存儲數據的長度,不能超過max_length限制;
不同點,是varchar根據數據實際長度存儲,char按指定max_length()存儲數據;所以,前者更節省硬盤空間;
name = models.CharField(max_length=32)
# 以下都是在數據庫中,本質都是字符串數據類型,此類字段只是在Django自帶的admin中生效
EmailField(CharField) # email
IPAddressField(Field) # IP
URLField(CharField) # URL
SlugField(CharField) # Slug
UUIDField(Field) # UUID
FilePathField(Field) # 文件路徑(/usr/local/python/)
FileField(Field)
ImageField(FileField) # 圖片路徑(本質也就是圖片的位置路徑)
CommaSeparatedIntegerField(CharField)
2、時間字段
create_time = models.DateTimeField(null=True) # 年月日時分秒
date = models.DateField() # 年月日
3、數字字段(整數、小數)
(max_digits=30,decimal_places=10) 即,總長度30,小數位10位
數字:
num = models.IntegerField() # 整數 (也分 tiny等,即小整數,大整數,超大整數...)
num = models.FloatField() # 浮點
price = models.DecimalField(max_digits=8, decimal_places=3) # 精確浮點
4、枚舉字段
應用場景?以及和外鍵對比,什麼優勢?
1、key-value對應,選項固定情況,即不是動態變化的。如:設備狀態(使用中、未使用、故障、已下線、其他),前後端數據交互時,數據是1、2、3,只需告訴前端分別對應的是什麼就可以了,因爲不會改變。
2、無需連表查詢性能低,省硬盤空間(選項不固定時用外鍵)
3、在modle文件裏不能動態增加(選項一成不變,用Django的choice)
# 元祖嵌套元祖,其實可以看做是字典的生成式一種,數據表中保存的是1\2\3,key-value對應
choice=(
(1,'男人'),
(2,'女人'),
(3,'其他')
)
lover = models.IntegerField(choices=choice) # 枚舉類型
5、其他
索引
db_index = True 表示設置索引
unique = True 唯一的意思,設置唯一索引
class Meta:
# 格式:元祖的嵌套,另外,聯合索引有基本原則:最左前綴(並有序的)!!!
unique_together = (
('email','ctime'), # 聯合唯一索引
)
index_together = (
('email','ctime'), # 聯合索引(不做限制)
)
二、ORM操作
背景:
1、orm使用方式:
orm操作可以使用類實例化,obj.save的方式;
也可以使用create()的形式;
2、QuerySet數據類型介紹
QuerySet與惰性機制
所謂惰性機制:
Publisher.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它並不會馬上執行sql,而是當調用QuerySet的時候才執行。
QuerySet特點:
<1> 可迭代的
<2> 可切片
<3> 惰性計算和緩存機制
def queryset(request):
books = models.Book.objects.all()[:10] # 切片 應用分頁
books = models.Book.objects.all()[::2]
book = models.Book.objects.all()[6] # 索引
print(book.title)
for obj in books: # 可迭代
print(obj.title)
# 惰性計算:
# 等於一個生成器,不應用books不會執行任何SQL操作
# query_set緩存機制:
# 1次數據庫查詢結果query_set都會對應一塊緩存,再次使用該query_set時,不會發生新的SQL操作;
# 作用:這樣減小了頻繁操作數據庫給數據庫帶來的壓力;
books = models.Book.objects.all()
authors = models.Author.objects.all()
for author in authors:
print(author.name)
print('-----')
models.Author.objects.filter(id=1).update(name='張某')
for author in authors:
print(author.name)
# 但是有時候取出來的數據量太大會撐爆緩存,可以使用迭代器優雅得解決這個問題;
models.Publish.objects.all().iterator()
return HttpResponse('OK')
基本操作
增加
# 準備三個表,作者(Author),書籍的分類(Classify),書籍出版(Publish)
def orm(request):
單表
1、方式一:表.objects.create()
models.Publish.objects.create(name='浙江出版社', addr="浙江.杭州")
models.Classify.objects.create(category='武俠')
models.Author.objects.create(name='金庸',sex='男', age=89, university='東吳大學')
2、方式二:類實例化,obj = 類(屬性=XX) obj.save()
obj = models.Author(name='吳承恩', age=518, sex='男', university='龍溪學院')
obj.save()
一對多
1、方式一:表.objects.create(外鍵名_id=那個類的id)
models.Book.objects.create(title='笑傲江湖', price=200, date=1968, classify_id=6, publish_id=6)
2、方式二:類實例化,obj=類(屬性=X, 外鍵=obj) obj.save()
classify_obj = models.Classify.objects.get(category='武俠')
publish_obj = models.Publish.objects.get(name='河北出版社')
# 注意以上獲取得是和 book對象 向關聯的(外鍵)的對象
book_obj = models.Book(title='西遊記', price=234, date=1556, classify=classify_obj, publish=publish_obj)
book_obj.save()
多對多
如果兩表之間存在雙向1對N關係,就無法使用外鍵來描述其關係了;
只能使用多對多的方式,新增第三張表關係描述表;
book = models.Book.objects.get(title='笑傲江湖')
author1 = models.Author.objects.get(name='金庸')
author2 = models.Author.objects.get(name='張根')
book.author.add(author1, author2)
# 書籍和作者是多對多關係,
# 如果兩表之間存在多對多關係,例如書籍相關的所有作者對象集合,作者也關聯的所有書籍對象集合
# add() 添加
# clear() 清空
# remove() 刪除某個對象
return HttpResponse('OK')
刪除
修改
# 方式1:update()
models.Book.objects.filter(id=1).update(price=3)
# 方式2:obj.save()
book_obj = models.Book.objects.get(id=1)
book_obj.price=5
book_obj.save()
查找
def ormquery(request):
books = models.Book.objects.filter(id__gt=2, price__lt=100)
book = models.Book.objects.get(title__endswith='金') # 單個對象,沒有找到會報錯
book1 = models.Book.objects.filter(title__endswith='金').first()
book2 = models.Book.objects.filter(title__icontains='瓶').last()
# 一般:query_set 是對象集合 [對象1、對象2、.... ]
books = models.Book.objects.all()
# values:query_set 是字典集合 [{一條記錄},{一條記錄} ]
books = models.Book.objects.values(
'title','price',
'publish__name',
'date',
'classify__category', # 正向連表: 外鍵字段__對應表字段
'author__name', # 反向連表: 小寫表名__對應表字段
'author__sex', # 區別:正向 外鍵字段__,反向 小寫表名__
)
books = models.Book.objects.values('title','publish__name').distinct()
# exclude 按條件排除。。。
# distinct()去重,
# exits()查看數據是否存在? 返回 true 和false
a = models.Book.objects.filter(title__icontains='金').
return HttpResponse('OK')
一對多,多對多
1、一對多(ForeignKey)
使用時,通常定義在多的一方
# 背景:老師(一)、學生(多,外鍵字段名:teacher = modles.ForeignKey(Teacher,...))
# obj對象處理:id爲1的老師,有哪些學生?
teacher = Teacher.objects.get(id = 1) # 先獲取對象
# 查
# 方式一:
Student類中,外鍵字段有定義 related_name=’teacher_student’, 可以直接用
studentList = teacher.teacher_student.all()
# 方式二:
外鍵定義沒寫 related_name=’student_teacher’, 可以改寫成:
studentList = teacher.student_set.all() # 反向
# 增
# 方式一:create方式
teacher.student_set.create(name="tom", age=14)
# 方式二:obj通過使用add
student_obj = Student(name="tom", age=14)
teacher.student_set.add(student_obj)
# 刪
student_obj = teacher.student_set.get(name="tom")
student_obj.delete()
2、多對多(ManyToManyField)
特點:
1、遷移時,會自動生成一箇中間表(表示倆個表的對應關係)
2、增刪改查,同時也適用一對多,一對一,修改少量參數即可
from django.db import models
class Goods(models.Model): # 商品
g_name = models.CharField(max_length=20)
g_price = models.DecimalField(max_digits=5, decimal_places=2)
gc = models.ForeignKey("Category", null=True, on_delete=models.SET_NULL) # gc爲外鍵,一對多,類別表爲母表
class Category(models.Model): # 類別
c_name = models.CharField(max_length=20)
class Store(models.Model): # 商家
s_name = models.CharField(max_length=30)
s_detail = models.TextField(blank=True, null=True)
sc = models.ManyToManyField("Category") # 與類別表進行多對多關聯
查看
# 專業術語來講,多對多關係,多對多字段設置在那個表,那個表就是子表
# 查找指定商家下面的所有分類
# 方式一:正向查詢
Store.objects.get(s_name="商家C").sc.all() # 寫法:子表對象.子表多對多字段.過濾條件
(all()/filter())
<QuerySet [<Category: Category object>, <Category: Category object>]>
# 方式二:反向查詢
Category.objects.filter(store__s_name="商家C")
Out[25]: <QuerySet [<Category: Category object>, <Category: Category object>]> # 母表對象.filter(子表表名小寫__子表字段名="過濾條件")
# 從分類查詢,查看那些商家裏面發佈指定的某一個分類
# 方式一:
(Category.objects.get(c_name="電腦整機")).store_set.all() # 寫法:母表對象.子表表名小寫_set.過濾條件
<QuerySet [<Store: Store object>, <Store: Store object>]>
# 方式二:
Store.objects.filter(sc=Category.objects.get(c_name="電腦整機"))
<QuerySet [<Store: Store object>, <Store: Store object>]>
# 方式三:
Store.objects.filter(sc__c_name="電腦整機") # filter(子表外鍵字段__母表字段='過濾條件')
<QuerySet [<Store: Store object>, <Store: Store object>]>
# 方式四:
Store.objects.filter(sc=category) # filter得到QuerySet,寫法:filter(子表外鍵字段=母表主鍵對象),此處和一對多略有不同,是子表外鍵字段而不是外鍵字段_母表主鍵
<QuerySet [<Store: Store object>, <Store: Store object>]>
增加
# 普通添加(一對一)
# 添加商家
# 方式一:
Store.objects.create(s_name="商家A", s_detail="物美價廉,抄底折扣。。。。")
Out[2]: <Store: Store object>
# 方式二:
Store(s_name="商家B", s_detail="大促銷").save()
# 添加類別
Category.objects.create(c_name="電腦整機")
<Category: Category object>
Category(c_name="文具耗材").save()
# ---------------------------------------------------
# 總結:增與改(增添子表或母表數據參照一對一的增,多對多重點在於關係表的對應關係變更 - 中間表的對應關係)
# ---------------------------------------------------
# 多對多
# 創建商家C並添加全部分類(多對多添加時,add 追加對象,而Category.objects.all()是對象集合)
方式一:
Store.objects.create(s_name="商家C").sc.add(*(Category.objects.all())) # 如果商戶已存在則把create改成get
方式二:
store = Store.objects.get(s_name="商家C")
store.sc = (Category.objects.all())
store.save()
# ---------------------------------------------------
# 創建商家D添加指定分類
# 方式一:
store = Store.objects.create(s_name="商家D")
category = Category.objects.filter(c_name__in=["電腦整機","文具耗材"]) # 單個改成get,全部改成all
store.sc.add(*category) # add是追加模式,category是一個查詢集(對象集合)
# store.sc.clear() # 清空此商家的商品(其實就是清除了,中間表的對應關係)
# 方式二:
# 讓指定商品分類添加指定的商家,反向查詢
store = Store.objects.create(s_name="商家E")
category = Category.objects.get(c_name="電腦整機")
category.store_set.add(store)
# 效果與上面一樣
# ---------------------------------------------------
# 讓所有商家都添加這個分類
stores = Store.objects.all()
category = Category.objects.get(c_name="電腦整機")
category.store_set.add(*stores)
category.store_set.clear() # 讓所有商家去除這個分類,刪除的是這個類
category.store_set.all().delete() # 是刪除這個類的所有商家,刪除的是商家
# ---------------------------------------------------
# 總結
# 只有子表纔有"子表名小寫_set"的寫法,得到的是一個QuerySet集合(對象集合),後邊可以接.add(),.remove(),.update(),.delete(),.clear()
刪除
# 問題一:讓指定商家清空分類 (即,這個商家和所有分類表沒有關係了,面向的是商家)
s = Store.objects.get(s_name="商家C")
s.sc = ""
s.save()
s=Store.objects.get(s_name="商家C")
c = Category.objects.all() # 對象集合
s.sc.remove(*c)
s = Store.objects.get(s_name="商家C")
s.sc.clear()
# 刪除母表與子表關聯關係
# 問題二:讓所有商家去掉指定分類 (即,這個指定分類和所有商家表沒有關係了,面向的是指定分類)
s = Store.objects.all()
c = Category.objects.get(c_name="電腦整機")
c.store_set.remove(*s)
c = Category.objects.get(c_name="電腦整機")
c.store_set.clear()
# 刪除商家該子表數據
# 刪除所有指定分類的全部商家
c = Category.objects.get(c_name="電腦整機")
c.store_set.all().delete()
# 刪除所有商家 (對比下,區別理解)
Store.objects.all().delete()
bug坑點
我在多對多字段中,定義了related_name字段,導致role__id__in=role_ids,反向查詢使用“小寫表名__字段名”失效,報錯:無法解析role字段,即根本沒能找到Role的這個關聯表。
參考文件
多對多處理,首選看看:https://blog.csdn.net/maidou931019/article/details/74852536
多層級--跨表關係查詢,首選看看:https://blog.csdn.net/pushiqiang/article/details/81127442
很全面和詳細的,非常不錯的一篇:https://blog.csdn.net/qq_26870933/article/details/81563149
大牛神器
借鑑鏈接:
模型基礎--field--方法--ORM:https://code.ziqiangxuetang.com/django/django-models.html
自定義field:https://code.ziqiangxuetang.com/django/django-custom-field.html
ORM
參考鏈接:
https://code.ziqiangxuetang.com/django/django-queryset-api.html
https://code.ziqiangxuetang.com/django/django-queryset-advance.html