一篇文章帶你了解Django ORM操作(基礎(chǔ)篇)
前言
在日常開發(fā)中,需要大量對數(shù)據(jù)庫進(jìn)行增刪改查操作。
如果頭鐵的話,使用原生SQL是最好的,畢竟性能又高,又靈活。
但是通常情況下,我們不是太需要那么苛刻的性能,也沒有那么多刁鉆的需求用原生SQL
通常會使用簡單快捷的ORM進(jìn)行增刪改查
一起看學(xué)習(xí)一下Django的ORM操作吧
表結(jié)構(gòu)設(shè)計
還是從實(shí)際角度出發(fā)。
假設(shè),現(xiàn)在我需要設(shè)計一個簡單的圖書管理系統(tǒng),是那種買的書,不是圖書館的書!!!
我想了想,首先,肯定有一個圖書表,專門存放圖書的信息,最起碼是這樣的。
但是又想了想,似乎我的書想發(fā)布,肯定是需要一個出版社幫我發(fā)布的,我肯定不能自己發(fā)布所以是這樣子的。
又想了想,書肯定是人寫的,肯定要有作者,所以還需要一個作者表,應(yīng)該是這樣子的。
又想了想,這一本書如果讓一般人編,難度有點(diǎn)大啊,一般都是多人一起完成的,所以大概還有這樣一張表。
其實(shí),上述漏點(diǎn)了一個東西,圖書需要?dú)w屬一個出版社的,所以,最終表結(jié)構(gòu)應(yīng)該是這樣的!
Django models代碼
- from django.db import models
- # 作者表
- class Author(models.Model):
- name = models.CharField(verbose_name="作者姓名", max_length=8)
- age = models.IntegerField(verbose_name="作者年齡")
- phone = models.CharField(verbose_name="作者聯(lián)系方式", max_length=11)
- # 出版社
- class Publish(models.Model):
- title = models.CharField(verbose_name="出版社名稱", max_length=16)
- phone = models.CharField(verbose_name="出版聯(lián)系方式", max_length=11)
- # 圖書
- class Book(models.Model):
- title = models.CharField(verbose_name="書名", max_length=32)
- price = models.DecimalField(verbose_name="價格", max_digits=5, decimal_places=2)
- PublishDate = models.DateField(verbose_name="初版日期")
- publish = models.ForeignKey(to=Publish, verbose_name="所屬出版社", on_delete=models.CASCADE)
- # 圖書Many作者
- class BookManyAuthor(models.Model):
- book = models.ForeignKey(to=Book, verbose_name="所屬圖書", on_delete=models.CASCADE)
- author = models.ForeignKey(to=Author, verbose_name="所屬作者", on_delete=models.CASCADE)
Mysql.sql
數(shù)據(jù)同上述Excel圖一致!
- web_author.sql
- web_book.sql
- web_bookmanyauthor.sql
- web_publish.sql
查詢操作
本次采用單獨(dú)使用Django ORM的方式,不需要將Django運(yùn)行起來,所以也不需要寫url什么的了!
前置導(dǎo)入
- import os
- import django
- # django_orm_demo為我的項(xiàng)目名稱
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_orm_demo.settings")
- django.setup()
- # 導(dǎo)入models一定要在 django.setup() 之后
- from web import models
查詢所有(all)
語法
- models.<模型類>.objects.all()
例如:查詢所有作者
- author_list = models.Author.objects.all()
- print(author_list)
執(zhí)行結(jié)果
例如:查詢所有圖書,并且遍歷詳情
- book_list = models.Book.objects.all()
- for book in book_list:
- print(book.title, book.price, book.PublishDate, book.publish)
執(zhí)行結(jié)果
查詢指定條件(filter)
語法
- models.<模型類>.objects.filter(<條件>)
例如:查詢張三的信息
- author = models.Author.objects.filter(name="張三")
- print(author)
- print(author.name)
執(zhí)行結(jié)果
似乎你發(fā)現(xiàn)了個錯誤,'QuerySet' object has no attribute 'name'。
這是因?yàn)閒ilter(<條件>)查詢出來的,可能不止一個值,就像name=張三,可能有很多張三!
所以獲取的是一個列表,注意第一個紅色圈圈,如果我明明知道就是一個值,也就像取第一個值,咋辦?
first
通過first,拿到的就是第一個值,同時也是模型類對象
代碼
- author = models.Author.objects.filter(name="張三").first()
- print(author,type(author))
- print(author.name,author.phone)
執(zhí)行結(jié)果
filter支持多條件
假設(shè)有倆張三
如果我想取第二個張三咋辦?
要是能寫倆條件就好了比如這樣name=張三 and age=22。
注:filter后面只能跟filter或者first,filter里面的條件都是and查詢
代碼
- # filter里面多個條件是and查詢
- author = models.Author.objects.filter(name="張三",age=22).first()
- print(author,type(author))
- print(author.name,author.phone)
執(zhí)行結(jié)果
常用filter條件列表
熟悉Mysql的可能都知道,有=,<,<=,like等各種范圍查詢,同樣,Django也同樣支持!
filter通過__來構(gòu)造條件
- # 包含三
- 字段__contains="三" # 原生SQL條件:where 字段 like "%三%"
- # 以三開頭
- 字段__startswith="三" # 原生SQL條件:where 字段 like "三%"
- # 以三結(jié)尾
- 字段__startswith="三" # 原生SQL條件:where 字段 like "%三"
- # 為空
- 字段__isnull=True # 原生SQL條件:where 字段 IS NULL
- # 不為空
- 字段__isnull=False # 原生SQL條件:where 字段 IS NOT NULL
- # in
- 字段__in=[1,2,3] # 原生SQL條件:where 字段 IN (1, 2, 3)
- # >
- 字段__gt=1 # 原生SQL條件:where 字段 > 1
- # >=
- 字段__gte=1 # 原生SQL條件:where 字段 >= 1
- # <
- 字段__lt=1 # 原生SQL條件:where 字段 < 1
- # <=
- 字段__lte=1 # 原生SQL條件:where 字段 <= 1
- # 日期字段,年
- 日期字段__year=2020 # 原生SQL條件:where 日期字段 BETWEEN 2020-01-01 AND 2020-12-31
- # 日期字段,月
- 日期字段__month=3 # 原生SQL條件:where EXTRACT(MONTH FROM 表名.日期字段) = 3
- # 日期字段,天
- 日期字段__day=4 # 原生SQL條件:where EXTRACT(DAY FROM 表名.日期字段) = 4
- # 時間比大小,|為或的意思
- 日期字段__gt|lt|...="2020-10-10" # 原生SQL條件:where 日期字段 > 2020-10-10
- # 比大小還可以是時間類型
- import datetime
- 日期字段__gt|lt|...=datetime.date(2020,10,10)# 同上
- # 時間范圍篩選
- 日期字段__range=("2020-01-01","2020-06-01") # 原生SQL條件:where 時間字段 BETWEEN 2020-01-01 AND 2020-06-01
- 日期字段__range=(datetime.date(2020,1,1),datetime.date(2020,6,1)) # 同上
get
其實(shí)當(dāng)我們只需要獲取一個值時,還可以使用get。
代碼
- author = models.Author.objects.get(name="李四")
- print(author,type(author))
- print(author.name,author.phone)
執(zhí)行結(jié)果
但是這個get不太推薦使用,原因如下
- 如果get條件獲取了倆或倆以上的值,會報錯。
- 如果get條件獲取不到值,還是會報錯。
示例代碼
- author = models.Author.objects.get(name="張三")
- # error:get() returned more than one Author -- it returned 2!
- author = models.Author.objects.get(name="不存在")
- # error:Author matching query does not exist.
- author = models.Author.objects.filter(name="不存在").first()
- # 結(jié)果:None
所以,推薦使用filter,如果確定只有一條,那就filter().first(),如果需要多條,遍歷即可!
query
在某些特殊情況下,我們可能對于查詢的結(jié)果感到有些意外!
可能需要看看原生SQL是啥,這時候需要用到query。
注:query只能用在filter()后面。
代碼
- sql = models.Author.objects.filter(name="李四").query
- print(sql)
執(zhí)行結(jié)果
總結(jié)
本篇通過一個類似實(shí)際的需求,進(jìn)行了一個表結(jié)構(gòu)設(shè)計。
有書表,出版社表,作者表,圖書和作者多對多表。
以這幾張表為例,進(jìn)行Django ORM的學(xué)習(xí)。
學(xué)習(xí)了如何查詢所有,如何條件查詢,filter常用條件有哪些。
get和filter().first()區(qū)別,如何通過query進(jìn)行查看原生SQL。
如果在操作過程中有任何問題,記得下面留言,我們看到會第一時間解決問題。
用微笑告訴別人,今天的我比昨天強(qiáng),今后也一樣。
本文轉(zhuǎn)載自微信公眾號「 Python爬蟲與數(shù)據(jù)挖掘」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 Python爬蟲與數(shù)據(jù)挖掘公眾號。