第九节:记录操作之增删改查

记录操作之增删改查

一、单表

1、 添加记录

准备表

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=65,decimal_places=5)
    publish = models.CharField(max_length=30)
    pub_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "%s:%s:%s" %(self.id,self.title,self.price)

添加记录的两种方式

# 方式一
obj=Book.objects.create(title="葵花宝典",price=100,publish="苹果出版社")

# 方式二:
obj=Book(title="九阴真经",price=100,publish="苹果出版社")
obj.save()

添加n条记录为后续操作做准备

Book.objects.create(title="红龙梦",price=300,publish="66出版社")
Book.objects.create(title="钢弹是怎样炼成的",price=10,publish="新华出版社")
Book.objects.create(title="聊斋",price=50,publish="77出版社")
Book.objects.create(title="老女人与海王",price=30,publish="33出版社")
Book.objects.create(title="西游记",price=43,publish="88出版社")

2、单表查询

查询API

<1> all():                  查询所有结果

<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象

<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
                            如果符合筛选条件的对象超过一个或者没有都会抛出错误。

<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象

<5> order_by(*field):       对查询结果排序('-id')

<6> reverse():              对且只对order_by排序的结果进行翻转

<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。

<9> first():                返回QuerySet集中的第一个对象  

<10> last():                返回QuerySet集中的最后一个对象 

<11> exists():              如果QuerySet包含数据,就返回True,否则返回False

<12> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列

<13> values_list(*field):   它与values()非常相似,但返回的是一个元组序列

<14> distinct():            从返回结果中剔除重复纪录

示例

# QuerySet数据类型(类似于一个列表,里面放着一些对象)
# 1 方法的返回值是什么
# 2 方法的调用者

===============调用者为管理器,返回值为一个记录对象=========
obj = Book.objects.get(title="聊斋")
print(obj)  # 结果为:Book object (5)
print(obj.title)
# 若找不到符合条件的记录则报错
Book.objects.get(title="跟Egon学养猪小妙招")  # 报错

===============调用者为管理器,返回值为QuerySet=========
# 1、all:
book_list = Book.objects.all()
print(book_list)  # 结果是一个QuerySet
print(book_list[0].title)
for obj in book_list:
    print(obj.title)

# 2、filter
book_list = Book.objects.filter(title="聊斋")  # 相当于where,还可以使用基于双下划线的模糊查询

# 3、exclude
book_list = Book.objects.exclude(title="聊斋")  # 除了title="聊斋"之外的都留下来

===============调用者为QuerySet,返回值。。。=========
# 1、count(): 返回的是整型
n = Book.objects.all().count()
print(n)  # 7

# 2、first():返回的是一个记录对象             
obj = Book.objects.all().first()
print(obj)  
print(obj.id)  # 1

# 3、last():返回的是一个记录对象     
obj = Book.objects.all().last()
print(obj)  
print(obj.id)  # 7

# 4、exists():返回的是布尔值
res = Book.objects.filter(title="跟Egon老师学算命").exists()
print(res)  # False

# 5、order_by(*field):返回的同样是QuerySet
objs = Book.objects.filter(id__lte=6)
print(objs)  # QuerySet
print(objs.order_by('price','-id'))  # 先按照price字段升序排,若price相同则按照id字段降序排

# 6、reverse():返回的同样是QuerySet    
objs = Book.objects.all()

无效
print([obj.id for obj in objs])
print([obj.id for obj in objs.reverse()])  # 顺序与上面保持一致

有效
print([obj.id for obj in objs.order_by('-id')])
print([obj.id for obj in objs.order_by('-id').reverse()])  # 顺序在上面的排序的基础上翻转

# 7、values(*field): 返回的同样是QuerySet
objs = Book.objects.filter(id__gte=3)
print(objs.values("title"))  # 返回一个QuerySet
print(objs.values("title")[0]['title'])  # 红龙梦
print(objs.values("title").last()['title'])  # 西游记

# 8、values_list(*field): 返回的同样是QuerySet 
objs = Book.objects.filter(id__gte=3)
print(objs.values_list("title"))
print(objs.values_list("title")[0][0])  # 红龙梦
print(objs.values_list("title").last()[0])  # 西游记

# 9、distinct(): 返回的同样是QuerySet
Book.objects.all().distinct()  # 该行代码无意义,因为每一条结果多不是重复的

正确用法如下
objs = Book.objects.all().values("price").distinct()
print(objs)

基于双下划线的模糊查询

Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__gte=100)
Book.objects.filter(price__lte=100)

# 等同于Book.objects.filter(id__gte=100,id__lte=200)
# 相当于where price between 100 and 200
Book.objects.filter(price__range=[100,200])  

Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")  # 忽略大小写
Book.objects.filter(title__startswith="py")
Book.objects.filter(title__iendswith="py")

Book.objects.filter(pub_date__lte="2021-02-23 17:51:00")
Book.objects.filter(pub_date__minute="38")

3、单表delete

删除delete:调用者只能是QuerySet或者单个一个记录对象

*# 批量删除
objs = Book.objects.filter(id__in=[1,3,5])
objs.delete()


# 删除单一记录
objs = Book.objects.filter(id=6)
obj=objs[0]
obj.delete()

*objs.last().delete()

在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:

Entry.objects.all().delete() 

如果不想级联删除,可以设置为:

pubHouse = models.ForeignKey(to=’Publisher’, on_delete=models.SET_NULL, blank=True, null=True)

4、单表update

修改update:调用者只能是QuerySet,返回值为int

objs = Book.objects.filter(id=7)
rows=objs.update(title="xxx")    
print(rows)

Book.objects.filter(name='跟Egon学算命').first().update(name='大家多能成神仙')  # 报错

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

二、多表

准备多对多、一对多、一对一关系如下

from django.db import models

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    # 阅读数
    # read_num=models.IntegerField(default=0)
    # 评论数
    # comment_num=models.IntegerField(default=0)

    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)

class AuthorDatail(models.Model):
    nid = models.AutoField(primary_key=True)
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

生成的表如下:

1、添加记录

多对一关系添加:app01_book与app01_publish

from app01.models import *

# 先创建出版社
publish_obj = Publish.objects.create(name="666出版社", city="上海")

# 再创建书籍与出版社关联,具体有两种方式
# 方式一
Book.objects.create(name="跟egon学算命", price=3, publish=publish_obj)

# 方式二
book_obj = Book(name="跟egon学风水", price=5)
book_obj.publish_id = publish_obj.nid
book_obj.save()

# 思考:
book_obj.publish与book_obj.publish_id是什么?

清理掉多对一的关系

# 可以只删掉一个书籍对象
Book.objects.filter(name="跟egon学算命").delete()

# 因为级联删除的存在,所以删出一个版社对象,对应的书籍对象会一并清除
Publish.objects.filter(name="666出版社").delete()

一对一关系添加(与多对一一样):app01_autor与app01_authordatail

# 先创建作者详情
obj = AuthorDatail.objects.create(telephone=1861131111,birthday="2011-11-11",addr="水帘洞")

# 再创建作者信息
Author.objects.create(name='Egon',age=18,author_detail=obj)

清理掉一对一关系(同多对一一样)

# 建议删作者时直接删除作者详情,这样便级联删除了作者
AuthorDatail.objects.filter(nid=1).delete()

# 如果只删作者,作者详情当然还是会存在的
Author.objects.filter(nid=1).delete()

多对多关系添加:app01_autor,app01_book_autors,app01_book

=====下述记录如果已经存在了就不用创建了,直接过滤出来用就可以了,如果删掉了,那就重新建一遍
# 1、添加作者及其详情
obj = AuthorDatail.objects.create(telephone=1861131111,birthday="2011-11-11",addr="水帘洞")
Author.objects.create(name='Egon',age=18,author_detail=obj)

obj = AuthorDatail.objects.create(telephone=1361131111,birthday="2022-12-12",addr="盘丝洞")
Author.objects.create(name='Tom',age=18,author_detail=obj)

obj = AuthorDatail.objects.create(telephone=1761131111,birthday="2013-10-10",addr="金光洞")
Author.objects.create(name='Jack',age=18,author_detail=obj)

# 2、添加书籍
publish_obj = Publish.objects.create(name="666出版社", city="上海")
Book.objects.create(name="跟egon学算命", price=3, publish=publish_obj)
Book.objects.create(name="跟egon学风水", price=3, publish_id=publish_obj.nid)

===添加作者与书的多对多关系
# 过滤出书籍对象
book_obj1 = Book.objects.filter(name="跟egon学算命").first()
book_obj2 = Book.objects.filter(name="跟egon学风水").first()

# 过滤出作者对象
egon = Author.objects.filter(name="egon").first()
tom = Author.objects.filter(name="Tom").first()
jack = Author.objects.filter(name="Jack").first()

# 添加关系
book_obj1.authors.add(egon,tom,jack)
book_obj2.authors.add(egon,jack)
ps: 也可以直接传id
book_obj1.authors.add(1,2,3)  # 或者用形式*[1,2,3]

查看app01_book_authors记录如下
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
|  1 |       1 |         1 |
|  2 |       1 |         2 |
|  3 |       1 |         3 |
|  4 |       2 |         1 |
|  5 |       2 |         3 |
+----+---------+-----------+

清理掉多对多关系

# remove:下面三种方式都可以
book_obj1.authors.remove(egon,tom)
book_obj1.authors.remove(1,2)
book_obj1.authors.remove(*[1,2])

查看app01_book_authors记录如下
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
|  3 |       1 |         3 |
|  4 |       2 |         1 |
|  5 |       2 |         3 |
+----+---------+-----------+

# clear(): 清空被关联对象集合
book_obj2.authors.clear()

查看app01_book_authors记录如下
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
|  3 |       1 |         3 |
+----+---------+-----------+

# set(): 先清空再设置,只能传入一个序列,里面包含要添加的作者对象或者作者对象的id都可以
book_obj1.authors.set([egon,2])

2、查询记录

1.多表查询的法则提炼如下

• 第一步:先搞清楚是正向查询还是反向查询

关联字段所在的表可以称之为源表,被关联的表称之为目标表,如此,正向反向一目了然了

• 第二步

*# 基于对象的查询相当于子查询(其实本质是分步查询)
* 正查用关联字段
* 反查用模型名,但如果反查的结果有多个值则要加_set


# 基于双下划线的查询相当于join链表
* 正查用关联字段
\
反查用模型名

2.基于对象的子查询

多对一查询:app01_book与app01_publish

# 正向案例:查询”跟egon学算命“是哪个出版社出版的
book_obj=Book.objects.filter(name="跟egon学算命").first()
print(book_obj.publish.name)  # 正向查询直接用关联字段,即publish即可

# 反向案例:查询”666出版社“出版的所有书籍
publish_obj = Publish.objects.filter(name="666出版社").first()
print(publish_obj.book_set.all())  # 反向查询用模型名,结果有多个,所有还有加_set,返回QuerySet

一对一查询:app01_autor与app01_authordatail

# 正向案例:查询”Egon“的手机号
egon=Author.objects.filter(name="Egon").first()
print(egon.author_detail.telephone)  # 正向查询直接用关联字段,即author_detail即可

# 反向案例:查询”nid=1的详情信息对应的作者名字“
obj = AuthorDatail.objects.filter(nid=1).first()
print(obj.author.name)  # 反向查询用模型名,结果只有一个,所有author后无需加_set

多对多查询:app01_autor,app01_book_autors,app01_book

# 正向案例:查询”跟egon学算命“的所有作者
egon = Book.objects.filter(name="跟egon学算命").first()
print(egon.authors.all())  # 正向查询直接用字段authors即可,而authors有多个,所以需要加all()

# 反向案例:查询”Egon“都出了哪些书
egon = Author.objects.filter(name="Egon").first()
print(egon.book_set.all())  # 反向查询用模型名,结果有多个,所有还有加_set,返回QuerySet

3.基于双下划线的链表查询

多对一查询:app01_book与app01_publish

# 1、查询”跟egon学算命“是哪个出版社出版的
===>正查
res = Book.objects.filter(name="跟egon学算命").values_list("publish__name")
print(res)  # <QuerySet [('666出版社',)]>

===>反查
res = Publish.objects.filter(book__name="跟egon学算命").values_list("name","city")
print(res)  # <QuerySet [('666出版社', '上海')]>

# 2、查询”666出版社“出版的所有书籍
===>正查
res = Publish.objects.filter(name="666出版社").values_list("book__name")
print(res)  # <QuerySet [('跟egon学算命',), ('跟egon学风水',)]>

===>反查
res = Book.objects.filter(publish__name="666出版社").values_list("name")
print(res) # <QuerySet [('跟egon学算命',), ('跟egon学风水',)]>

一对一查询:app01_autor与app01_authordatail

# 1、查询”Egon“的手机号
===>正查
res = Author.objects.filter(name="Egon").values_list("author_detail__telephone")
print(res)  # <QuerySet [(1861131111,)]>

===>反查
res = AuthorDatail.objects.filter(author__name="egon").values("telephone")
print(res)  # 名字的大小写不重要,因为mysql中的查询默认也忽略大小写

# 2、查询”nid=1的详情信息对应的作者名字“
===>正查
res = Author.objects.filter(author_detail__nid=1).values_list("name")
print(res)  # <QuerySet [('EGON',)]>

===>反查
res = AuthorDatail.objects.filter(nid=1).values_list("author__name")
print(res)  # <QuerySet [('EGON',)]>

多对多查询:app01_autor,app01_book_autors,app01_book

# 正向案例:查询”跟egon学算命“的所有作者
===>正查
res = Book.objects.filter(name="跟egon学算命").values_list("authors__name")
print(res)  # <QuerySet [('EGON',), ('Tom',), ('Jack',)]>

===>反查
res = Author.objects.filter(book__name="跟egon学算命").values_list("name")
print(res)  # <QuerySet [('EGON',), ('Tom',), ('Jack',)]>

# 查询”Egon“都出了哪些书
===>正查
res = Author.objects.filter(name="egon").values_list("book__name")
print(res)  # <QuerySet [('跟egon学算命',), ('跟egon学风水',)]>

===>反查
res = Book.objects.filter(authors__name="egon").values_list("name")
print(res)  # <QuerySet [('跟egon学算命',), ('跟egon学风水',)]>

如果有必要,你可以一直连续跨表

# 1、查询“666出版社”出版过的所有书籍及期作者名字
===>正查
res = Book.objects.filter(publish__name="666出版社").values_list("name","authors__name")
print(res)

<QuerySet [('跟egon学算命', 'EGON'), ('跟egon学算命', 'Tom'), ('跟egon学算命', 'Jack'), ('跟egon学风水', 'EGON'), ('跟egon学风水', 'Jack')]>

===>反查
res = Publish.objects.filter(name="666出版社").values_list("book__name","book__authors__name")
print(res)

# 2、2011年出生的作者出版过的所有书籍名称以及出版社名称
===>正查
res=Book.objects.filter(authors__author_detail__birthday__year=2011).values_list("name","publish__name")
print(res)
<QuerySet [('跟egon学算命', '666出版社'), ('跟egon学风水', '666出版社')]>

===>反查
res=AuthorDatail.objects.filter(birthday__year="2011").values_list("author__book__name","author__book__publish__name")
print(res)

三、查询相关参数补充

1、多对对参数:symmetrical

仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。

举个例子:

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self")
此时,person对象就没有person_set属性。

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self", symmetrical=False)
此时,person对象现在就可以使用person_set属性进行反向查询。

2、foreign key参数:related_name与related_query_name

related_name = "xxx"
反向:小写模型名_set 换成 xxx

related_query_name = "xxx"
反向:小写模型名_set 换成 xxx_set

例如:

class Classes(models.Model):
    name = models.CharField(max_length=32)

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().student_set.all()
当我们在ForeignKey字段中添加了参数 related_name 后,

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes", related_name="students")
当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().students.all()

四、*聚合与分组查询*

1、annotate

分组查询annotate等同于mysql的group by,但是annotate的分组要分两种情况讨论

1、默认以表的主键字段分组

管理器objects左边的那个模型是谁就以谁的主键字段作为分组依据,例如Book.objects.annotate(),则按照Book的主键字段分组

举例

# 1、每本书的作者个数
res=Book.objects.annotate(authors_num=Count('authors')).values("name","authors_num")
print(res)

原生sql分析:
会先链接表app01_book和app01_authors,然后再按照app01_book表的主键字段分组,此处app01_book表的主键字段为nid

# 2、每个出版社卖的最便宜的那本书的价格
res=Publish.objects.annotate(x=Min("book__price")).values("x")
print(res)  # <QuerySet [{'x': Decimal('2.00')}]>

原生sql分析:同上

# 3、统计不止一个作者的图书
res = Book.objects.annotate(n=Count("authors")).filter(n__gt=1).values_list("name", "n")
print(res)

# 4、查询每个作者的书的总价格
res=Author.objects.annotate(s=Sum("book__price")).values('s')
print(res)

原生sql分析:
会先链接表app01_author、app01_book_authors、app01_book
然后再按照app01_author表的主键字段分组,此处为app01_author.nid

2、如果想按照指定的字段分组,则需要引入values()

annotate()前面的出现了values(),就会以values()中指定的字段分组
如果没有,就会默认按照模型的主键字段分组,例如
Book.objects.values("price").annotate() # 按照Book模型的price字段分组

# 1、统计每年出版的书个数
res=Book.objects.values("publish_date__year").annotate(n=Count("nid")).values("publish_date__year","n")
print(res)

# 输出结果
<QuerySet [{'publish_date__year': 2021, 'n': 2}, {'publish_date__year': 2022, 'n': 1}]>

如果我们想统计哪一年哪一月出版的书个数,需要用到date_format函数,此时就需要调用extra来执行date_format了,如下,注意%要连续写两个,第一个代表取消第二%的特殊意义

res=Book.objects.extra(select={"y_m":"date_format(publish_date,'%%Y-%%m')"}).values("y_m").annotate(n=Count("nid")).values("y_m","n")

print(res)  

# 输出结果
<QuerySet [{'y_m': '2021-02', 'n': 2}, {'y_m': '2022-02', 'n': 1}]>

ps:

在严格模式下(ONLY_FULL_GROUP_BY)分组之后默认只能获取分组依据,若查询了非分组字段,会导致错误,需要修改数据库模式:

#设置sql_mole如下操作(我们可以去掉ONLY_FULL_GROUP_BY模式):
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

五、F查询与Q查询

1、 aggregate

若想把整张表当成一个组来使用聚合函数,应该调用aggregate

# 1、先导入聚合函数
from django.db.models import Max, Min, Avg, Sum, Count
"""
小窍门:
只要是跟数据库相关的模块基本都在django.db.models里面
如果没有那么应该在django.db里
"""

# 2、查询所有作者的最大nid、最小年龄、平均年龄、年龄之和、作者个数

res = Author.objects.aggregate(
        Max("age"),
        Min("age"), 
        Avg("age"), 
        Sum("age"), 
        Count("nid")
    )

print(res)  # 调用的sql为:select avg("age"),max("nid"),... from app01_author;
{'age__max': 30, 'age__min': 10, 'age__avg': 20.0, 'age__sum': 60, 'nid__count': 3}

# 3、也可以指定key值
res = Author.objects.aggregate(
        x=Max("age"),
        y=Min("age"),
    )
print(res) 
{'x': 30, 'y': 10}

2、F查询

F查询够帮你直接获取到表中的某个字段对应的值,具体应用如下

# 修改模型Book增加阅读数与评论数字段,然后重新迁移数据库,新增好记录
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    # 阅读数
    read_num=models.IntegerField(default=0)
    # 评论数
    comment_num=models.IntegerField(default=0)

    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name

from django.db.models import F
# 1、查询阅评论数大于阅读数的书籍名
res = Book.objects.filter(comment_num__gt=F("read_num"))
print(res)

# 2、将所有书的价格在原来的基础上增加50元
Book.objects.update(price=F("price")+50)

注意,针对数字运算,F可以直接与数字进行数学运算,但如果我们想拼接字符串,则需要引入Concat并配合Value一起实现,如下

# 3、将所有书籍的名称后面加爆款两个字
from django.db.models.functions import Concat
from django.db.models import Value, F

Book.objects.update(name=Concat(F('name'), Value("爆款")))
# Book.objects.update(name=F('name') + "爆款")  # 错误,所有书的名字都会被改为0

3、Q查询

对于filter()方法内逗号分隔开的多个条件,都是and关系,如果想用or或者not关系,则需要使用Q

from django.db.models import Q

Book.objects.filter(Q(nid__gte=3), Q(nid__lte=5))  # 还是and关系
Book.objects.filter(Q(nid__lte=3) | Q(nid__gte=5))  # or关系

Book.objects.filter(~Q(nid__gt=2))  # ~ 等同于在条件前加了not  代表: ! nid>2即nid<=2
Book.objects.filter(~Q(nid__gt=2) | Q(nid__gte=5))  #  代表nid<=2 or nid>=5

Q查询的高阶用法:能够以字符串作为查询字段

q = Q()
q.children.append(('nid__gt', 2))  # 条件中引用的字段为字符串类型
q.children.append(('price__lt', 50))
res = Book.objects.filter(q)  # filter内可以直接放q对象,默认还是and关系
print(res)

q = Q()
q.connector = 'or'
q.children.append(('nid__lte', 2))
q.children.append(('nid__gte', 5))
res = Book.objects.filter(q)  # 此时是or关系
print(res)

# 那什么场景下,我们查询条件中的字段是字符串类型呢?
# 比如我们制作一个搜索功能,我们需要根据用户输入搜索字段完成查询,而用户输入的都是字符串类型,此时就用到了Q的高阶用法
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术