十三、ORM
概念:对象关系映射
本质:用面向对象的方式,去描述数据库,操作数据库,达到不用编写sql语句对数据库进行增删改查。
优势:不用直接编写SQL代码,只需像操作对象一样从数据库操作数据
类—》表
类属性—》字段
实例—》数据
所有的代码写在moudles里面
1.模型的创建与映射
1.模型文件:student/models.py
2.创建模型:
-
varchar—》models.CharField(max_length) 字符串 max_length设置长度
-
int—》SmallIntegerField(IntegerField)数字
-
models.DateTimeField(auto_now_add=True) 时间(自动填充当前时间)
-
models.DateField 日期
-
longtext—》models.TextField 文本
class Student(models.Model):
name = models.CharField(max_length=20)
age = models.SmallIntegerField()
sex = models.SmallIntegerField(default=1) #设置默认值
qq = models.CharField(max_length=20)
phone = models.CharField(max_length=20)
# c_time = models.DateTimeField(verbose_name='数据创建时间',auto_now_add=True)#auto_now_add 自动填充当前时间
c_time = models.DateTimeField('数据创建时间',auto_now_add=True)#名字必须放在第一位
3.激活模型
- 1.检查app是否被注册(settintg里的installed_app)
- 2.迁移
python manage.py makemigrations teacher#指定app迁移
python manage.py makemigrations #迁移全部模型
(djangoApp) pyvip@VIP:~$ workon djangoApp
(djangoApp) pyvip@VIP:~$ ls
config djangoProject install.sh py_case snap summer-2 公共的 模板 视频 图片 文档 下载 音乐 桌面
(djangoApp) pyvip@VIP:~$ cd djangoProject/CRM
(djangoApp) pyvip@VIP:~/djangoProject/CRM$ python manage.py makemigrations
python manage.py qslmigrate student 0001 #查看原生sql语句
以上操作完成,保存更改,但是操作还没生效。
- 迁移生效
python manage.py migrate
-
重点:注意
迁移功能非常强大,允许我们在开发项目是对模型随时更改,不需要删除数据库或者创建新的表----实时去升级数据库而不丢失数据。
4.总结,模型修改三部曲
1.修改模型(创建模型)
2.运行 python manage.py makemigrations 创建迁移
3.运行 python manage.py migrate 迁移生效
2.模型数据的增删改查
进入交互式python shell中
pip install ipython
python manage.py shell
1.增
from student.models import Student #导入模型
#第一种方式,需要将创建的对象保存
s = Student(name='summer',age=20,qq='12345')
s.save()
#第二种方式#创建空实力,在属性赋值,对象要保存
s1 = Student()
s1.name = 'july'
s1.age = 18
#第三种方式#create,不用保存
Student.objects.create(name='april',age = 19)
#第四种方式#有就取值,没有就创建记录
s = Student.objects.get_or_create(name = 'blue')
2.查
#查所有
In [15]: res = Student.objects.all()
In [16]: res
Out[16]: <QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>, <Student: Student object (4)>]>
In [18]: print(res.query)
SELECT `student_student`.`id`, `student_student`.`name`, `student_student`.`age`, `student_student`.`sex`, `student_student`.`qq`, `student_student`.`phone`, `student_student`.`c_time` FROM `student_student`
#查单条,只能返回一个对象,同时符合条件的有多个会报错
Student.objects.get(pk=1) #逐渐不一定会命名为id,
2 Student.objects.filter(age=18)
3 res = Student.objects.filter(age=18) print(res.query)
3.改
s = Student.objects.get(id = 4)
s <Student: blue>
s.phone = '1254135'
s.save()
第二种,一次修改多条数据
Student.objects.filter(sex = 1).update(sex=0)
4.删
s = Student.objects.get(pk = 3)
s.delete()
批量删除
Student.objects.filter(age=18).delete()
Student.objects.all().delete()
3.字段类型+属性
Field常用参数
primary_key: 指定是否为主键。
unique: 指定是否唯一。
null: 指定是否为空,默认为False。
blank: 等于True时form表单验证时可以为空,默认为False。
default: 设置默认值。
DateField.auto_now: 每次修改都会将当前时间更新进去,只有调用,QuerySet.update方法将不会调用。这个参数只是Date和DateTime以及TimModel.save()方法才会调用e类才有的。
DateField.auto_now_add: 第一次添加进去,都会将当前时间设置进去。以后修改,不会修改这个值
如果你在最起初的时候去设置primary_key和unique,必须在刚刚开始是就去加上,如果一定要在后面加上就要删除全部的数据库,并且在mysql里删除有关app的一切
4.查询方法
首先在环境下进入python编写页面
python manage.py shell
from teacher.modles import Student
#然后插入数据
#get all filter
#all
1.
In [7]: Student.objects.all()
Out[7]: <QuerySet [<Student: summer>, <Student: july>, <Student: april>, <Student: hah>]>
#filter
2.
In [10]: Student.objects.filter(name='summer')
Out[10]: <QuerySet [<Student: summer>]>
3.
res = In [12]: res = Student.objects.filter(name='july')
In [13]: print(res.query)
SELECT `student_student`.`num`, `student_student`.`name`, `student_student`.`age`, `student_student`.`sex`, `student_student`.`qq`, `student_student`.`phone`, `student_student`.`c_time`, `student_student`.`x_time` FROM `student_student` WHERE `student_student`.`name` = july
#get
Student.objects.get(name='april')
共同点:
1.都是通过objects去实现——》objects:每一个django模型类,都有一个默认管理器,objects
其他
1.
In [15]: Student.objects.first() #查询第一条数据
Out[15]: <Student: summer>#返回一个对象
2.
In [16]: Student.objects.last() #查询最后一条数据
Out[16]: <Student: hah>#返回一个对象
3.
In [17]: Student.objects.exclude(name='summer') #与filter用法相同,作用相反,排除
Out[17]: <QuerySet [<Student: july>, <Student: april>, <Student: hah>]>
In [18]: Student.objects.filter(name='summer')
Out[18]: <QuerySet [<Student: summer>]>
4.指定字段查询
In [19]: Student.objects.values('name')
Out[19]: <QuerySet [{'name': 'summer'}, {'name': 'july'}, {'name': 'april'}, {'name': 'hah'}]>#返回字典
In [23]: res = Student.objects.values('name')
#他可以查指定字段的东西,但是其余的东西却不能找到
In [24]: res[2]['name']
Out[24]: 'april'
#如果要拿全部的东西,需要用到only
In [27]: res = Student.objects.only('name')
In [28]: res
Out[28]: <QuerySet [<Student: summer>, <Student: july>, <Student: april>, <Student: hah>]>
In [30]: res[2]
Out[30]: <Student: april>
In [31]: res[2].name
Out[31]: 'april'
In [32]: res[2].sex
Out[32]: 0
#和only相反的defer(排除)
#####排序
#order_by:根据指定字段排序
In [37]: res = Student.objects.order_by('age')
In [38]: print(res.query)
SELECT `student_student`.`num`, `student_student`.`name`, `student_student`.`age`, `student_student`.`sex`, `student_student`.`qq`, `student_student`.`phone`, `student_student`.`c_time`, `student_student`.`x_time` FROM `student_student` ORDER BY `student_student`.`age` ASC
ASC表示正序
In [40]: res = Student.objects.order_by('-age')
In [41]: print(res.query)
SELECT `student_student`.`num`, `student_student`.`name`, `student_student`.`age`, `student_student`.`sex`, `student_student`.`qq`, `student_student`.`phone`, `student_student`.`c_time`, `student_student`.`x_time` FROM `student_student` ORDER BY `student_student`.`age` DESC
DESC表示反序
##切片
In [43]: Student.objects.all()[:2]
Out[43]: <QuerySet [<Student: summer>, <Student: july>]>
##查询
#单条件
In [47]: Student.objects.filter(age=20,sex=0)
Out[47]: <QuerySet [<Student: summer>, <Student: april>]>
#多条件查询,需要导入Q库
In [48]: from django.db.models import Q
In [49]: Student.objects.filter(Q(sex=0),Q(age=20)|Q(age=19
...: ))
Out[49]: <QuerySet [<Student: summer>, <Student: april>]>
5.查询条件
#exatc 准确匹配
WHERE `student_student`.`name` = summer
#iexatc 不区分大小写匹配
WHERE `student_student`.`name` LIKE summer
#contains 包含匹配
WHERE `student_student`.`name` LIKE BINARY %s%
#icontains 不匹配大小写的包含匹配
WHERE `student_student`.`name` LIKE %s%
# in
In [63]: Student.objects.filter(pk__in=[1,2])
Out[63]: <QuerySet [<Student: summer>, <Student: july>]>
In [65]: Student.objects.filter(sex__in='01')
Out[65]: <QuerySet [<Student: summer>, <Student: july>, <Student: april>, <Student: hah>]>
#子查询
res = Student.objects.filter(name__icontains='s'). only('name')
res1 = Student.objects.filter(pk__in=res).only('name') print(res1.query)
SELECT `student_student`.`num`, `student_student`.`name` FROM `student_student` WHERE `student_student`.`num` IN (SELECT U0.`num` FROM `student_student` U0 WHERE U0.`name` LIKE %s%)
#gt大于 gte大于等于 lt小于 lte小于等于
In [71]: Student.objects.filter(pk__gt=2)
Out[71]: <QuerySet [<Student: april>, <Student: hah>]>
#range,范围查找
In [74]: Student.objects.filter(age__range=(0,21))
Out[74]: <QuerySet [<Student: summer>, <Student: july>, <Student: april>, <Student: hah>]>
#聚合分组annotate
In [76]: from django.db.models import Count,Avg,Max,Sum
In [77]: res = Student.objects.values('sex').annotate(ren=C
...: ount('sex'))
In [78]: print(res.query)
SELECT `student_student`.`sex`, COUNT(`student_student`.`sex`) AS `ren` FROM `student_student` GROUP BY `student_student`.`sex` ORDER BY NULL
6.表关系的实现
一对一,一对多,多对多
1.表关系
一个班级-----多个学生
问:foreignkey放在哪?
一个班级找一个学生
一个学生找一个班级
所以foreignkey放在学生表
from django.db import models
# Create your models here.
class Teacher(models.Model):
name = models.CharField('学生姓名',max_length=20)
age = models.SmallIntegerField('年龄',null=True)
sex = models.SmallIntegerField('性别',null=True)
qq = models.CharField('QQ',max_length=20,unique=True)
phone = models.CharField('电话',max_length=20,unique=True)
c_time = models.DateTimeField('创建时间',auto_now_add=True)
# detail = models.OneToOneField('TeacherDetail',on_delete=models.SET_NULL,null=True)
grade = models.ForeignKey('Grade',on_delete=models.SET_NULL,null=True)
def __str__(self):
return"{}-{}".format(self.name,self.age)
class TeacherDetail(models.Model):
college = models.CharField('学院',max_length=20)
teacher = models.OneToOneField('Teacher',on_delete=models.CASCADE)
class Grade(models.Model):
name = models.CharField("班级名称",max_length=20)
num = models.CharField('班期',max_length=20)
class Coures(models.Model):
name = models.CharField("课程名称",max_length=20)
teachers = models.ManyToManyField('Teacher')
2.回滚
python manage.py migrate teacher 0001
注意回滚后必须把最后一次记录删了
3.中间表自己创建
前面需要在一个表上加上through:
class Coures(models.Model):
name = models.CharField("课程名称",max_length=20)
teachers = models.ManyToManyField('Teacher',through='Enroll')#在关联的表上面添加through,这样可以不按照他给你的teacher_coures创建中间表,而是按照自己的表格来创建
#中间表
class Enroll(models.Model):
teacher = models.ForeignKey('Teacher',on_delete=models.CASCADE)
course = models.ForeignKey('Coures',on_delete=models.CASCADE)
pay = models.FloatField('缴费金额',default=0)
c_time = models.DateTimeField('报名时间',auto_now_add=True)
4.OneToMany(正向/反向增删改查)
正向:一个模型有外键字段,通过这个模型对外键进行操作就叫正向
反向:一个模型如果被另一个模型外键关联,通过这个模型对关联他的模型进行操作
class Student(models.Model):
....
grade = models.ForeignKey('Grade',on_delete=models.SET_NULL,null=True)
#增:通过属性赋值
In [12]: s1 = Teacher(name='summer',age=20,sex=1,qq='123',
...: phone='456',grade = g1)
In [13]: s1.save()
#增:主键方式
s3 = Teacher(name='april',age=18,sex=0,qq='1357',phone='2468')
s3.grade_id = g3.id s3.save()
#查
In [22]: s1
Out[22]: <Teacher: summer-20>
In [23]: s2.grade.name
Out[23]: '爬虫班'
In [25]: Teacher.objects.filter(grade__name='django框架')
Out[25]: <QuerySet [<Teacher: summer-20>]>
#删:删除两个之间的关联关系
In [26]: s1.grade = None
In [27]: s1.save()
In [28]: s1.grade
反向的管理器:如果一个模型(Teacher)有一个ForeignKey(grade),那么这一个外建模型的实例为g1将可以返回一个teacher模型的所有市里的管理器(teacher_set)(teacher是模型名,小写)
#增
#1.通过teacher_set管理器
new_s = g2.teacher_set.create(name='fat',age=20,sex=1,qq='12367',phone='12537')
#2.一次多个数据
In [32]: s1,s2,s3 = Teacher.objects.filter(id__lte=3);
In [33]: g1.teacher_set.add(s1,s2,s3)
#改
g2.teacher_set.set([s2,s3])
#删
g2.teacher_set.remove(s2,s3)
g2.teacher_set.clear()
#查:和objects一样使用
g1.teacher_set.all()
In [44]: g1.teacher_set.filter(age=18)
Out[44]: <QuerySet []>
5.ManyToMany
class Course(models.Model):
...
teachers = models.ManyToManyField('Tracher',through='Enroll')
反向模型管理器:Course_set
替换模型名:related_name--可以通过这个来指定属性替代course_set
teachers = models.ManyToManyField('Teacher',through='Enroll',related_name = 'course')
因为改了数据,因此需要重新迁移数据。
python manage.py makemigrations
python manage,py migrate
#再次导入ipython
python manage.py shell
就可以再次进行编写
In [1]: from teacher.models import Teacher,TeacherDetail,Coures,Enroll,Grade
#增
c1 = Course.objects.create(name='python')
s1 = Teacher.objects.first()
#关联
In [7]: e = Enroll()
In [8]: e.course = c1
In [9]: e.teacher = s1
In [14]: e.save()
#查
#正向查找
In [21]: c1.teachers.all()
Out[21]: <QuerySet [<Teacher: summer-20>]>
#反向查找
In [19]: s1.course.all()
Out[19]: <QuerySet [<Course: Course object (1)>]>
6.OneToOne
正向:foreignkey在哪个字段下面就是通过这个字段去找关联的东西。
正向:一对一字段所载的模型,通过这个模型去访问关联的模型
In [23]: d1 = TeacherDetail(college='宁夏理工学院')
In [24]: d1.teacher = s1
In [25]: d1.save()
#查
In [26]: TeacherDetail.objects.values('college','teacher__name','teacher__qq')
Out[26]: <QuerySet [{'college': '宁夏理工学院', 'teacher__name': 'sum'teacher__qq': '123'}]>
反向:前面的反向都是通过管理器,泽丽反向类似正向
In [28]: s = Teacher(name='yl',age=19,sex=0,qq='151551',phone='357337') #原始模型的小写名
In [29]: s.studentdetail = d1
In [30]: s.save()
#查
Teacher.objects.values('name','qq','teacherdetail__college')
7.跨表查询
#如果我想要跨越关系,只需要使用跨模型的向相关字段的字段名以双下划线隔开,知道达到想要的结果为止。
#男老师的课程
In [56]: Course.objects.filter(teachers__sex=1)
Out[56]: <QuerySet [<Course: Course object (1)>]>
#报名python课程的老师
Teacher.objects.filter(course__name='python')
####contions模糊查询
#及报名python也是django11期学员
Teacher.objects.filter(course__name='python',grade__num__contains='11')
#查缴费小于3000的老师
In [71]: e = Enroll()
In [72]: e.course = c2
In [73]: e.teacher = s5
In [74]: e.pay = 1000
In [75]: e.save()
In [68]: Teacher.objects.filter(enroll__pay__lt=3000)
Out[68]: <QuerySet [<Teacher: summer-20>, <Teacher: july-19>, <Teacher: april-18>, <Teacher: fat-20>]>
#查询学员报名课程的班级有哪些
In [5]: Grade.objects.filter(teacher__course__name='python')
Out[5]: <QuerySet [<Grade: django框架>, <Grade: django框架>, <Grade: 基础班>]>
#去重
In [6]: Grade.objects.filter(teacher__course__name='python').distinct()
Out[6]: <QuerySet [<Grade: django框架>, <Grade: 基础班>]>
如果想获取更多有关python的信息,和想玩python制作的小程序,可以关注微信公众号(dreamspy)。我们一起用python改变世界,一起用python创造梦想。