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關鍵字參數不存在。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM