天天看點

Django Model模型

Model簡介

模型準确且唯一的描述了資料。它包含您儲存的資料的重要字段和行為。一般來說,每一個模型都映射一張資料庫表。

  • 每個模型都是一個 Python 的類,這些類繼承 django.db.models.Model;
  • 模型類的每個屬性都相當于一個資料庫的字段;
  • 利用這些,Django 提供了一個自動生成通路資料庫的 API;

使用模型

在定義模型時,每個字段都被指定為一個類屬性,并且每個屬性映射為一個資料庫列。

建立資料庫時,會自動添加主鍵id字段,但是這種行為可以被改寫。

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)      

如果想使用自定義的模型,需要修改設定檔案中的INSTALLED_APPS,在這個設定中添加包含models.py檔案的子產品名稱。例如項目中的myapp.models子產品;

INSTALLED_APPS = [
    #...
    'myapp',
    #...
]      

向INSTALLED_APPS添加新的應用的時候,務必運作 manage.py migrate,也可以先使用指令manage.py makemigrations進行遷移。

字段

模型中最重要且唯一必要的是資料庫的字段定義,字段在類屬性中定義,并且每一個字段都應該是某個Field類的執行個體。

常用字段類型

AutoField():一個IntegerField,根據可用ID自動遞增。如果沒指定主鍵,就建立它自動設定為主鍵。

IntegerField():一個整數;

CharField(max_length = None):字元串字段

DateField(auto_now=False, auto_now_add=False):日期

TextField():一個很長的的文本字段

BooleanField():布爾字段;

OneToOneField(to, on_delete, parent_link = False):一對一

ForeignKey(to, on_delete):一對多

ManyToManyField(to):多對多

字段參數

null:如果設定為True,當該字段為空時,Django會将資料庫中該字段設定為NULL。預設為False 。

blank:如果設定為True,該字段允許為空。預設為False。

default:該字段的預設值。可以是一個值或者是個可調用的對象,如果是個可調用對象,每次執行個體化模型時都會調用該對象。

primary_key:如果設定為 True ,将該字段設定為該模型的主鍵。

unique:如果設定為 True,這個字段的值必須在整個表中保持唯一。

verbose_name:任何字段類型都接收一個可選的位置參數,如果未指定Django會自動使用字段的屬性名作為該參數值,并且把下劃線轉換為空格。

ForeignKey.on_delete:當ForeignKey删除引用的對象時,Django将模拟on_delete參數指定的SQL限制的行為 。

    CASCADE, 删除引用的對象時,也删除引用它的對象;
    PROTECT, 通過抛出異常來禁止删除引用的對象。
    SET_NULL, 将引用設定為NULL,隻有在null為True的情況下。
    SET_DEFAULT, 設定預設值,ForeignKey必須設定預設值。
    SET(...), 設定給定值。
    DO_NOTHING, 不采取行動。如果資料庫後端強制引用完整性,這将導緻完整性錯誤,除非手動向資料庫字段添加SQL on delete限制。      

on_delete參數

自動設定主鍵

在一個模型中,如果你沒有對任何一個字段設定primary_key=True選項。 Django會自動添加一個IntegerField字段,并設定為主鍵,是以除非想重寫Django預設的主鍵設定行為,可以不手動設定主鍵。主鍵字段是隻可讀的,如果你修改一個模型執行個體的主鍵并儲存,這等同于建立了一個新的模型執行個體

id = models.AutoField(primary_key=True)  #預設添加的自增主鍵      

Meta()

使用内部Meta類來給model定義中繼資料;

abstract
如果abstract=True,那麼model為抽象基類;

app_label
在其他地方寫了一個模型類,而這個模型類是屬于myapp的,那麼需要指定app_label='myapp';

db_table
用于指定自定義資料庫表名的;

get_latest_by
由于Django的管理方法中有個lastest()方法,就是得到最近一行記錄。如果你的資料模型中有 DateField 或 DateTimeField 類型的字段,你可以通過這個選項來指定lastest()是按照哪個字段進行選取的。

managed
由于Django會自動根據模型類生成映射的資料庫表,如果你不希望Django這麼做,可以把managed的值設定為False。

ordering
這個字段是告訴Django模型對象傳回的記錄結果集是按照哪個字段排序的。加負号為反序ordering = ['-create_time']

permissions
建立此對象時進入權限表的額外權限。
指定了一個附權重限: can_deliver_pizzas
permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
這是一個2-元素 tuple 的tuple或清單, 其中兩2-元素 tuple 的格式為:(permission_code, human_readable_permission_name)。

unique_together
一起使用的字段名稱集必須是唯一的,這是一個清單,這些清單在一起考慮時必須是唯一的
unique_together = [['driver', 'restaurant']]

verbose_name
給model類起一個更可讀的名字:

verbose_name_plural
model的複數名稱      

Meta屬性

QuerySet API

一旦建立 資料模型 後,Django自動給予一套資料庫抽象API,允許你建立、檢索、更新和删除對象。

建立對象

為了用 Python 對象展示資料表對象,Django使用了一套直覺的系統:一個模型類代表一張資料表,一個模型類的執行個體代表資料庫表中的一行記錄。

要建立一個執行個體對象,有兩種建立方式:

  • 先用關鍵字參數初始化,然後調用 save() 将其存入資料庫。
  • 直接調用create(** kwargs)方法,建立對象并将其更新至資料庫;

save(force_insert = False, force_update = False, using=DEFAULT_DB_ALIAS, update_fields=None);

調用方法時,會将對象儲存至資料庫。如果想自定義儲存行為,可以重寫這個方法。

在調用save()之前無法确定執行個體對象的自增主鍵是什麼,因為自增id是資料庫計算的,也不是Django計算的,除非明确指定;

如果執行個體對象的主鍵屬性設定為True(除None空字元串以外的值),那麼django會執行UPDATE;

如果執行個體對象的主鍵屬性沒被設定,或者沒有更新任何資訊(例如主鍵設定了一個資料庫中不存在的值),那麼Django會執行INSERT;

如果執行個體對象執行save(),那麼資料庫中這條資料的所有字段都會被更新一次,無論字段是否有變化;

可以指定update_fields參數,可以是一個清單,清單中是需要更新的字段名;此時資料庫隻會對指定字段進行更新;

可以通過指定force_insert, force_update參數,讓資料強制進行INSERT或UPDATE操作。

th = Teacher(teacher_name='Alice', sex=True)
th.save()

th = Teacher()
th.teacher_name = 'Even'
th.sex = False
th.save()      

save()示例

create(**kwargs)

建立對象并将其全部儲存在一個步驟中的便捷方法

#指定關鍵字參數
School.objects.create(school_name='清華',city='beijing')

#傳遞字典參數
sh_info = {'school_name': '北大', 'city': 'beijing'}
School.objects.create(**sh_info)      

create()示例

删除對象

delete(using=DEFAULT_DB_ALIAS, keep_parents=False);

立刻删除對象,并傳回被删除的對象數量和一個包含了每個被删除對象類型的數量的字典。也可以批量删除對象,所有的QuerySet都有delete()方法,它會删除QuerySet中的所有成員。

當Django删除某個對象時,預設會模仿SQL限制ON DELETE CASCADE的行為——換而言之,某個對象被删除時,關聯對象也會被删除;這種限制行為由ForeignKey的on_delete參數指定。

# 删除某一個對象
school1.delete()

# 删除QuerySet中的所有成員
School.objects.filter(city='beijing').delete()

# 删除School的所有對象
School.objects.all().delete()      

delete()示例

更新對象

update(** kwargs);

對QuerySet中指定的字段執行SQL更新查詢,并傳回比對的行數(如果某些行已具有新值,則可能不等于更新的行數)。

可以同時跟新多個字段;

方法立即應用,執行後就改變了資料庫的資料;

QuerySet更新的唯一限制是,隻能更新模型主表中的列,不能更新相關聯的模型中的列。

# 更新一個列
Student.objects.filter(pk=2).update(age=18)
# 更新QuerySet中的多個對象中的多個列
st_info = {'age': 18, 'score': 666}
Student.objects.filter(id__lt=3).update(**st_info)
# 更新與其他model相關聯的列
sh = School.objects.get(pk=4)
Student.objects.filter(pk=3).update(school=sh)      

update()示例

檢索對象

要從資料庫檢索對象,就要通過模型類的Manager建構一個QuerySet;一個QuerySet代表來自資料庫中對象的一個集合,可以根據給定參數縮小查詢結果量。在SQL的層面上, QuerySet對應SELECT語句,而過濾器對應類似 WHERE 或 LIMIT 的限制子句。

QuerySet是惰性的,建立 QuerySet 并不會引發任何資料庫活動,Django隻有在QuerySet被使用時才執行查詢操作。

Manager 是一種接口,它賦予了Django模型操作資料庫的能力。Django應用中每個模型擁有至少一個 Manager,預設名稱是objects。Managers隻能通過模型類通路,而不是通過模型執行個體,目的是強制分離“表級”操作和“行級”操作。

#model類可以直接調用
all():傳回一個包含資料表中所有對象的QuerySet;
get(**kwargs):傳回一個滿足給定查詢參數的對象,沒有則DoesNotExist;
filter(**kwargs):傳回一個新的QuerySet,包含的對象滿足給定查詢參數;
exclude(**kwargs):傳回一個新的QuerySet,包含的對象不滿足給定查詢參數;

#QuerySet可以調用
order_by(*fields):根據指定字段進行排序
values(*fields, **表達式):
distinct(*field):去掉重複的行
reverse():反轉查詢集元素的順序;
count():傳回一個整數,表示與資料庫比對的QuerySet中的對象數;
first():傳回查詢集比對的第一個對象
last():傳回查詢集中的最後一個對象
exists():如果QuerySet包含任何結果傳回True,不包含則為False;
union(*other_qs,all=False):組合其他QS的結果;
difference(*other_qs):保留調用QS中存在,其他QS不存在的元素;      

QuerySet API

School.objects.all()  #<QuerySet [<School: 清華大學>, <School: 北京大學>, <School: 山東大學>, <School: 複旦大學>]>
School.objects.get(school_name='北京大學')  #北京大學
School.objects.filter(city='beijing')  #<QuerySet [<School: 清華大學>, <School: 北京大學>]>
School.objects.exclude(city='beijing')  #<QuerySet [<School: 山東大學>, <School: 複旦大學>]>
School.objects.filter(pk=1).values()  #<QuerySet [{'id': 1, 'school_name': '清華大學', 'city': 'beijing', 'pass_line': 685}]>
School.objects.values('city').distinct()  #<QuerySet [{'city': 'beijing'}, {'city': 'shandong'}, {'city': 'shanghai'}]>
School.objects.order_by('pass_line')  # <QuerySet [<School: 山東大學>, <School: 複旦大學>, <School: 北京大學>, <School: 清華大學>]>
School.objects.order_by('pass_line').reverse()#<QuerySet [<School: 清華大學>, <School: 北京大學>,<School: 複旦大學>,<School: 山東大學>]>
School.objects.count()  #4
School.objects.filter(city='beijing').first()  #清華大學
School.objects.filter(city='beijing').last()  #北京大學
School.objects.filter(pass_line__gt=500).exists()  #True
School.objects.filter(pass_line__gt=700).exists()  #False      

QuerySet API方法示例

字段查詢

字段查找是指定SQL WHERE子句的内容的方式。它們被指定為QuerySet方法的關鍵字參數;通過給定的限制條件查找出相對應子集。

in:在給定的可疊代對象中
gt, gte, lt, lte:大于小于
range:給定對象範圍内
isnull:是否為空
exact, iexact:完全符合
contains, icontains:包含比對
startswith, istartswith:開頭
endswith, iendswith:結尾
regex, iregex:正規表達式      

field查詢

Student.objects.filter(age__in=[18,19])  #<QuerySet [<Student: Jerry>, <Student: Lee>]>
Student.objects.filter(age__gt=20)  #<QuerySet [<Student: Ming>]>
Student.objects.filter(age__lt=20)  #<QuerySet [<Student: Jerry>, <Student: Lee>]>
Student.objects.filter(score__range=[650, 700])  #<QuerySet [<Student: Jerry>]>
Student.objects.filter(age__isnull=True)  #<QuerySet []>
Student.objects.filter(student_name__exact='Ming')  #<QuerySet [<Student: Ming>]>
Student.objects.filter(student_name__contains='e')  #<QuerySet [<Student: Jerry>, <Student: Lee>]>
Student.objects.filter(student_name__startswith='L')  #<QuerySet [<Student: Lee>]>
Student.objects.filter(student_name__endswith='y')  #<QuerySet [<Student: Jerry>]>
Student.objects.filter(student_name__regex='[A-Z]e[a-z]*')  #<QuerySet [<Student: Jerry>, <Student: Lee>]>      

field查詢示例

聚合查詢

Aggregate(*expressions, output_field = None, distinct = False, filter = None, ** extra)

聚合表達式是Func()表達式的一種特殊情況,查詢需要一個聚合函數。

Avg():傳回給定表達式的平均值
Count():傳回給定表達式的總計數
Max():傳回給定表達式的最大值
Min():傳回給定表達式的最小值
Sum():計算給定表達式的所有值的總和      

聚合函數

from django.db.models import Avg, Count, Max, Min, Sum

Student.objects.aggregate(Avg('score'))  #{'score__avg': 618.0}
Student.objects.aggregate(Count('score'))  #{'score__count': 3}
Student.objects.count()  #3
Student.objects.aggregate(Max('score'))  #{'score__max': 666}
Student.objects.aggregate(min_value=Min('score'))  #{'min_value': 560}
Student.objects.aggregate(sums=Sum('score'))  #{'sums': 1854}      

聚合函數示例

分組查詢

annotate(*args, **kwargs);

如果先使用values()方法對整體分組,聚合函數隻能針對某組對象進行處理;而annotate()可以針對每組進行處理。

例如:查詢每個城市的學校數量,和每個城市學校最高錄取分數

School.objects.values('city').annotate(Count('pass_line')) 
#<QuerySet [{'city': 'beijing', 'pass_line__count': 2}, {'city': 'shandong', 'pass_line__count': 1}, {'city': 'shanghai', 'pass_line__count': 1}]>
School.objects.values('city').annotate(Max('pass_line')) 
#<QuerySet [{'city': 'beijing', 'pass_line__max': 685}, {'city': 'shandong', 'pass_line__max': 657}, {'city': 'shanghai', 'pass_line__max': 665}]>      

分組查詢示例

F查詢

一個F()對象表示一個模型字段或注釋的列的值。它可以引用模型字段值并使用它們執行資料庫操作,而無需将它們從資料庫中拉出到Python記憶體中。

讓資料庫而不是Python來做工作;

避免多線程中對資料庫中字段的搶占;

減少一些操作所需的查詢數量。

from django.db.models import F

school = School.objects.get(pk=3)
school.pass_line = F('pass_line') + 20
school.save()

school = School.objects.filter(pk=3)
school.update(F('pass_line') + 20)      

F查詢

django遇到F()示例時,它會覆寫python運算符來建立一個封裝的SQL表達式,訓示資料庫增加由school.pass_line表示的資料庫字段。

無論school.pass_line的值是什麼,python都不會知道,它完全由資料庫處理,此時的F()執行個體就像一個資料庫字段的引用。

使用F()函數儲存值後,再次使用執行個體調用并不能拿到新的值.這是因為F()函數是資料庫操作,并不是在記憶體中python進行的;要通路儲存後的新值時,必須重新加載該對象。

school = School.objects.get(pk=school.pk)
#or
school.refresh_from_db()      

重新擷取

儲存F()執行個體後,指派給模型字段的對象将會保留,每次執行save()時,字段的F()也會執行一次。

school = School.objects.get(pk=3)
school.pass_line = F('pass_line') + 20
school.save()
school.save()      

持久性

如果pass_line初始值是500,最終值是540;通過在儲存模型對象後重新加載模型對象,例如使用refresh_from_db()可以避免此持久性。

Q查詢

封裝一組字段查詢操作。

在字段查詢中,可以使用,分割并列的查詢條件;但字段中不能進行其他關系條件的查詢。

使用Q()執行個體字段查詢後,可以進行&|~等條件的查詢。

from django.db.models import F

School.objects.filter(city='beijing', pass_line__gt=680)  #<QuerySet [<School: 清華大學>]>
School.objects.filter(Q(city='beijing') & Q(pass_line__gt=680)) #<QuerySet [<School: 清華大學>]>
School.objects.filter(Q(city='beijing') | Q(pass_line__gt=680)) #<QuerySet [<School: 清華大學>, <School: 北京大學>]>
School.objects.filter(~Q(city='beijing'))  #<QuerySet [<School: 山東大學>, <School: 複旦大學>]>
School.objects.filter(Q(pass_line__lt=660) & (Q(city='shandong') | Q(city='shanghai')))  #<QuerySet [<School: 山東大學>]>      

Q查詢

Q查詢與字段查詢共同使用時,字段查詢需要放在Q()的後面。

School.objects.filter(Q(city='shandong') | Q(city='shanghai'), pass_line__lt=660)  #<QuerySet [<School: 山東大學>]>      
con = Q()

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id_lt', 2))
q1.children.append(('name_contains', 'hi'))

q2 = Q()
q2.connector = 'OR'
q2.children.append(('status', '線上'))

con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)      

多條件,執行個體化Q()

關聯對象

當你在模型中定義了關聯關系(如ForeignKey,OneToOneField,或 ManyToManyField),該模型的執行個體将會自動擷取一套 API,能快捷地通路關聯對象。

一對一

表結構

OneToOneField(to, on_delete, parent_link = False, **options)

 一對一的關系。

#一個學生隻能有一個學号和檔案号
#一個學号和檔案号隻能屬于一個學生
#身份資訊和學生就可以建立一對一關聯
from django.db import models


class Student(models.Model):
    student_name = models.CharField(max_length=20)
    age = models.IntegerField(default=15)
    identity = models.OneToOneField('Identity', on_delete=models.CASCADE)


class Identity(models.Model):
    student_number = models.IntegerField()
    archive_number = models.IntegerField()      

models關系

查找

# 正向查找
st = Student.objects.get(pk=2)
print(st.identity)  #20190711011

# 反向查找
id = Identity.objects.get(pk=1)
print(id.student)  #Ming      

一對一查找

一對多

表結構

ForeignKey(to, on_delete, **options)

一對多的關系。需要兩個位置參數:與模型相關的類和on_delete選項。在資料庫上自動建立資料庫索引ForeignKey,您可以通過設定db_index為禁用此功能False。

可以通過'self'來建立遞歸關系,與自身具有一對多的關系。

當添加一個外鍵後,Django追加_id字段名來建立資料庫的列名;Student的資料表中的school字段将變為school_id列。

#一個學生隻能在一個學校就讀
#一個學校中可以有多個學生
#學校和學生就可以建立一對多關聯
from django.db import models

class Student(models.Model):
    student_name = models.CharField(max_length=20)
    age = models.IntegerField(default=15)
    school = models.ForeignKey('School', on_delete=models.CASCADE)

class School(models.Model):
    school_name = models.CharField(max_length=20)
    city = models.BooleanField(max_length=100)      

models關系

建立對象

1、在建立執行個體對象時,關聯字段顯式指定一個關聯對象,或者關聯字段id指定一個對象id;

#通過字段屬性指定關聯的對象
sh_obj1 = School.objects.filter(city='上海').first()
student1_info = {
    'student_name': '小海',
    'age': 21,
    'score': 662,
    'school': sh_obj1
}
Student.objects.create(**student1_info)

#通過指定表列名指定關聯對象的id值,也可以是個數字
sh_obj2 = School.objects.filter(pass_line__lt=660).order_by('pass_line').last()
student2_info = {
    'student_name': '大B',
    'age': 20,
    'score': 672,
    'school_id': sh_obj2.id
}
Student.objects.create(**student2_info)      

正向建立方式

2、也可以通過關聯對象反向建立一個對象執行個體。

sh = School.objects.get(pk=1)
sh.student_set.create(
    student_name='大黃',
    age=23,
    score=581,
)      

反向建立

正向查找

通過雙下劃線直接調用關聯對象中的字段。

obj = Student.objects.filter(school__city='上海')
print(obj)  #<QuerySet [<Student: 小海>]>

#連表查詢,查詢每個城市的學生人數
obj = Student.objects.values('school__city').annotate(Count('age'))
print(obj)  #<QuerySet [{'school__city': '上海', 'age__count': 1}, {'school__city': '濟南', 'age__count': 2}]>      

正向查找

模型的執行個體能通過其屬性友善的通路關聯(外部的)對象。

#通過屬性調用關聯對象
student = Student.objects.filter(student_name='小海').first()
print(student.school)  #上海交通大學

#可以對外鍵進行修改,通過save()儲存至資料庫
obj = School.objects.filter(city='濟南').first()
student.school = obj
student.save()
student.refresh_from_db()
print(student.school)  #山東大學

# 如果ForeignKey字段配置了null=True,可以指定值為 None 移除關聯
student.school = None
student.save()
student.refresh_from_db()
print(student.school)  #None      

屬性查找

反向查找

反向查找,可以通過外鍵類名的小寫,加上_set,傳回一個QuerySet。

sh_obj = School.objects.filter(city='濟南').last()
st_obj = sh_obj.student_set.all()
print(st_obj)  #<QuerySet [<Student: 阿拉蕾>, <Student: 大B>]>
#傳回的QuerySet也可以調用篩選、排序等API
obj = st_obj.order_by('age')
print(obj)  #<QuerySet [<Student: 大B>, <Student: 阿拉蕾>]>      

反向查找

模型的執行個體能通過其屬性友善的通路關聯(外部的)對象。

#查找哪些學校中有年齡小于18的學生
obj = School.objects.filter(student__age__lt=18)
print(obj)  #<QuerySet [<School: 北京大學>]>      

屬性查找

add(*objs, bulk = True, through_defaults = None)

将指定的模型對象添加到相關的對象集。

st = Student.objects.get(student_name='小海')
print(st.school)  #上海交通大學
sh = School.objects.get(pk=4)
sh.student_set.add(st)
print(st.school)  #複旦大學      

add()示例

在ForeignKey關系的情況下,使用QuerySet.update()更新至資料庫,也可以使用bulk=False參數調用QuerySet.save()

add()也接受關聯指向的字段作為參數,可以改寫為sh.student_set.add(4)

remove(*objs, bulk=True)

從相關對象集中删除指定的模型對象;

st = Student.objects.get(student_name='小海')
print(st.school)  # 複旦大學
sh = School.objects.get(school_name='複旦大學')
sh.student_set.remove(st)
st.refresh_from_db()  #重新擷取執行個體對象
print(st.school)  #None      

remove()示例

在ForeignKey關系的情況下,此方法僅在null=True情況下存在;

預設使用QuerySet.update()更新至資料庫,也可以使用bulk=False參數調用QuerySet.save()

remove()也接受關聯指向的字段作為參數,可以改寫為sh.student_set.remove(4)

clear(bulk=True)

從相關對象集中删除所有對象;

sh = School.objects.get(school_name='複旦大學')
sh.student_set.clear()      

clear()示例

這不會删除相關對象,隻是将關聯關系取消。

隻在ForeignKeys字段null=True時才可以用,它也接受bulk關鍵字參數。

set(objs, bulk=True, clear=False, through_defaults=None)

替換相關對象集;

new_list = [obj1, obj2, obj3]
obj.related_set.set(new_list)      

set()示例

如果clear為False(預設),将利用remove()删除新集中缺少的元素,并且僅添加新元素;如果clear=True,則調用clear()方法,并立即添加整個集合。

對于ForeignKey對象,bulk 參數傳遞給add()和remove()的。

由于set()是複合操作,是以受競争條件的限制。

多對多

表結構

ManyToManyField(to, **options)

多對多的關系。需要一個位置參數:與模型相關的類。

1、Django建立了一個中間資料表來建立多對多關系,預設情況下,此表名稱是使用多對多字段的名稱以及包含它的模型的表名生成的。

對于多對多關聯關系的兩個模型,可以在任何一個模型中添加ManyToManyField字段,但隻能選擇一個模型設定該字段,不能同時在兩模型中添加該字段。

#一個學生可以有多個任課老師,
#一個老師也可以教多個學生,
#學生和老師就可以建立多對多關聯class Student(models.Model):
    student_name = models.CharField(max_length=20)
    age = models.IntegerField(default=15)
    teachers = models.ManyToManyField('Teacher')

class Teacher(models.Model):
    teacher_name = models.CharField(max_length=20)
    sex = models.BooleanField(default=True)      

models關系

2、在指定ManyToManyField字段時,通過through參數可以指定自定義的關系表,也就可以自定義關系表的表結構;

class Student(models.Model):
    student_name = models.CharField(max_length=20)
    age = models.IntegerField(default=15)
    score = models.IntegerField(default=560)
    teacher = models.ManyToManyField('Teacher', through="StudentToTeacher")

class Teacher(models.Model):
    teacher_name = models.CharField(max_length=20)
    sex = models.BooleanField(default=True)
    course = models.CharField(max_length=20, default='國文')

class StudentToTeacher(models.Model):
    st_id = models.AutoField(primary_key=True)
    student_id = models.ForeignKey('Student', on_delete=models.CASCADE)
    teacher_id = models.ForeignKey('Teacher', on_delete=models.CASCADE)

    class Meta:
        unique_together = [
            ('student_id', 'student_id')  #兩個字段聯合唯一
        ]      

ManyToManyField()

3、在中間的關系表中,可以利用兩個ForeignKey字段,分别指向兩個關聯對象,讓他們在這張表中同時建立外鍵關系。

class Student(models.Model):
    student_name = models.CharField(max_length=20)
    age = models.IntegerField(default=15)
    score = models.IntegerField(default=560)

class Teacher(models.Model):
    teacher_name = models.CharField(max_length=20)
    sex = models.BooleanField(default=True)
    course = models.CharField(max_length=20, default='國文')
    
class StudentToTeacher(models.Model):
    st_id = models.AutoField(primary_key=True)
    student_id = models.ForeignKey('Student', on_delete=models.CASCADE)
    teacher_id = models.ForeignKey('Teacher', on_delete=models.CASCADE)      

自定義關系表

建立對象

多對多不可以在建立時直接指定關聯對象;要先建立對象,然後再添加關聯關系。

teacher_info = {
    'teacher_name': '魯迅',
    'sex': False,
    'course': '國文'
}
Teacher.objects.create(**teacher_info)

student_info = {
    'student_name': '老王頭',
    'age': 25,
    'score': 562,
}
Student.objects.create(**student_info)      

建立對象

add(*objs, through_defaults = None)

将指定的模型對象添加到相關的對象集。

多對多關系不會調用save()方法(bulk參數不存在),而是使用QuerySet.bulk_create()建立關系

ManyToManyFeild()定義Student類中,那麼通過Student對象添加Teacher對象,就被視為正向添加;反之為反向添加。反向調用時通過外鍵class名的小寫,加上_set。

#正向添加
th = Teacher.objects.filter(course='國文').first()
st = Student.objects.filter(student_name='老王頭').first()
st.teacher.add(th)
print(st.teacher.all())  #<QuerySet [<Teacher: 魯迅>]>

#反向添加
th = Teacher.objects.get(pk=1)
st = Student.objects.filter(pk__lt=3)
th.student_set.add(*st)
print(th.student_set.all())  #<QuerySet [<Student: Jerry>, <Student: Ming>]>      

add()示例

remove(*objs)

從相關對象集中删除指定的模型對象;

clear()

從相關對象集中删除所有對象;

set(objs, clear=False, through_defaults=None)

替換相關對象集;

多對多關聯中的add(),set()和remove()放法能接收主鍵值,bulk關鍵字參數不存在。

轉載于:https://www.cnblogs.com/houyongchong/p/model.html