Django--ORM--增刪改查

一、創建模型類

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章