以学生-课程数据模型为例子:
学生(学生ID,姓名,性别,年级)
课程(课程ID,课程名,老师)
选课(选课ID,学生ID,课程ID,成绩,课程属性)
使用Django的模型层定义这些数据段
class Course(models.Model):
name = models.CharField(max_length=20)
teacher = models.CharField(max_length=20)
class Student(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=10)
grade = models.IntegerField(default=2020)
courses = models.ManyToManyField(Course, through='SC')
class SC(models.Model):
student = models.ForeignKey(Student, models.CASCADE)
course = models.ForeignKey(Course, models.CASCADE)
score = models.IntegerField(default=0)
attribute = models.CharField(max_length=10)
执行命令
>py manager.py makemigrations
>py manager.py migrate
成功执行后,相应的SQL语句已经被执行,在数据库中自动创建了以下表
Student表
id、name、gender、grade
Course表
id、name、teacher
SC表
id、score、attribute、course_id、student_id
在模型层定义的类对应着一个数据库的表项,每个类的一个实例就是相应的表中的一个元组
所以对应数据库的增操作就是创建一个模型类的对象
s1 = Student(name='aaa',gender='male',grade=2019)
s1.save()
save()方法必须调用,调用save()后Django才操纵数据库执行操作
执行了以上代码后,查看数据库
数据库中保存了刚创建的学生对象
使用create()方法可以一步完成实例化和存储数据到数据库的操作
c1 = Course.objects.create(name='sc',teacher='zzz')
执行了以上代码后,查看数据库
s1 = Student.objects.get(pk=1)
c1 = Course.objects.get(pk=1)
sc1 = SC(student=s1,course=c1,score=88,attribute='elective')
sc1.save()
执行以上代码后,查看数据库
在Student模型中,添加了字段courses用于和Course模型的多对多关联,在数据库中,建立了sc表来表示这一关联,使用add()方法就可以添加关联对象,而对应的在sc表中会创建一个元组
s2 = Student.objects.get(pk=2)
c1 = Course.objects.get(pk=1)
s2.courses.add(c1)
执行以上代码后,会在sc表中创建一个新的元组
但是,在定义模型时,使用了中间模型来为学生和课程关系添加额外的属性:成绩与课程属性,在上面的调用中,这两个属性会设置为默认值,可以用 through_defaults
参数指定这些属性的值
s2 = Student.objects.get(pk=2)
c2 = Course.objects.get(pk=2)
s2.courses.add(c2,through_defaults={'score':55,'attribute':'elective'})
执行以上代码后,会在sc表中创建一个新的元组,且带成绩与课程属性,查看数据库
在前面已经使用了查询操作,可以看出是用 模型类.objects.get()
来进行查询,其中 模型类.objects
是一个控制器
Django中只能用模型类调用api查询,不能用类的实例调用
控制器的all()方法
>>> Student.objects.all()
# , ]>
重写 __str__
方法可以改变显示
实质改变了SQL语句的WHERE子句的内容
filter(**kwargs)
# 返回一个新的 QuerySet,包含的对象满足给定查询参数。
-----------------------------------------------------------------------------
exclude(**kwargs)
# 返回一个新的 QuerySet,包含的对象 不 满足给定查询参数。
-----------------------------------------------------------------------------
get(**kwargs)
# 返回匹配查询条件的对象
# 有多个结果抛出 MultipleObjectsReturned 异常
# 没有结果抛出 DoesNotExist 异常
更多的QuerySet 方法
>>> Student.objects.filter(grade=2022)
# ]>
>>> Student.objects.exclude(grade=2020)
# , ]>
QuerySet也能调用以上方法,所以可以多个条件串联起来进行链式查询
>>> Student.objects.exclude(grade=2020).filter(grade=2022).get(grade=2022)
#
# get()方法返回的是模型类的对象
QuerySet对象可以储存起来,不会被其他操作影响到,可以之后继续调用方法查询
QuerySet对象只有在被计算时进行数据库操作
可以使用Python的切片语法改变QuerySet的长度,不能用负数索引
>>> Student.objects.all()[0:5]
# , ]>
虽然返回的还是QuerySet对象,但是切片操作后,不能继续过滤和排序
>>> Student.objects.all()[0:5].get(grade=2022)
# Traceback (most recent call last):
# …………
# AssertionError: Cannot filter a query once a slice has been taken.
除了用 =
设置过滤条件,还有其他过滤条件可以设置,在属性后面加双下划线 __
就可以使用
进行精确的匹配
Student.objects.filter(grade__exact=2022)
# 等价于
Student.objects.filter(grade=2022)
不分大小写的匹配
Course.objects.filter(name__iexact='cs')
大小写敏感的包含
Student.objects.filter(name__contains='a')
大致对应的WHERE子句
WHERE name LIKE '%a%';
大小写不敏感的包含
Student.objects.filter(name__icontains='a')
在给定的可迭代对象内
Student.objects.filter(grade__in=[2019,2020,2021])
Student.objects.filter(name__in='abc')
大致对应的WHERE子句
WHERE grade IN (2019,2020,2021);
WHERE name IN ('a','b','c');
greater than,比给的数字大
Student.objects.filter(grade__gt=2018)
大致对应的WHERE子句
WHERE grade > 2018;
greater than or equal to,大于等于给的数字
Student.objects.filter(grade__gte=2018)
less than,小于
less than or equal to,小于等于
大小写敏感的开头匹配
Student.objects.filter(name__startwith='李')
大小写不敏感的开头匹配
大小写敏感的结尾匹配
大小写不敏感的结尾匹配
范围
SC.objects.filter(score__range=(80,89))
大致对应的WHERE子句
WHERE score BETWEEN 80 AND 89;
假如想查询老师是’zzz‘的学生,Django提供了跨关系查询,同样也是用双下划线 __
连接
Student.objects.filter(courses__teacher='zzz')
也可以反向关联,比如查询有2022级学生上的课程,反向关联要把模型类名小写
Course.objects.filter(student__grade=2022)
Django提供主键(primary key)查询快捷方式
Student.objects.get(pk=1)
# 返回主键是1的Student对象
使用该方法删除对象,返回被删除的对象数量和一个包含了每个被删除对象类型的数量的字典。
模型类的对象和QuerySet都能调用此方法,但是管理器不能调用该函数
s1=Student.objects.get(pk=1)
s1.delete()
SC.objects.filter(score__lt=60).delete()
使用该方法更新对象,对指定字段执行SQL的更新操作,并返回匹配的行数
SC.objects.filter(socre__lt=60).update(score=60)
更新不能跨关系执行
单个模型类的实例不能调用update()方法
但是可以获取到该对象后修改相应的值,再用save()方法保存
sc = SC.objects.get(pk=2)
sc.score = 100
sc.save()