介紹
基本概括
- 一對多:models.ForeignKey(其他表)
- 多對多:models.ManyToManyField(其他表)
- 一對一:models.OneToOneField(其他表)
當你去調用它們時。關系如下:
第一個參數:模型,模型名(str)
第二個參數:是與主表與從表的關系。
- CASCADE 級聯,刪除主表數據時連通一起刪除外鍵表中數據
- PROTECT 保護,通過拋出ProtectedError異常,來阻止刪除主表中被外鍵應用的數據
- SET_NULL 設置為NULL,僅在該字段null=True允許為null時可用
- SET_DEFAULT 設置為默認值,僅在該字段設置了默認值時可用
- SET() 設置為特定值或者調用特定方法
- DO_NOTHING 不做任何操作,如果數據庫前置指明級聯性,此選項會拋出IntegrityError異常
注意事項
1.id字段不寫的話會自動添加
2.對於外鍵字段,Django會在字段名上添加"_id"來創建數據庫中的列名
3.外鍵字段ForeignKey有一個null=True的設置,你可以賦給它空值None
文章參考:http://www.py3study.com/Article/details/id/1562.html
一對一
OneToOneField
定義模型
作者與作者詳細,可以看成一對一的關系。
class Author(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() gender = models.CharField(max_length=30) class AuthorDetail(models.Model): address = models.CharField(max_length=50) phone = models.IntegerField() author = models.OneToOneField('Author',models.CASCADE,default='')
創建數據
創建作者
from my_app import models author = models.Author.objects data = { 'name':'kidd', 'age':18, 'gender':'男' } author.create(**data)
創建作者詳細
第一種
from my_app import models author = models.Author.objects.filter(id=1)[0] detail = models.AuthorDetail.objects data = { 'address':'青島市', 'phone':12345, 'author':author } detail.create(**data)
第二種
from my_app import models detail = models.AuthorDetail.objects data = { 'address':'青島市', 'phone':54321, 'author_id':1 } detail.create(**data)
如果不知道author_id從哪來的,建議先看注意事項。
跨表查詢
基於對象
返回類型:str
正向查詢
通過作者姓名查詢詳細地址
from my_app import models author = models.Author.objects.filter(name='kidd')[0] author_address = author.authordetail.address
反向查詢
通過手機號查詢作者姓名
from my_app import models detail = models.AuthorDetail.objects.get(phone=54321) author = detail.author.name
基於下划線
返回類型:QuerySet
正向查詢
from my_app import models address = models.Author.objects.filter(name='kidd').values('authordetail__address')
反向查詢
from my_app import models author = models.AuthorDetail.objects.filter(author__name='kidd').values('address')
一對多
ForeignKey
定義模型
出版社可以出不同的書。
class Publish(models.Model): name = models.CharField(max_length=50) city = models.CharField(max_length=50) class Book(models.Model): title = models.CharField(max_length=50) price = models.IntegerField() publish = models.ForeignKey(Publish,models.CASCADE)
創建數據
創建出版社
from my_app import models data = { 'name':'清X', 'city':'北京', } models.Publish.objects.create(**data)
創建書
第一種
from my_app import models obj = models.Publish.objects.get(id=1) data = [ { 'title':'九陽真經', 'price':68, 'publish':obj }, { 'title':'易筋經', 'price':66, 'publish':obj } ] for value in data: models.Book.objects.create(**value)
第二種
from my_app import models data = [ { 'title':'正骨內經', 'price':99, 'publish_id':1 }, { 'title': '太玄經', 'price': 89, 'publish_id': 1 }, ] for value in data: models.Book.objects.create(**value)
跨表查詢
基於對象
正向查詢
查看書從哪個城市出版
from my_app import models book = models.Book.objects.filter(id=2).first() city = book.publish.city
反向查詢
查看出版社出版的所有書名
from my_app import models publish = models.Publish.objects.filter(id=1).first() books = publish.book_set.all() for book in books: print(book.title)
基於下划線
正向查詢
from my_app import models city = models.Book.objects.filter(id=2).values('publish__city') print(city)
反向查詢
from my_app import models books = models.Publish.objects.filter(id=1).values('book__title') for book in books: print(book.get('book__title'))
多對多
ManyToManyField
定義模型
作者跟書之間存在多對多的關系,一個作者可以創建好幾本書,一本書可以有好幾個作者。
class Author(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() gender = models.CharField(max_length=30) class Book(models.Model): title = models.CharField(max_length=50) price = models.IntegerField() authors = models.ManyToManyField(Author)
當你遷移完數據后,你會發現多了一張表,而這樣表是Django自動創建的。我的這站表名為:my_app_book_authors
創建數據
創建作者
from my_app import models persons = [ { 'name': '小明', 'age':28, 'gender':'男' }, { 'name': '小紅', 'age': 26, 'gender': '女' }, { 'name': '小軍', 'age': 28, 'gender': '男' }, ] for person in persons: models.Author.objects.create(**person)
創建書
from my_app import models book = models.Book.objects.create(title='學不會的數學',price=99) persons = models.Author.objects.filter(id__lt=5) book.authors.add(*persons)
上面創建方式因為是從book中進行創建的,因為在Book中有author對象。
如果想要在作者中創建,即沒有ManyToManyField,可以加:模型名__set
關系表:
現在我想把:作者id=3,書名 學不會的數學且價格為99從關系表中刪除。
from my_app import models book = models.Book.objects.filter(title='學不會的數學',price=99).first() author = models.Author.objects.filter(id=3).first() book.authors.remove(author)
更多
# 清空被關聯對象集合,無需傳參 book.authors.clear() # 先清空再設置,傳遞的參數必須是可迭代對象,一般為列表,列表內可以是對象,也可以是id book.authors.set()
跨表查詢
基於對象
正向查詢
從書中查找所有作者
from my_app import models books = models.Book.objects.filter(title='學不會的數學')[0] books = books.authors.all() for book in books: print(book.name)
反向查詢
查看作者寫的書
from my_app import models authors = models.Author.objects.get(id=1) authors = authors.book_set.all() for author in authors: print(author.title)
基於下划線
正向查詢
按字段
from my_app import models authors = models.Book.objects.filter(title='學不會的數學').values('authors__name') for author in authors: print(author.get('authors__name'))
反向查詢
按表名
from my_app import models authors = models.Author.objects.filter(book__title='學不會的數學').values('name') for author in authors: print(author.get('name'))
多對多(手動)
當我們使用Django自帶的ManyToManyField時,它會自動的創建第三張表。這里我們將手動創建
class Person(models.Model): name = models.CharField(max_length=64)
class Hobby(models.Model): title = models.CharField(max_length=64)
class PH_Key(models.Model): person = models.ForeignKey(Person,models.CASCADE) hobby = models.ForeignKey(Hobby,models.CASCADE) class Meta: unique_together = ['person','hobby'] # 保證值唯一
from my_app import models person = models.Person.objects hobby = models.Hobby.objects ph_key = models.PH_Key.objects ph_key.create(person=person.get(id=1),hobby=hobby.get(id=1))
當你再去創建一樣的時,會報錯。因為加了值唯一。
不建議這么去用,還是用Django自帶的吧。
聚合查詢
語法
aggregate(*args,**kwargs)
是QuerySet中的一個方法。
使用
需要函數,一塊聯合用應。
算出下圖的平均值,總和。
from django.db.models import Avg,Sum from my_app import models # 使用默認鍵名 result = models.Person.objects.all().aggregate(Avg('age'),Sum('age')) # 自定義鍵名 result = models.Person.objects.all().aggregate(avg=Avg('age'),sum=Sum('age'))
更多函數
1.expression 引用模型字段的一個字符串,或者一個query expression 2.output_field 用來表示返回值的model field,一個可選的參數 3.extra 關鍵字參數可以給聚合函數生成的SQL提供額外的信息 4.Avg 返回給定表達式的平均值,它必須是數值,除非指定不同的output_field 5.Count 返回與expression相關的對象的個數,有一個可選的參數distinct,如果distinct=True,那么Count將只計算唯一的實例,默認值是False 6.Max 返回給定字段的最大值 7.Min 返回給定字段的最小值 8.Sum 返回給定字段的總和
分組查詢
語法
annotate(*args,**kwargs)
也是QuerySet中的一個方法。
使用
當然,他也需要與函數聯合使用。這可能是個糟糕的例子。
如下圖:從名字相同中,找出最大年齡。
from django.db.models import Max from my_app import models result = models.Person.objects.all().values('name').annotate(max=Max('age'))
小結
# values在annotate()之前,表示group by。之后,表示為取值 # filter在annotate()之前,表示過濾。之后,表示having
F查詢
注意:只能對數值進行操作。
將上面的圖,繼續拿下來使用。
現在我想將他們的年齡全部加2歲。
from django.db.models import F from my_app import models models.Person.objects.all().update(age=F('age')+2)
Q查詢
說明
# filter()等方法只能是'AND'運算。 # filter(id__ge=0,id__le=10) 即:1<id<9 # 如果需要執行復雜的查詢,就需要使用Q對象 # 導入包: from django.db.models import Q # 操作符: "&" 與 "|" 或 "~" 非
實例
依然是這樣圖表:
1、查詢 id=1 或 id=3 的人名。
from django.db.models import Q from my_app import models result = models.Person.objects.filter(Q(id=1)|Q(id=3)).values('name')
2、人名為kidd,年齡大於20,的id。
from django.db.models import Q from my_app import models result = models.Person.objects.filter(Q(name='kidd'),age__gt=20).values('id')
也可以這樣
result = models.Person.objects.filter(Q(name='kidd') & Q(age__gt=20)).values('id')
3、人名不為kidd,且年齡為20,其他所有人的人名。
from django.db.models import Q from my_app import models result = models.Person.objects.filter(~Q(name='kidd')&Q(age=20)).values('name')
查詢結果
有時候在多對多表中,常常會有重復的ID。
例如,老師跟班級之間的關系,老師可以交多個班級,班級可以有多個老師,當你在取數據時會出現一個老師出現多次的情況,為了避免這種情況可以簡單做一個字典操作。
obj = models.Teacher.objects.all().values("id","name","grade__caption","grade__id") obj_dic = {} for key in obj: nid = key["id"] if obj_dic.get(nid): obj_dic[nid]["grade_list"].append({"grade_id":key["grade__id"],"caption":key["grade__caption"]}) else: obj_dic[nid] = { "nid":nid, "name":key["name"], "grade_list":[ {"grade_id":key["grade__id"],"caption":key["grade__caption"]} ] }
總結
在數據庫中,其實沒有一對一,多對多全都是模擬出來的,只有一個一對多也就是ForeignKey。
一對一:
在要限制的字段中,添加只能出現一次就好了,也就是Django中的 unique=Ture
多對多:
創建第三張表,將表進行ForeignKey。