模型之间可以有三种表关系,即一对一,一对多和多对多。表关联之间的数据操作在Django中可以很方便的操作到。在模型中,表关联的字段类型是关联表的实例,而不是字段本身类型。关联字段在数据库中会在其后补上_id,这才是关联字段本身的类型。这句话听起来很绕,下面具体来看看。

下面是学生和学院的表模板。

class Student(models.Model):#学生表
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
department = models.ForeignKey('Department',on_delete=models.CASCADE,related_name = 'student',null=True)
course = models.ManyToManyField('Course',related_name='student') def __str__(self):
return ('Student<id = {},name={},department={}>'.format(self.s_id, self.s_name,self.department_id)) class Department(models.Model): #学院表
d_id = models.AutoField(primary_key=True)
d_name = models.CharField(max_length=15)
def __str__(self):
return('Department<id = {},name={}>'.format(self.d_id,self.d_name))

下面我们为了方便操作,在项目目录下输入python manage.py shell进入交互模式方便操作查看。进入后将所创建的模板都导进去,输入from music.models import Department,Student,Course,Stu_detail 。

  • 下面以第一种方式来添加数据。
>>> s3 = Student(s_name = '小松',department_id = 1)
>>> s3
<Student: Student<id = None,name=小松,department=1>>
>>> s3.save()
>>>

看到上面会有疑问,Student类中的学院属性是department,为什么在实例化会是department_id呢?上面说过,对于关联字段,数据库会自动在其后加上_id,对于int类型是department_id。而关联表实例对象才是department的类型。如果将上述代码的department_id改成department将会报错。

>>> s3 = Student(s_name = '小松',department = 1)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/pyvip/.virtualenvs/Django2.0/lib/python3.5/site-packages/django/db/models/base.py", line 467, in __init__
_setattr(self, field.name, rel_obj)
File "/home/pyvip/.virtualenvs/Django2.0/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 210, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "1": "Student.department" must be a "Department" instance.
  • 第二种方式添加数据
d2 = Department(d_name = '艺术学院')
>>> d2.save()
>>> d2
<Department: Department<id = 2,name=艺术学院>>
>>> s4 = Student(s_name = '小花')
>>> s4.department = d2
>>> s4.save()
>>> s4
<Student: Student<id = 4,name=小花,department=2>>

先创建一个艺术学院,再实例化后点出属性赋值一个学院的实例化。

表关联对像的访问

对于类模板中已有的关联字段,可以直接正向查询得到,如学生的学院表,可以直接点出其department。但对于未有的关联字段,如查询学院表的学生,就无法直接来查询,因为其没有学生这个关联属性。我们可以通过反向查询,即通过小写的关联表名加上_set来查询。

>> s4.department
<Department: Department<id = 2,name=艺术学院>>
>>> d1.student_set.all()
<QuerySet [<Student: Student<id = 1,name=小杰,department=1>>, <Student: Student<id = 2,name=小王,department=1>>, <Student: Student<id = 3,name=小松,department=1>>]>

可以在关联表时加上参数related_name = 小写本表名 ,来取代foo_set。

>>> d1.student.all()
<QuerySet [<Student: Student<id = 1,name=小杰,department=1>>, <Student: Student<id = 2,name=小王,department=1>>, <Student: Student<id = 3,name=小松,department=1>>]>

表关联对象的一些方法

表关联对象除了一对一及一对多中一的这一方,其他的表关系的对象实则是一个管理器对象。如下面的d1.student,这就是一个管理器对象。

>>> d1.student
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0xb639416c>

下面增加一个课程表。

class Course(models.Model): #课程表
c_id = models.AutoField(primary_key=True)
c_name = models.CharField(max_length=15)
def __str__(self):
return('Course<id = {},name={}>'.format(self.c_id,self.c_name))

下面创建一们python课程,通过课程反向查询学生,可以发现这也是一个管理器对象。

>>> c1 = Course(c_name = 'python')
>>> c1.save()
>>> c1.student
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0xb6372a0c>

通过学生查其上的课程也是一样的。

>>> s4.course
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0xb637282c>

下面再加入一个与学生一对一的学生详情表。

class Stu_detail(models.Model): #学生详细表
stu_id = models.OneToOneField('Student',on_delete=models.CASCADE)
age = models.IntegerField()
gender = models.BooleanField(default=1) #默认值1表示男性
city = models.CharField(max_length=15)
def __str__(self):
return ('Stu_detail<id={},age={},gender={},city={}'.format(self.stu_id,self.age,self.gender,self.city))

下面创建一个学生详情的数据,分别通过学生查其详情和通过详情查学生,可以发现其是一个实例,不是一个管理器对象。

ss1 = Stu_detail(stu_id_id = 1,age = 18,gender = 1,city='南昌')
>>> ss1
<Stu_detail: Stu_detail<id=Student<id = 1,name=小杰,department=1>,age=18,gender=1,city=南昌>
>>> ss1.save()
>>> ss1.stu_id
<Student: Student<id = 1,name=小杰,department=1>>
s1.stu_detail
<Stu_detail: Stu_detail<id=Student<id = 1,name=小杰,department=1>,age=18,gender=True,city=南昌>

虽然一对一时,学生类中没有学生详情表的关联字段,但可以直接点出其小写表名,便可查询。

综上可总结出,有管理器对象的是一对多的多和多对多的两个多。管理器有着属于自己的四种常用方法。下面来介绍下:

  • add()方法

add方法可以把已经存在数据库中的模型实例加入到关联对象中去。如创建一个学生,但不指定其所属学院,最后通过以学院的add方法来给其传入一个刚刚创建的学生实例,达到将其添加到指定学院中去。

>>> s5 = Student(s_name = '小龙')
>>> s5.save()
>>> s5
<Student: Student<id = 5,name=小龙,department=None>>
>>> d2.student.add(s5)
>>> s5
<Student: Student<id = 5,name=小龙,department=2>>
>>>
  • create()方法

与add方法不同的是,create方法传入的数据不需要是已存在的。它是添加一个新数据,并将其存入数据库。

>>> d1.student.create(s_name = '小李')
<Student: Student<id = 6,name=小李,department=1>>
  • remove()方法

remove移除,指定将某一实例化的某一关联对象移除掉。如下面将一个学生从一个学院中开除掉。

>>> d2.student.remove(s5)
>>> Student.objects.get(s_id =5)
<Student: Student<id = 5,name=小龙,department=None>>
  • clear()方法

清空方法,可以清空某一实例化的某一个关联字段的所有对象。如将一学院的所有学生都清空掉。

>>> d1.student.all()
<QuerySet [<Student: Student<id = 1,name=小杰,department=1>>, <Student: Student<id = 2,name=小王,department=1>>, <Student: Student<id = 3,name=小松,department=1>>, <Student: Student<id = 6,name=小李,department=1>>]>
>>> d1.student.clear()
>>> d1.student.all()
<QuerySet []>

多表查询

关联表之间可以互相作为桥梁,充当查询条件来查询到指定的值。其基本语法是:正向查询——表名.objects.filter(字段名__字段名 条件语句)  反向查询——表名.objects.filter(小写表名__字段名 条件语句)

下面是正向查询,查询一个学生id为1的学生的详情表

>>> Stu_detail.objects.filter(stu_id__s_id = 1)
<QuerySet [<Stu_detail: Stu_detail<id=Student<id = 1,name=小杰,department=1>,age=18,gender=True,city=南昌>]>

下面是一个反向查询的例子,查询一个名字中带王的所属学院。

>>> Department.objects.filter(student__s_name__contains='王')
<QuerySet [<Department: Department<id = 1,name=信息学院>>]>

聚合查询

通过关键字aggregate可以执行求最大值Amx、最小值Min、计数Count、求和Sum、平均值Avg等。语法规则是:表名.objects.all()aggregrate(Max('字段名'))  ,其返回的是一个字典的类型。在使用聚合查询前,要先记得导包。返回的字典的key部分是django自动生成的‘字段名__函数名',我们也可以自己去一个别名来取代key,即采用赋值的方式,表名.objects.all()aggregrate(别名=Max('字段名'))

>>> from django.db.models import Count,Max,Min,Sum
>>> Student.objects.all().aggregate(Max('s_id'),Min('s_id'),Sum('s_id'),Count('s_id'))
{'s_id__sum': Decimal('21'), 's_id__max': 6, 's_id__min': 1, 's_id__count': 6}

Q查询

Q查询是一个多条件的查询,Q条件之间通过‘&’、‘|’、’~、来分别表示与、或、非。用Q查询前同样也要导包。

from django.db.models import Q

>>> Student.objects.filter(Q(s_id  =1)|Q(s_name__contains='王'))
<QuerySet [<Student: Student<id = 1,name=小杰,department=1>>, <Student: Student<id = 2,name=小王,department=1>>]>
>>> Student.objects.filter(Q(s_id__lte=4)&Q(s_name__contains='王'))
<QuerySet [<Student: Student<id = 2,name=小王,department=1>>]>

F查询

F查询是一个多字段值进行比较的查询。

from django.db.models import F

>>> Student.objects.filter(department__d_id__lt=F('s_id'))
<QuerySet [<Student: Student<id = 2,name=小王,department=1>>, <Student: Student<id = 3,name=小松,department=1>>, <Student: Student<id = 4,name=小花,department=2>>, <Student: Student<id = 5,name=小龙,department=2>>, <Student: Student<id = 6,name=小李,department=1>>]>

上述查询学生所属学院id小于等于其学生id的所有学生。

分组查询

分组查询的关键字是annotate,下面的例子第一个values的作用是以什么进行分组,第二个values的作用是以什么字段输出。

>>> Student.objects.all().values('department').annotate(count = Count('department')).values('department_id','count')
<QuerySet [{'department_id': 1, 'count': 4}, {'department_id': 2, 'count': 2}]>

Django模型基础(三)——关系表的数据操作的更多相关文章

  1. Django 08 Django模型基础3(关系表的数据操作、表关联对象的访问、多表查询、聚合、分组、F、Q查询)

    Django 08 Django模型基础3(关系表的数据操作.表关联对象的访问.多表查询.聚合.分组.F.Q查询) 一.关系表的数据操作 #为了能方便学习,我们进入项目的idle中去执行我们的操作,通 ...

  2. Django——8 关系表的数据操作 表关联对象的访问 多表查询

    Django 关系表中的数据操作 表关联对象的访问 关联对象的add方法 create方法 remove方法 clear方法 多表查询 查询补充 聚合查询 分组查询 F查询 Q查询 关系表的数据操作 ...

  3. 九.django模型基础(三)之关联对象操作及多表查询

    Ⅰ.关系表的数据操作 1.正向 正向:如果一个模型有外键字段,通过这个模型对外键进行操作叫做正向. 1)更新(增) a.通过属性复制 b.通过主键的方式 总结: ForeignKey 字段的更新,跟普 ...

  4. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  5. Django基础五之django模型层(二)多表操作

    一 创建模型 表和表之间的关系 一对一.多对一.多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束. ...

  6. Django 07 Django模型基础2 (常用查询和多表关联)

    Django 07 Django模型基础2 (常用查询和多表关联) 一.常用查询 #查找数据 def search_user(request): #获取 rs = User.objects.first ...

  7. Django 06 Django模型基础1(ORM简介、数据库连接配置、模型的创建与映射、数据的增删改查)

    Django 06 Django模型基础1(ORM简介.数据库连接配置.模型的创建与映射.数据的增删改查) 一.ORM系统 #django模型映射关系 #模型类-----数据表 #类属性-----表字 ...

  8. 06.Django基础五之django模型层(二)多表操作

    一 创建模型 表和表之间的关系 一对一.多对一.多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束. ...

  9. day 70 Django基础五之django模型层(二)多表操作

    Django基础五之django模型层(二)多表操作   本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 ORM ...

随机推荐

  1. 从0开始自己配置一个vps虚拟服务器(3)

    安装数据库mysql,因为这个服务器比较烂,我只能装低版本的数据库.尝试了很多遍,终于装上去了,高版本应该没那么麻烦. 我安装了很多遍,下载的安装包,都没有安装成功. mysql各版本安装地址: (我 ...

  2. UVA - 12166 Equilibrium Mobile (修改天平)(dfs字符串表示的二叉树)

    题意:问使天平平衡需要改动的最少的叶子结点重量的个数. 分析:天平达到平衡总会有个重量,这个重量可以由某个叶子结点的重量和深度直接决定. 如下例子: 假设根结点深度为0,结点6深度为1,若以该结点为基 ...

  3. 超低功耗2.4G收发一体: SI24R1

    Si24R1是一颗工作在2.4GHz ISM频段,专为低功耗无线场合设计,集成嵌入式ARQ基带协议引擎的无线收发器芯片.工作频率范围为2400MHz-2525MHz,共有126个1MHz带宽的信道.同 ...

  4. C#验证码 使用GDI绘制验证码

    首先展示一下效果图如下: C#中的GDI特别方便,很多方法我们只要简单的调用就可以实现很复杂的功能.具体实现过程如下: 首先创建一个windows窗体应用(测试使用,实际开发winform程序时在需要 ...

  5. windows炸鸡啤酒

    20170831 今天郁闷,一台windwos远处不上去,被怼了,只能说我活该,事先不弄清楚自己负责的服务运行机器的管理员. 今天尤其特别想知道这台windows跑了多久(linux:uptime), ...

  6. Spark 2.x 在作业完成时却花费很长时间结束

    使用 Apache Spark 2.x 的时候可能会遇到这种现象:虽然 Spark Jobs 已经全部完成了,但是程序却还在执行.比如我们使用 Spark SQL 去执行一些 SQL,这个 SQL 在 ...

  7. HDU 4921 Map DFS+状态压缩+乘法计数

    算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数. 对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久, ...

  8. POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

    求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的, ...

  9. hdu 1671 Phone List 统计前缀次数

    Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  10. assert和hasattr,getattr,setattr

    assert hasattr(self, 'initial_data'), ( 'Cannot call `.is_valid()` as no `data=` keyword argument wa ...