八.常用查询及关系的实现(二)
1.示例:一对多 学生与学院
1.1结构设计
通过的外键联系起来两表
1.2建立模型
1.建立学生信息表与学院信息表模型
from django.db import models
# Create your models here.
'''
继承自模型类models
模型类和数据库表的关系
属性和表的字段的对应关系
'''
class Department(models.Model):
#学院类
d_id = models.AutoField(primary_key=True) # 设置主键以后,不会再自增长了
d_name = models.CharField(max_length=20)
class Meta:
db_table = 'department' # 给一个表名
def __str__(self):
return self.d_name
class Student(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
#ForeignKey在定义时设置 连接的表名 ,related_name 参数来覆盖foo_set 的名称.
department = models.ForeignKey('Department',on_delete=models.CASCADE)
class Meta:
db_table = 'student'
def _str_(self):
return self.s_name
# 'Srudent<s_id = %s , s_name=%s>'%(
# self.s_id,self.s_name
# )
注意:如果模型I有一个ForeignKey,那么该ForeignKey 所指的模型II实例可以通过一个管理器回前面有ForeignKey的模型I的所有实例。默认情况下,这个管理器的名字为foo_set,其中foo 是源模型的小写名称。在定义时设置related_name 参数来覆盖foo_set 的名称.
1.3 将模型映射到数据库
1.首先执行以下命令,要创建映射文件
python manage.py makemigrations
命令后面可以跟app名称,表示指定对某个app的模型进行映射,没写所有的app都执行.
2.执行以下命令,将映射文件中的映射数据提交到数据库中
python manage.py migrate
3.进入mysql 查看映射的数据库表
- mysql -uroot -pqwe123 进入mysql
- show databases; 查看所有的数据库
- use look; 使用数据库
- show tables 查看数据库
打开数据我们能看到创建的以app名_模型名的数据表,而其他的一些表格是django自动生成的.
注意:如果要删除表,那么可以去django模型中注释掉模型类,然后执行映射的命令,不要手动在命令行里面去删除.
在执行前,保证我们创建模型的APP是已经注册过的APP
注意:在运行之前一定要将PyCharm的程序上传到虚拟机,不然会报一下错误
pymysql.err.OperationalError: (1046, 'No database selected')
django.db.utils.OperationalError: (1046, 'No database selected')
执行过程:
- workon 查看虚拟环境
- workon name 运行虚拟环境
- ls 查看目录下的文件
- cd 项目文件 进入文件
- python manage.py makemigrations 创建映射文件
- python manage.py migrate 映射文件中的映射数据提交到数据库中
- show tables 查看建立的表
1.查看所有数据库 | 2.使用数据库,查看库里的所有表 |
3.查看学院表数据结构 | 4.查看学生表数据结构 |
1.4添加数据
1.在子应用的views中导入models.py文件,写显示函数
from django.shortcuts import render
from django.http import HttpResponse
from .models import Department,Student #导入建立的模型
# Create your views here.
def add_Department_Student(request):
#向学院表与学生表添加信息
#添加学院信息
d1 = Department(d_id = 1 ,d_name = '文学院')
d1.save()
d2 = Department(d_id = 2, d_name = '计算机技术')
d2.save()
#添加学生信息
#方法1 :.第一种方式就是跟之前的一样,用传参的方法添加,需要注意的是外键的值必须是关联表中已经存在的值.
s1 = Student(s_id = 1 , s_name = '忘记',department_id = 2)
s1.save()
#方法2 :用的属性赋值的方式,因为我们在模型类有定义了一个department的属性,而这个属性的对象的类型必须是department表的类实例对象
s2 = Student(s_id = 2 ,s_name = '坚强')
s2.department = d2
s2.save()
s3 = Student(s_id = 3 , s_name = '嘿你好',department_id = 1)
s3.save()
return HttpResponse('插入成功')
2.设置子路由的url
from django.urls import path,re_path
from .import views
urlpatterns = [
#添加学生与学院信息
path('add_Department_Student',views.add_Department_Student ,name = 'add_Department_Student'),
]
3.运行结果:
4.在虚拟机的Mysql中查询新建的表
1.5表关联对象的访问
1.在子应用的views中导入models.py文件,写显示函数
from django.shortcuts import render
from django.http import HttpResponse
from .models import User,BookInfo,Department,Student #导入建立的模型
# Create your views here.
def test_Info_Department_Student(request):
s1 = Student.objects.get(s_id=1) #给学生一个实例对象
d1 = Department.objects.get(d_id=1) #给学院一个实例对象
print(d1.student_set) #反向的时候是一种管理器,里面包含了方法
print(d1.student_set.all()) #.all 拿到该学院学生的所有数据
#add()方法 修改数据,无序用seve()保存,自动保存,适用于 一对多,多对多
d1.student_set.add(s1) #将学生id为1的学生换到学院id为1
# creat()方法 新建数据 一对多,多对多
d1.student_set.create(s_name = '张画') #给学院id为1添加学生
return HttpResponse('访问成功')
2.设置子路由的url
from django.urls import path,re_path
from .import views
urlpatterns = [
#访问学生与学员信息
path('test_Info_Department_Student',views.test_Info_Department_Student ,name = 'test_Info_Department_Student'),
]
3.运行结果:
4.在虚拟机的Mysql中表前后对比
1.6处理关联对象方法
用法同上1.5 (下面是在终端实现的,不过方法是一样的)
1. add(obj1, obj2, ...) 添加的已经存在数据库的数据
添加一指定的模型对象到关联的对象集中。
1.d1.student的管理器有add的方法.
2.例子中的s2能添加成功是因为设置了student表中department字段允许为空了.
2.create(**kwargs) 添加不存在的数据 ,将数据直接存入数据库
创建一个新的对象,将它保存并放在关联的对象集返回新创建的对象
3.remove(obj1, obj2, ...) 从关联的对象集中删除指定的模型对象。
删除的是关系表中的数据的对象集中。
因为我们有修改student表中的department_id字段允许为空,所以当删除的时候这个字段值为NULL.
4.clear() 从关联的对象集中删除所有的对象
注意:注意对于所有类型的关联字段,add()、create()、remove()和clear()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。
2.多对多查询
Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:
# 查询学院名字为‘计算机学院’的学生的信息
Student.objects.filter(department__d_name='计算机学院')
它还可以反向工作。若要引用一个“反向”的关系,只需要使用该模型的小写的名称。
#查询学生名字中包含 '小' 的学生的学院信息
Department.objects.filter(student__s_name__contains='小')
# 查询学号为1的学生所有的课程
Course.objects.filter(student__s_id=1)
# 查询报了课程1的所有的学生
Student.objects.filter(course__c_id=1)
# 查询报了'python'课程的的学生的所属学院的信息
Department.objects.filter(student__course__c_name='python')
关于多对多表查询的详细信息:查看Django(多表查询操作) - SmllNine - 博客园 (cnblogs.com)
3.查询方法补充
3.1 聚合查询
聚合查询:aggregate()是QuerySet 的一个终止子句,它返回一个包含一些键值对的字典
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
3.2分组查询
annotate():为QuerySet中每一个对象都生成一个独立的汇总值。
是对分组完之后的结果进行的聚合
3.3 F查询
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值
3.4 Q查询
Q查询: 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
Q对象可以使用&(and)、|(or)操作符组合起来
使用~(not)操作符在Q对象前表示取反