1. 程式人生 > 實用技巧 >Python學習第149天(Django之模型層1)

Python學習第149天(Django之模型層1)

一.ORM 中常用欄位和引數

1.常用欄位

AutoField

自增列,可以將其理解為ID主鍵欄位,注意的是必須填入引數 primary_key=True
當model中如果沒有自增列,則自動會建立一個列名為id的列

id = models.AutoField(primary_key=True)

IntegerField

整形欄位,圍在 -2147483648 to 2147483647。(一般不用它來存手機號(位數也不夠),直接用字串存,)

kucun = models.IntegerField()  # 可以不指定引數

CharField

字元欄位,必須提供max_length引數, max_length表示字元長度。

title = models.CharField(max_length=255)
# 注意:Django中的CharField對應的MySQL資料庫中的varchar型別

DecimalField

小數字段,必須提供max_digits引數和decimal_places引數
price = models.DecimalField(max_digits=8,decimal_places=2)

DateField

日期欄位,日期格式 YYYY-MM-DD,相當於Python中的datetime.date()例項。

publish_date = models.DateField(auto_now_add=True)

DateTimeField

日期時間欄位,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()例項。

2.欄位引數

verbose_name

 給欄位命名

null

用於表示某個欄位可以為空。null=True 

unique

如果設定為unique=True 則該欄位在此表中必須是唯一的 

db_index

如果db_index=True 則代表著為此欄位設定索引

default

為該欄位設定預設值

關於時間引數

1.auto_now_add
配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫。

2.auto_now
配置上auto_now=True,每次更新資料記錄的時候會更新該欄位。

3.關係欄位

1.ForeignKey

外來鍵型別在ORM中用來表示外來鍵關聯關係,一般把ForeignKey欄位設定在 '一對多''多'的一方。
ForeignKey可以和其他表做關聯關係同時也可以和自身做關聯關係。

欄位引數

1.to 設定要關聯的表
publish = models.ForeignKey(to='Publish')  # 預設是跟publish表的主鍵欄位做的一對多外來鍵關聯

2.to_field
設定要關聯的表的欄位

3.on_delete
當刪除關聯表中的資料時,當前表與其關聯的行的行為。

2.OneToOneField

通常一對一欄位用來擴充套件已有欄位。(通俗的說就是一個人的所有資訊不是放在一張表裡面的,簡單的資訊一張表,隱私的資訊另一張表,之間通過一對一外來鍵關聯)
ps:可以用 ForeignKey(unique=True) 代替

欄位引數

1.to
設定要關聯的表。
author_detail = models.OneToOneField(to='AuthorDetail')

2.to_field
設定要關聯的欄位。

3.on_delete
當刪除關聯表中的資料時,當前表與其關聯的行的行為。

ManyToManyField

多對多欄位
# 是虛擬欄位,表中不會顯式,
作用:
1.告訴orm自動建立第三種表
2.幫助orm跨表查詢

authors = models.ManyToManyField(to='Author')

二.表操作

表操作之 欄位增刪改查

當一張表已經創建出來之後 後續還想新增欄位,可以有兩種方式

(1)給新增的欄位設定預設值

addr = models.CharField(max_length=32,default='China')  # default該欄位預設值

(2)給新增的欄位設定成可以為空

age = models.IntegerField(null=True)  # 該欄位允許為空

刪除欄位 直接在models.py中註釋該欄位 然後重新執行兩條命令即可注意:執行完之後 表中該欄位所對應的所有的資料全部刪除並且一般情況下 基本是不會用到真正意義上的刪除

1.表操作之 單表

查:必知必會13條

<1> all(): 查詢所有結果

<2> filter(**kwargs): 它包含了與所給篩選條件相匹配的物件

<3> get(**kwargs): 返回與所給篩選條件相匹配的物件,返回結果有且只有一個,如果符合篩選條件的物件超過一個或者沒有都會丟擲錯誤

<4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的物件

<5> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,執行後得到的並不是一系列model的例項化物件,而是一個可迭代的字典序列

<6> values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列

<7> order_by(*field): 對查詢結果排序

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

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

<10> count(): 返回資料庫中匹配查詢(QuerySet)的物件數量。

<11> first(): 返回第一條記錄

<12> last(): 返回最後一條記錄

<13> exists(): 如果QuerySet包含資料,就返回True,否則返回False

總結
# 返回QuerySet物件的方法有
all()
​
filter()
​
exclude()
​
order_by()
​
reverse()
​
distinct()
​
# 特殊的QuerySet
values()       返回一個可迭代的字典序列
​
values_list() 返回一個可迭代的元祖序列
​
# 返回具體物件的
get()
​
first()
​
last()
​
# 返回布林值的方法有:
exists()
​
# 返回數字的方法有
count()

查:雙下劃線

1.大於/小於
models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
2.in
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於11、22、33的資料
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
3.模糊查詢
models.Tb1.objects.filter(name__contains="ven")  # 獲取name欄位包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
4.範圍
models.Tb1.objects.filter(id__range=[1, 3])      # id範圍是1到3的,等價於SQL的bettwen and
5.以什麼開頭 以什麼結尾
欄位__startswith  欄位__endswith
6.按年查詢
models.Class.objects.filter(create_time__year=2017)  # date欄位可以通過在其後加__year,__month,__day等來獲取date的特點部分資料

<1> create()

1.create方法能夠新增資料 並且有一個返回值
2.返回值就是新增的資料物件本身
res = models.User.objects.create(username=username,password=password)
# insert into user(username,password) values(username,password)
print(res)  >>> User object
print(res.password)
print(res.username)

<2> 物件方法

user_obj = models.User(username=username, password=password)
user_obj.save()

models.User.objects.filter(條件).delete()
# delete from user where id = delete_id;
ps: querySet 物件可以用.delete() 方法

<1> update()

models.User.objects.filter(id=edit_id).update(username=username,password=password)
# update user set username = username,password = password where id = edit_id
"""
filter拿到是一個列表   filter操作其實都是批量操作
如果filter結果列表中有多個數據 那麼會一次性全部修改 
類似於for迴圈一個個修改
"""
ps: querySet 物件可以用.update() 方法

<2> 物件方法

edit_obj.username = username
edit_obj.password = password
edit_obj.save()
"""
第二種方式會從頭到尾將所有的欄位全部修改一遍  效率極低,不推薦使用
"""

2.表操作之 多表

<1>.一對多 表關係的增刪改

# 一對多 欄位資料的增刪改查
    # 增
    # 1 傳出版社的id數字
    models.Book.objects.create(title='三國演義', prince=189.99, publish_id=1)
    # 2 傳出版社物件
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='紅樓夢', prince=999.99, publish=publish_obj)
​
    # 改
    # 1 傳出版社的id數字
    models.Book.objects.filter(pk=1).update(publish_id=3)
    # 2 傳出版社物件
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)
​
    # 刪
    models.Publish.objects.filter(pk=2).delete()  # 預設級聯更新級聯刪除

<1>.多對多 表關係的增刪改

 # 多對多表關係 欄位資料的增刪改
    # 增 給主鍵為1的書籍新增兩個作者
    # 1 傳作者的id數字
    book_obj = models.Book.objects.filter(pk=1).first()
    print(book_obj.authors)  # 物件點選多對多虛擬欄位 會直接跨到多對多的第三張表
    book_obj.authors.add(1)
    book_obj.authors.add(2, 3)
    # 2 傳作者物件
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.add(author_obj)
    book_obj.authors.add(author_obj1,author_obj2)
​
    """
       add()
       是給書籍新增作者,括號內既可以傳數字也可以傳物件
       並且支援一次性傳多個,逗號隔開即可
       """
​
    # 改 將主鍵為1的書籍物件 作者修改為2,3
    # 1 傳作者的id數字
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.set([2,])
    book_obj.authors.set([2,3])
    # 2 傳作者物件
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.set([author_obj,])
    book_obj.authors.set([author_obj, author_obj1, author_obj2])
​
    """
    set()括號內,需要傳一個可迭代物件 
    可迭代物件中,可以是多個數字組合
    也可以是多個物件組合
    但是不要混著用!!!
    """
​
    # 刪
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(3)
    book_obj.authors.remove(1,2)
    author_obj = models.Author.objects.filter(pk=1).first()
    author_obj1 = models.Author.objects.filter(pk=2).first()
    author_obj2 = models.Author.objects.filter(pk=3).first()
    book_obj.authors.remove(author_obj)
    book_obj.authors.remove(author_obj1,author_obj2)
    """
        remove()括號內既可以傳數字 也可以傳物件 
        並且支援傳對個 逗號隔開即可
        """
​
    # 將某本書跟作者的關係全部清空
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear()  # 清空當前書籍與作者的所有關係
    """
       add()
       set()
       remove()
       上面三個都支援傳數字 或者物件 並且可以傳多個 但是set需要傳可迭代物件
​
       clear()
       clear括號內不需要傳任何引數
       """

<3>跨表查詢

正向與反向的概念

# 一對一
    # 正向:author表--->關聯欄位在author表裡--->authordetail表      按欄位
    # 反向:authordetail表--->關聯欄位在author表裡--->author表      按表名小寫
    
      
    # 一對多
    # 正向:book表--->關聯欄位在book表裡--->publish表       按欄位
    # 反向:publish表--->關聯欄位在book表裡--->book表       按表名小寫_set.all() 因為一個出版社對應著多個圖書
    
    # 多對多
    # 正向:book表--->關聯欄位在book表裡--->author表        按欄位
    # 反向:author表--->關聯欄位在book表裡--->book表        按表名小寫_set.all() 因為一個作者對應著多個圖書
    
    
    正向查詢按外來鍵欄位
    反向查詢按表名小寫
    """
    基於物件的跨表查詢(子查詢:將一張表的查詢結果當做另外一個查詢語句的條件)
    """
    強調:在書寫orm語句的時候 跟寫sql語句一樣 
    不要嘗試著 一次性寫完  應該做到寫一點看一點再一點

基於物件的跨表查詢

1.正向
# 查詢書籍id是1 的出版社名稱
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish.name)  # 物件點外來鍵欄位直接跳到對應的表裡
2.反向
# 查詢出版社是東方出版社出版的書籍
publish_obj = models.Publish.objects.filter(name='東方出版社').first()
# print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())
# 總結
"""
    當你反向查詢的結果是多個的時候,就需要 表名_set.all()
    否則直接表明小寫即可
"""

基於雙下劃線的查詢(連表操作)

本質:  left join
inner join
right join
union
# 查詢xiongda作者的手機號
1.正向
res=models.Author.objects.filter(name='xiongda').values('author_detail__phone','author_detail__addr')
print(res)
(解釋:author_detail 是 Author表中關聯AuthorDetail表的外來鍵欄位(外來鍵欄位可以理解為就是被關聯表中的一行資料即一條記錄)
author_detail__phone 就是拿到了xiongda對應在AuthourDetail表中的那條記錄裡的phone欄位的值) 2.反向 res1 = models.AuthorDetail.objects.filter(author__name='xiongda').values('phone') print(res1)

聚合查詢(aggregate)

# 統計所有書的總價格
from django.db.models import Max,Min,Count,Avg,Sum
​
res = models.Book.objects.aggregate(Sum('price'))
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5=models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price'))

分組查詢(annotate)

from django.db.models import Max, Min, Count, Avg, Sum
​
# 統計每一本書的作者個數
res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num','title')
​
# 統計出每個出版社賣的最便宜的書的價格
res = models.Publish.objects.annotate(mmp =Min('book__price')).values('name','mmp')
​
# 統計不止一個作者的圖書
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
​
ps: models 後面跟的是什麼就按什麼分組

F 查詢

F查詢的本質就是從資料庫中獲取某個欄位的值
"""
之前查詢等號後面的條件都是我們人為輸入的
現在變成了需要從資料庫中獲取資料放在等號後面,實現了動態比較的效果
"""

from django.db.models import F
​
# 查詢庫存數量大於賣出數量的書
res = models.Book.objects.filter(kucun__gt=F('maichu'))
​
# 將書籍庫存數全部增加1000
models.Book.objects.update(kucun=F('kucun')+1000)
​
# 把所有書名後面加上'新款'
from django.db.models.functions import Concat
from django.db.models import Value
​
ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
models.Book.objects.update(title = F('title')+'新款')  # 不能這麼寫

Q 查詢

filter() 等方法中逗號隔開的條件是與的關係。 如果你需要執行更復雜的查詢(例如OR語句),你可以使用Q物件。
| 代表或的關係
~ 是取反

from django.db.models import Q
​
# 查詢 賣出數大於100 或者 價格小於100塊的
models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100))
​
# 查詢 書名不是 三國演義的書 或者 價格等於444元的
models.Book.objects.filter(~Q(title='三國演義')|Q(price=444))
​
# Q高階用法
    q = Q()
    q.connector = 'or'  # 修改查詢條件的關係   預設是and
    q.children.append(('title__contains','三國演義'))  # 往列表中新增篩選條件
    q.children.append(('price__gt',444))  # 往列表中新增篩選條件
    res = models.Book.objects.filter(q)  # filter支援你直接傳q物件  但是預設還是and關係
    print(res)

還是喜歡大螢幕寫東西!!!