掌握DJango model數據表相關操作
分析思路,創建數據表
對於表操作,表之間的關聯關係,必須理解他們之間的關係,對於編程很重要。可以看看映射關係、外鍵和relationship查詢 ,至少明白外鍵相關基本知識。
(一)多表查詢
一對一:models.OneToOneField(to_field='id',to='Authordatil')
一對多:(外鍵設置唯一性)
models.ForeignKey(to='Publish',to_field='id')
多對多:自動生成第三張表
models.ManyToManyField(to='Author')
(二)創建表模型
作者與詳情 ( 一對一 )
書與作者( 多對多 )
出版社與書(一對多 )
出版社:id name add email
書: id name price publish
作者: id name sex authordatil
詳情: id photo address
models.py 文件,創建數據模型
from django.db import models
class Publish(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=100)
address=models.CharField(max_length=64)
email=models.EmailField()
def __str__(self):
return '%s,%s,%s'%(self.name,self.address,self.email)
class Author(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
choices=((0,'女'),(1,'男'))
sex=models.SmallIntegerField(choices,default=0) #數字整型
#作者與詳情:(一對一) to='AuthorDetail' 加引號,這個表能找到就可以,不用引號,類必須在上面定義
authordatil=models.OneToOneField(to_field='id',to='Authordatil',on_delete=models.CASCADE)
def __str__(self):
return self.name
class Authordatil(models.Model):
id=models.AutoField(primary_key=True)
photo=models.CharField(max_length=124)
address=models.CharField(max_length=64)
class Book(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
price=models.DecimalField(max_digits=5,decimal_places=2)
#出版社與書(一對多關係)外檢設置唯一性,關聯的表,關聯的字段
publish=models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE)
#書與作者關係是多對多關係
authors=models.ManyToManyField(to='Author')
-
id 字段是自動添加的
-
對於外鍵字段,Django 會在字段名上添加"_id" 來創建數據庫中的列名
-
外鍵字段 ForeignKey 有一個 null=True 的設置(它允許外鍵接受空值 NULL),你可以賦給它空值 None 。
標題添加/刪除/修改表記錄
1、一對多添加記錄
- 通過 _id 來添加記錄
直接添加Book,views中定義一個方法,簡單測試:
models.Book.objects.create(name='紅樓夢', price=20.0, publish_id=1)
return HttpResponse('成功插入一條Book記錄!')
看看控制檯,會報錯了
'Cannot add or update a child row: a foreign key constraint fails 初步判定主鍵約束錯誤,也就是說publish_id 對應的Publish不存在。那就先添加幾個Publish吧
views中定義一個方法:
def addPublish(request):
models.Publish.objects.create(name='北京出版社', address='北京', email='[email protected]')
models.Publish.objects.create(name='安徽出版社', address='安徽', email='[email protected]')
models.Publish.objects.create(name='人教版出版社', address='北京', email='[email protected]')
li=[]
for i in range(5):
li.append(models.Publish(name='新華出版社%s' % i, address='北京', email='[email protected]')) # 批量生成對象
models.Publish.objects.bulk_create(li)
return HttpResponse('成功插入Publish記錄!')
查看數據庫信息:
出版社Publish數據有了,現在繼續測試添加Book功能了。
def addBookById(request):
models.Book.objects.create(name='紅樓夢', price=20.0, publish_id=101)
return HttpResponse('成功插入一條Book記錄!')
查看數據庫數據,可以看到數據已經成功插入了。
簡單理解剛纔的問題:主鍵約束了之後,插入book前提是已經有了外鍵的數據,publish_id,也就是有一個Publish記錄,這樣纔可以插入Book記錄,且publish_id正好是Publish記錄中對應的一條記錄。
- 通過對象添加記錄
def addBookByPublish(request):
publish = models.Publish.objects.filter(pk=101).first()
models.Book.objects.create(name='紅樓夢', price=34.5, publish=publish)
return HttpResponse('通過對象插入一條記錄!')
首先得到一個publish對象,然後作爲參數直接插入到Book表中,看看數據庫信息。
# pk 表示主鍵,一旦主鍵改變,還是會找到對應的主鍵來獲取對象,如果通過主鍵查詢道德數據爲null,那麼表示不存在這個記錄,也就無法正常插入Book了。
2、一對多刪除記錄
def delBook(request):
models.Book.objects.filter(name='紅樓夢').first().delete()
return HttpResponse('刪除記錄!')
一對多修改記錄
-
通過queryset對象的update方法修改
-
通過對象的屬性修改,調用對象的save()方法保存
-
通過queryset對象的update方法修改
方式一:通過 _id 修改
def upDateBook(request):
models.Book.objects.filter(pk=4).update(name='西遊記', publish_id=102)
return HttpResponse('通過ID修改!')
修改前數據表Book信息
修改後信息如下
方式二:通過 對象修改修改
def upDateBookByPublish(request):
publish = models.Publish.objects.filter(pk=103).first()
models.Book.objects.filter(pk=4).update(name='東遊記',price=100.0, publish=publish)
return HttpResponse('通過對象修改!')
數據庫當前數據
- 通過對象的屬性修改,調用對象的save()方法保存
方式一:通過 _id 修改
def upDateBookByIDBook(request):
book = models.Book.objects.filter(pk=4).first()
book.publish_id = 104
book.price = 200.0
book.save()
return HttpResponse('upDateBookByIDBook!')
方式二:通過對象修改
def upDateBookBook(request):
book = models.Book.objects.filter(pk=4).first()
publish = models.Publish.objects.filter(pk=105).first()
book.publish = publish
book.save()
return HttpResponse('upDateBookBook!')
3、多對多增刪改記錄
-
多對多增加記錄
-
多對多刪除記錄
-
多對多清空記錄
-
多對多修改記錄
-
多對多增加記錄
先準備測試用的數據
(1)通過對象添加記錄
def addAuthorDetail(request):
models.Authordatil.objects.create(photo='www.baidu.com/author1.png', address='天上人間1包間')
models.Authordatil.objects.create(photo='www.baidu.com/author2.png', address='天上人間2包間')
models.Authordatil.objects.create(photo='www.baidu.com/author3.png', address='天上人間3包間')
models.Authordatil.objects.create(photo='www.baidu.com/author4.png', address='天上人間4包間')
return HttpResponse('添加AuthorDetail')
def addAuthor(request):
models.Author.objects.create(name='tom', sex=0,authordatil_id=1)
models.Author.objects.create(name='tony', sex=1,authordatil_id=2)
models.Author.objects.create(name='jack', sex=1,authordatil_id=3)
models.Author.objects.create(name='ant', sex=0,authordatil_id=4)
return HttpResponse('添加addAuthor')
之前庫中有一本書東遊記
現在就要爲這邊《東遊記》這本書添加作者
def addAuthorByBook(request):
# 爲紅樓夢這本書添加一個作者
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='東遊記').first()
tony = models.Author.objects.filter(name='tony').first()
jack = models.Author.objects.filter(name='jack').first()
book.authors.add(tom)
# 一次添加兩個作者,中間用逗號隔開
book.authors.add(tony, jack)
return HttpResponse('給書添加作者')
看數據庫數據表: bookapp_book_authors
(2)通過 id 添加記錄
直接上代碼
def addAuthorByBookById(request):
# 爲紅樓夢這本書添加一個作者
book = models.Book.objects.filter(name='東遊記').first()
# 一次添加兩個作者,中間用逗號隔開
book.authors.add(4)
return HttpResponse('addAuthorByBookById')
看看數據庫表
也就是說,得到了book之後,直接通過作者的id作爲參數,找到了作者,然後直接添加,內部django幫助封裝了一層其實。
- 多對多刪除記錄
remove() # 可以傳對象,可以傳id,可以傳多個
(1)通過對象刪除記錄
def delBookOfAuthor(request):
# 刪除東遊記作者名字是tom的作者
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='東遊記').first()
book.authors.remove(tom)
return HttpResponse('delBookOfAuthor')
可以看到,bookapp_book_authors表中的tom記錄已經刪掉了
(2)通過id刪除記錄
def delBookOfAuthorByID(request):
# 刪除東遊記作者id是3、4的兩個作者
book = models.Book.objects.filter(name='東遊記').first()
book.authors.remove(3,4)
return HttpResponse('delBookOfAuthorByID')
- 多對多清空記錄
clear() # 沒有參數
# 刪除東遊記作者id是3、4的兩個作者
book = models.Book.objects.filter(name='東遊記').first()
book.authors.clear()
return HttpResponse('delBookOfAllAuthor')
- 多對多修改記錄
set() # 先清空在增加,必須傳列表,列表裏面可以是對象,可以是id
(1)通過對象修改記錄
def updateBookAuthor(request):
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='東遊記').first()
book.authors.set([tom, ])
return HttpResponse('updateBookAuthor')
(2)通過id修改記錄
def updateBookAuthorID(request):
# 修改東遊記作者爲作者id是3、4的作者
book = models.Book.objects.filter(name='東遊記').first()
book.authors.set([3,4 ])
return HttpResponse('updateBookAuthorID')
四、基於對象的跨表查詢–多次查詢、子查詢
正向查詢和反向查詢
正向查詢:關聯字段在從表,由從表查詢主表中的數據 -----> 按字段查詢
反向查詢:關聯字段在從表,由主表查詢從表中的數據 -----> 按表名小寫查詢
1、一對一基於對象的跨表查詢
正向:正向查詢按 字段
反向:反向查詢按 表名小寫
def findBookAndPublish(request):
# 1.正向 查詢東遊記這本書的出版社郵箱
book = Book.objects.filter(name='東遊記').first()
# book.publish 就是出版社對象
pulish = book.publish
print(pulish.email)
# 2.反向 查詢地址是北京的出版社出版的圖書
publish = Publish.objects.filter(address='北京').first()
# publish.book_set.all() 拿出所有的圖書
books = publish.book_set.all()
# 統計一下條數
books = publish.book_set.all().count()
print(books)
return HttpResponse('findBookAndPublish')
結果:
itjavawfc@163.com
0
2、多對多基於對象的跨表查詢
正向:正向查詢按 字段.all()
反向:反向按 表名小寫_set.all()```
```python
def findBookAndPublishMoreToMore(request):
# 1.查詢紅樓夢這本書所有的作者
book = Book.objects.filter(name='東遊記').first()
book.authors.all() # 是所有的作者,是一個queryset對象,可以繼續點
print(book.authors.all())
# 2.查詢lqz寫的所有書
lqz = Author.objects.filter(name='jack').first()
books = lqz.book_set.all()
print(books)
return HttpResponse('findBookAndPublishMoreToMore')
<QuerySet [<Author: jack>, <Author: ant>]>
<QuerySet [<Book: Book object (4)>]>
五、基於雙下劃線的跨表查詢
1、一對一的基於雙下劃線的跨表查詢
正向:按 字段,跨表可以在filter,也可以在values中
反向:按 表名小寫,跨表可以在filter,也可以在values中
def findBookTyp1(request):
# 1.查詢tom作者的照片 正向查詢 跨表的話,按字段
# 以author表作爲基表
ret = Author.objects.filter(name='tom').values('authordatil__photo')
print(ret)
# 2.以authordetail作爲基表 反向查詢,按表名小寫 跨表的話,用表名小寫
ret = Authordatil.objects.filter(author__name='tom').values('photo')
print(ret)
return HttpResponse('findBookTyp1')
打印結果:
<QuerySet [{'authordatil__photo': 'www.baidu.com/author1.png'}]>
<QuerySet [{'photo': 'www.baidu.com/author1.png'}]>
2、多對多的基於雙下劃線的跨表查詢
正向:按 字段,跨表可以在filter,也可以在values中
反向:按 表名小寫,跨表可以在filter,也可以在values中
def findBookTyp2(request):
# 查詢東遊記的所有作者名字
# 1.以Book爲基表
ret = Book.objects.filter(name='東遊記').values('authors__name')
print(ret)
# 2.以Author爲基表
ret = Author.objects.filter(book__name='東遊記').values('name')
print(ret)
return HttpResponse('findBookTyp2')
<QuerySet [{'authors__name': 'jack'}, {'authors__name': 'ant'}]>
<QuerySet [{'name': 'jack'}, {'name': 'ant'}]>
3、連續跨表查詢
一直用雙下劃線 __ 獲取字段
def findBookTyp3(request):
# 查詢東遊記這本書所有的作者的照片
book = Book.objects.filter(name='東遊記').first()
authors = book.authors.all()
for author in authors:
authordatil = author.authordatil
print(authordatil.photo)
# 方法二,使用連續跨表
ret = Book.objects.filter(name='東遊記').values('authors__authordatil__photo')
print(ret)
return HttpResponse('findBookTyp3')
結果:
www.baidu.com/author3.png
www.baidu.com/author4.png
<QuerySet [{'authors__authordatil__photo': 'www.baidu.com/author3.png'}, {'authors__authordatil__photo': 'www.baidu.com/author4.png'}]>