前言
通过讲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()
注意:重构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()
stu_info.phone = '13545455433'
stu_info.save()
s_id = stu_info.id
stu = Student.objects.filter(s_name='小明').first()
# 第一种写法: 学生对象.OneToOneField字段 = 关联对象
stu.stuinfo = stu_info
# 第二种写法: 学生对象.OneToOneField字段 = 关联对象.id
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) # 和上面一样
# print(stu)
# 拓展表对象.关联的模型名称小写
# stu = 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 定义的字段定义在任何一个关联模型中都可以