# 模型层
通过讲mysql的系统,翻译一遍,在django中通过创建model去和数据库中的表进行一一映射,并且通过ORM封装 的处理方式去练习这一到习题,并写出如下的解题答案
# 1.数据库准备
在model中定义数据库,其中的性别,男的存1,女的存0。
class Student(models.Model):
stuname = models.CharField(max_length=20)
stusex = models.BooleanField()
stubirth = models.DateField()
stutel = models.CharField(max_length=255)
class Meta:
db_table = 'student'
# 2.数据库迁移
python manage.py makemigrations
python manage.py migrate
# 3. 数据插入
# 3.1 使用表单form提交post请求数据
<form action="/app/addStu/" method="post">
stuname: <input type="text" name="name">
stusex: <input type="text" name="sex">
stubirth: <input type="date" name="birth">
stutel: <input type="text" name="tel">
<input type="submit" value="提交">
</form>
# 3.2 获取post请求,获取请求数据,并且创建数据
# 方法1:获取类对象进行save()保存
stu = Student() #得到一个对象,即记录
stu.stuname = stuname
stu.stusex = sex
stu.stubirth = birth
stu.stutel = tel
stu.save()
# 方法2:使用create()方法
Student.objects.create(stuname=stuname,
stusex=sex,
stubirth=birth,
stutel=tel)
# 方法3:使用初始化
在Student模型中重构__init__()方法,添加如下代码
def __init__(self, name, birth=None, sex=None,tel=None):
super().__init__()
self.stuname = name
self.stubirth = birth
self.stusex = sex
self.stutel = tel
# 视图函数中定义创建学习信息的方法为:
stu = Student('小草', 18, 1, 12331244323)
stu.save()
----------------------------- 复习 -----------------------------------
class A:
def __init__(self):
self.name = '儿子' # 当有了init函数时,相当于有了实例,所以此时的name时'儿子'
name = '父级' # 当没有init时,打印'父级',此时A()回去执行父级object的init返回一个空间
obj_1 = A() # 区分在这个括号,判断到底能不能实例化,但始终儿子会继承父级的东西
print(obj_1.name)
print(A.name) # 父级
-----------------------------------------------------------------------
#详细讲解
#models.py 文件中
from django.db import models
class Class(models.Model):
def __init__(self,name): #添加了init函数
super().__init__()
self.name = name
name = models.CharField(max_length=12)
#此时对应的views.py文件
def add_class(request):
# 方法一:在class中没有__init__时,此时他将会回到Model的init中执行
class_obj = models.Class()
class_obj.name = 'Pyhton20期'
class_obj.save()
# 方法二: 在class中设置了__init__ 初始化函数时,我们可以通过
class_obj = models.Class('linux 20期') #使用了
class_obj.save()
return HttpResponse('添加成功')
#可能这里会有点模糊:name和self.name 怎么就联系在一起了? 其实在我们通过Class()方式来创建一条记录的时候,就是对类进行了一次实例化,也就是说,其本身就是一个实例化过程,最开始程序进入Class类,加载了name字段(在父类Model中初始化字段,对字段进行约束),也就是说在这时候就已经有了self.name,那么我就就可以在init后对self.name进行覆盖:
class Class(models.Model):
def __init__(self,name):
self.name = name # 放在init之前无效
super().__init__() # 这里会重置、分配name字段,之后实例化的self.name 就可以用于赋值
self.name = '123' # 也就是说使用这种方法赋值,必须放在init后面,且,所有赋值的原理都是如此
name = models.CharField(max_length=12)
注意:重构init方法的时候,一定要使用super().init(),否则会报studen对象没有_state的属性。
# 4. 查询所有的学生信息
使用all()方法获取所有的数据
Student.objects.all()
# 4. 查询所有女学生的姓名和出生日期
Student.objects.filter(stusex=0)
或者
Student.objects.exclude(stusex=1)
其中:
filter():返回符合条件的数据
exclude():过滤掉符合条件的数据
# 5.查询所有的学生,按照id从大到小排序
Student.objects.all().order_by('-id')
其中:
order_by('id'):表示按照id升序的排列
order_by('-id'):表示按照id降序的排列
# 6. 查询所有的学生信息,并序列化
Student.objects.all().values()
Student.objects.all().values('s_name', 's_age')
# 7.查询所有80后学生的姓名、性别和出生日期(筛选)
Student.objects.filter(stubirth__gte='1980-01-01',
stubirth__lte='1990-01-01')
# 8.查询名字中有王字的学生的姓名(模糊),like '%小%', like '小%',like '%小'
Student.objects.filter(s_name__contains='小')
Student.objects.filter(s_name__startswith='小')
Student.objects.filter(s_name__endswith='小')
# 9.查询id等于1,2的学生信息
# select * from student where id in (1,2)
stus = Student.objects.filter(id__in=[1,2])
# 10. 获取id为1的信息,get()和filter()的使用
Student.objects.filter(id=1)
Student.objects.get(id=1)
Student.objects.get(pk=1)
# get获取不到数据会直接报错, filter获取不到数据是返回空
stus = Student.objects.get(pk=5)
Student.objects.filter(id=5)
# get只能返回一个数据,返回多个会报错
Student.objects.get(s_age=15) # 前提条件:数据库中s_age为15的数据有多条
# 11.获取所有学生(按照id降序)中第一个/最后一个学生信息
# 获取按照id降序的第一个学生信息
Student.objects.all().order_by('-id')[0]
Student.objects.all().order_by('-id').first()
# 获取所有学生(按照id降序)中最后一个学生信息
Student.objects.all().order_by('-id').last()
# 模型加参
1.建表
class Grade(models.Model):
#班级名称
g_name = models.CharField(max_length=10, unique=True, null=False)
class Meta:
db_table = 'grade'
class StudentInfo(models.Model):
#学生信息:地址和电话
address = models.CharField(max_length=50, null=True)
phone = models.CharField(max_length=11, null=True)
class Meta:
db_table = 'stu_info'
class Student(models.Model):
# 长度为10,且唯一不能为空的姓名s_name字段 CharField - 字符串类型
s_name = models.CharField(max_length=10, unique=True, null=False)
# IntegerField - 整型字段
age = models.IntegerField(default=18)
# auto_now_add:表示第一次创建数据时,自动默认为创建的时间
create_time = models.DateTimeField(auto_now_add=True)
# auto_now: 表示修改时,自动更新为修改时间
operate_time = models.DateTimeField(auto_now=True)
# 是否删除
is_delete = models.BooleanField(default=0)
# 定义浮点数总长度3位,小数点后1位(decimal_places=1)
yuwen = models.DecimalField(max_digits=3, decimal_places=1, null=True)
math = models.DecimalField(max_digits=3, decimal_places=1, null=True)
# 一对一:定义在关联的两个模型中的任何一方都可以;地址和学生是一一对应的,排除兄弟情况
stuinfo = models.OneToOneField(StudentInfo, related_name='stu', on_delete=models.CASCADE, null=True)
# 一对多:只能定义在‘多’的一方,一个班级对应多个学生
grade = models.ForeignKey(Grade, related_name='stu', on_delete=models.CASCADE, null=True)
class Meta:
db_table = 'student'
2.数据库迁移
python manage.py makemigrations
python manage.py migrate
# 模型对应关系描述如下:
1:1 一对一 OneToOneField :两方都可以 1:N 一对多 ForeignKey :只能写在多的一方 M:N 多对多 ManyToManyField 会自动建一个中间表 :两方都可以
# 在views.py文件中
def add_stu_info(request):
if request.method == 'GET':
# 向拓展表中添加信息
stu_info = StudentInfo() #这里是实例直接执行了Model中的__init__,我们也可以自己定义__init__
stu_info.phone = '13545455433'
stu_info.save()
s_id = stu_info.id
stu = Student.objects.filter(s_name='小明').first()
# 第一种写法: 学生对象.OneToOneField管理对象 = 关联对象,这就相当于stuinfo是一个连接外表的外键,指向与外表的一条记录,这里的stu_info,相当于一条记录,下面的方法相当于讲小明这条记录,与刚创建的stu_info记录的主键进行了绑定
stu.stuinfo = stu_info
# 第二种写法: 学生对象.OneToOneField字段 = 关联对象.id,这个就相当于对每个字段进行赋值了:student_id = '2',记主键之间的绑定
stu.stuinfo_id = stu_info.id
stu.save()
return HttpResponse('添加拓展表信息')
def sel_stuinfo_by_stu(request):
if request.method == 'GET':
# 通过学生信息找拓展表信息
stu = Student.objects.get(s_name='小明')
# StudentInfo.objects.get(pk=stu.stuinfo_id) # 等价于stu.stuinfo,都是找主键
# 学生对象(stu).OneToOneField字段(stuinfo)
stu.stuinfo
return HttpResponse('获取拓展表信息成功')
def sel_stu_by_info(request):
if request.method == 'GET':
# 通过拓展表中的手机号码找学生信息
stuinfo = StudentInfo.objects.filter(phone='13545455433').first()
# stu = Student.objects.filter(stuinfo=stuinfo) #通过学生表的关联表找
# stu = Student.objects.filter(stuinfo_id=stuinfo.id) # 通过一个student_id修改
# print(stu)
# 拓展表对象.关联的模型名称小写
# stu = stuinfo.student # 和上面两步一样,这步很简单,已经知道stuinfo了,让其.student
# 定义related_name参数, 拓展表对象.related_name值
stu = stuinfo.stu # 这的stu是onetonoe字段的related_name参数,它和上面那步是互斥的
print(stu)
return HttpResponse('通过拓展表信息查询学生表信息')
def add_grade(request):
if request.method == 'GET':
# 添加班级信息, 并给学生分配班级
names = ['Python班级', 'Java班级', 'Php班级', 'C++班级']
for name in names:
if Grade.objects.filter(g_name=name).exists():
Grade.objects.creat(g_name=name)
# 分配班级
stus = Student.objects.filter(pk_in=[5, 6, 7, 10, 11, 12]).all()
g = Grade.objects.filter(g_name='Python班级').first()
for stu in stus:
stu.grade = g
# stu.grade_id = g.id
stu.save()
return HttpResponse('添加班级和学生信息')
def sel_grade_by_stu(request):
if request.method == 'GET':
# 通过学生查询班级信息
stu = Student.objects.filter(s_name='小明').first()
g = stu.grade
print(g)
# 班级查询学生
stus = g.student_set.all() # 和下面一样
stus = g.stu.all() # 定义了related_name='stu',但是用了related_name之后,就不能用_set了
return HttpResponse('通过学生查询班级成功')
# 多对多
先声明两个类Course, Student
class Course(models.Model):
c_name = models.CharField(max_length=10, unique=True, null=False)
class Meta:
# 指定表名
db_table = 'course'
class Student(models.Model):
# 长度为10,且唯一不能为空的姓名s_name字段 CharField - 字符串类型
s_name = models.CharField(max_length=10, unique=True, null=False)
# IntegerField - 整型字段
age = models.IntegerField(default=18)
# auto_now_add:表示第一次创建数据时,自动默认为创建的时间
create_time = models.DateTimeField(auto_now_add=True)
# auto_now: 表示修改时,自动更新为修改时间
operate_time = models.DateTimeField(auto_now=True)
# 是否删除
is_delete = models.BooleanField(default=0)
# 定义浮点数总长度3位,小数点后1位(decimal_places=1)
yuwen = models.DecimalField(max_digits=3, decimal_places=1, null=True)
math = models.DecimalField(max_digits=3, decimal_places=1, null=True)
# 多对多
course = models.ManyToManyField(Course, related_name='stu')
class Meta:
db_table = 'student'
views.py文件中
def add_course(request):
if request.method == 'GET':
# 添加课程信息
names = ['大学语文', '日语', '数电', '模电']
for name in names:
cou = Course()
cou.c_name = name
cou.save()
return HttpResponse('添加课程成功')
def sel_cou_by_stu(request):
if request.method == 'GET':
# 查询id为1的学生所选择的课程信息
stu = Student.objects.get(pk=1)
# 学生查找课程
stu.course
# 课程查询学生
cou = Course.objexts.get(pk=1)
cou.student_set.all() # student是小写的类名, 没有related_name之前可以用
cou.stu.all()
return HttpResponse('多对多的查询成功')
def add_del_stu_cou(request):
if request.method == 'GET':
# 增删中间表的信息
# 给小王分配'日语', '数电', '模电'
stu = Student.objects.filter(s_name='小明').first()
cou1 = Course.objects.get(c_name='日语')
cou2 = Course.objects.get(c_name='数电')
cou3 = Course.objects.get(c_name='模电')
# 新增中间表数据
stu.course.add(cou1)
stu.course.add(cou2)
stu.course.add(cou3) # add方法加入课程(flask中用的append), 此时中间表就有信息了
# cou1.stu.add(学生对象) # 和上面一样的
# 删除中间表数据 stu.course此时有3门课程
stu.course.remove(cou2)
stu.course.remove(cou3) # 此时删掉了数电和模电课程
return HttpResponse('操作中间表信息成功')
def on_delete_stu(request):
if request.method == 'GET':
# 演示删除, on_delete参数的效果
stuinfo = StudentInfo.objects.get(id=6)
stuinfo.delete()
# models.CASCADE 表示:主键所在行的数据被删, 外键所在行的数据也会被删
# models.PROTECT 表示:主键有对应的外键数据时, 不让删除主键的数据
# models.SET_NULL 表示:主键删除, 外键置空
# 常用的就上面三个
return HttpResponse('on_delete演示成功')
# 模型关联关系
# 一对一
class A():
id = modules.IntegerFiled()
class B():
aa = mldels.OneToOneField(A, on_delete=models.CASCADE, null=True,related_name='cc')
- OneToOneField(关联模型)
- 模型定义
- 关联名 = models.OneToOneField(关联的表名, related_name = '关系名', on_delete=models.CASCADE, null=True)
- 已知 A 对象 a 查询 B 对象
- 当 related_name 没定义时: a.b
- 当 related_name = 'cc'时: a.cc
- 已知 B 对象 b 查询 A 对象 b.aa
- 一对一:定义在关联的两个模型中的任意一方都可以
# 一对多
class A():
id
class B():
aa = models.ForeignKey(A, on_delete=models.CASCADE, null=True,related_name='cc')
- ForeignKey(关联模型)
- 模型定义
- aa = ForeignKey(A)
- 已知 A 对象 a,查询 B 对象
- 当 related_name 没定义时: a.b_set
- 当 related_name = 'cc'时: a.cc
- 已知 B 对象 b 查询 A 对象 b.aa
- 一对多:定义在'多'的一方
# 多对多
- course = models.ManyToManyField(Course 要进行关联的表的名字,related_name='stu') 会自动生成中间文件,中间文件的表名为 course
- 查询 id 为 1 的学生课程信息
- stu = Student.objects.get(pk=1)
- 学生查询课程
- stu.course
- 课程查询学生
- cou = Course.objects(pk=1)
- 当 related_name 没定义时: cou.student_set.all()
- 当 related_name 定义时: cou.stu.all()
- 增加中间表信息
- stu = Student.objects.filter(s_name = '小明').first()
- cou1 = Course.objects.get(c_name='日语')
- stu.course.add(cou1)
- 删除中间表信息
- stu.course.remove(cou1)
- on_delete 参数
- models.CASCADE 表示: 主键所在行的数据被删,外键所在行的数据也会被删
- models.PROTECT 表示: 主键有对应的外键数据时,不让删除主键的数据
- models.SET_NULL 表示: 主键删除,外键置空
- 注意: ManyToManyFiled 定义的字段定义在任何一个关联模型中都可以