当前位置 : 主页 > 编程语言 > python >

Django 如何使用 Exists

来源:互联网 收集:自由互联 发布时间:2023-02-04
Django ORM 模型 class Base(models.Model): set_null = { 'null': True, 'blank': True } set_fk = { 'db_constraint': False, 'on_delete': models.SET_NULL } set_mtm = { 'db_constraint': False, } class Meta: abstract = Trueclass Student(Base): n

Django ORM 模型

class Base(models.Model): set_null = { 'null': True, 'blank': True } set_fk = { 'db_constraint': False, 'on_delete': models.SET_NULL } set_mtm = { 'db_constraint': False, } class Meta: abstract = True class Student(Base): name = models.CharField(max_length=10, **Base.set_null) age = models.IntegerField(**Base.set_null) classes = models.ManyToManyField('Class', related_name='student_class', **Base.set_mtm) class Meta: db_name = 'student' class Class(Base): name = models.CharField(max_length=10, **Base.set_null) class Meta: db_name = 'classes' class Middle(Base): category = models.CharField(max_length=10, **Base.set_null) name = models.CharField(max_length=10, **Base.set_null) value = models.CharField(max_length=10, **Base.set_null) class Meta: db_table = 'tb_middle' class A(Base): model = models.ForeignKey( 'Middle', related_name='a_model', **Base.set_fk, **Base.set_null ) class Meta: db_table = 'tb_a'

sql 中 where 使用

SELECT name FROM student WHERE age > 18;

在执行这条 SQL 语句的时候,DBMS 会扫描 student 表中的每一条记录,然后把符合 age 大于 18 这个条件的所有记录筛选出来,并放到结果集里面去。也就是说 WHERE 关键字的作用就是判断后面的逻辑表达式的值是否为 True。如果为 True,则将当前这条记录(经过 SELECT 关键字处理后)放到结果集里面去,如果逻辑表达式的值为 False 则不放。

sql 中的 exists

有个哥们讲的很适合初学者

概念:EXISTS 运算符用于判断查询子句是否有记录,如果有一条或多条记录存在返回 True,否则返回 False。

执行流程:先执行子查询,得到一个集合(或值),然后将这个集合(或值)作为一个常量带入到父查询的 WHERE 子句中去。

案例

查询选择课程是语文课程的所有学生名称

SELECT "app1_student"."name" FROM "app1_student" WHERE EXISTS ( SELECT U0."id", U0."name" FROM "app1_class" U0 INNER JOIN "app1_student_classes" U1 ON ( U0."id" = U1."class_id" ) WHERE ( U0."name" = 语文 AND U1."student_id" = "app1_student"."id" ) )

django 中 exists

官方文档

官方描述:Exists 是一个 Subquery 子类,它使用 SQL EXISTS 语句。在许多情况下,它的性能比子查询更好,因为当找到第一条匹配的记录时,数据库能够停止对子查询的执行。

案例一

上面的案例 Django 中可以这样写

# 方法一 原生sql 见上 queryset = Student.objects.filter(Exists(Class.objects.filter(student_class=OuterRef('pk'), name='语文'))).values('name') # 方法二 queryset = Student.objects.filter(classes__name='语文').values('name')

方法二 sql

SELECT "app1_student"."name" FROM "app1_student" INNER JOIN "app1_student_classes" ON ( "app1_student"."id" = "app1_student_classes"."student_id" ) INNER JOIN "app1_class" ON ( "app1_student_classes"."class_id" = "app1_class"."id" ) WHERE "app1_class"."name" = 语文

根据真实情况选择不同查询方式。遵循尽可能使用一次数据库交互数据数据。

案例二

获取 tb_middle 中 category 为 a_model 且排除已经和tb_a 表存在关联的表 tb_middle 字段 name value的数据

思路

  • 查询表 tb_middle 已经被使用的数据
  • filter中过滤掉被使用的数据

达到了效果,却需要查询两次数据库。而且,在书写python比较繁琐

Middle.objects.filter(category=category).filter( ~Exists(A.objects.filter(model=OuterRef('pk'))) ) # Exists 存在 | ~Exists 不存在

下次更新 annotate subquery 使用方法...

网友评论