django QuerySet

本文深入探讨了Django中QuerySet的工作原理,包括何时及如何评估QuerySet,QuerySet API的使用,以及如何利用QuerySet进行高效的数据查询和操作。文章还详细解释了Q对象和聚合函数的应用,帮助开发者更好地理解和掌握Django的数据库操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:https://docs.djangoproject.com/en/2.0/ref/models/querysets/

相关文章:https://blog.youkuaiyun.com/youyou1543724847/article/details/86425408

1. when QuerySet evaluated

在创建QuerySet后,对QuerySet 进行filter、slice、传递操作,但是这些操作并不会立即导致相关SQL的执行。只有当对Query Set进行evaluate操作时,才会导致操作落库。

什么操作导致Query Set evaluated呢?

  1. 迭代:当你对Query Set进行迭代方法时
for e in Entry.objects.all():
    print(e.headline)

PS:当你只需要确认Query Set中是否存储数据时(而不需要知道具体数据内容,请使用exist函数(该种方式比迭代访问更快),例如:

if some_queryset.filter(pk=entry.pk).exists():
    print("Entry contained in queryset")
  1. slicing : QuerySet支持slicing操作。但是对一个没有计算的Query Set 进行slicing操作还是返回一个未切片的Query Set。但是如果你在切片访问时,使用了step参数,那么Django会执行数据库操作,返回一个list对象。对一个被评估了的QuerySet进行slicing操作也是返回一个list。
    注意:对一个没有评估计算的queryset 进行slicing 操作还是返回没有评估计算的queryset。如果之后通过slicing 操作对数据进行修改,则是不允许的。
  2. picking/caching操作
  3. 执行repr()操作、len(),count()操作
  4. list()操作:强制执行评估计算,例如:
entry_list = list(Entry.objects.all())
  1. bool测试操作,如 bool,or,and 或是if 语句(如果query set 中包含一条数据,则结果为真)
if Entry.objects.filter(headline="Test"):
   print("There is at least one Entry with the headline Test")

1.1. picking Query Set (对QuerySet 对象进行序列化)

当你对一个Query set对象进行序列化时,会导致queryset 操作落库,且查询出来的数据都加载到内存中。通常来说,序列化是进行cache 操作的前序操作。另外当你对一个Query Set 进行反序列化时,你可以获取到对该QuerySet序列化时数据库的相关状态(例如,在对Query set序列化时,model中含有3条符合条件的数据,之后,model进行了其他的增删改查操作。但是当你反序列化后,得到的Query Set对象还是和之前的3条数据绑定了)。

如果你只想对Queryset 中的必要信息进行序列化(方便之后能重新构建出一个新的Queryset,而不需要绑定的数据),则可以只对Query Set对象的query属性进行处理(You can then recreate the original QuerySet (without any results loaded) 。

例如:

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

2.QuerySet API

特点:

  1. 支持filter chain;
  2. 常用的对象属性包括:ordered,db;
  3. 支持的API主要分为两种:返回一个新的Query Set;返回其他数据类型的;

下面主要对QuerySet API进行简单描述。

2.1 返回新的QuerySet 的API

API参数说明含有
filter(**kwargs)kwargs 为 域查询参数(field lookup)返回包含满足条件对象的QuerySet 对象 。当存储多个查询参数时,参数通过and 相连
exclude(**kwargs)kwargs 为 域查询参数(field lookup)返回包含 不满足条件对象的QuerySet 对象。当存储多个查询参数时,参数通过and 相连,然后在外面用一个not 扩起来,形如: where not ( A and B and C)
annotate(*args, **kwargs)数据库聚合操作(sun,average等),详细信息见:https://docs.djangoproject.com/en/2.0/ref/models/querysets/#id5
order_by(*fields)用于排序的字段通常来说,在model meta中指定了排序的信息。但是可以通过order_by 对每个QuerySet进行排序定制 。例如:Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline') 。其中,字段前面的负号指示递减排序。递增是默认选项。如果要随机排序,使用?号。同时,order_by 支持多表的排序
reverse()对结果进行逆序。两次reverse之后,结果和原始的顺序一致
distinct(*fields)字段名去除重复的行
values(*fields, **expressions)返回一个Query Set,该Queryset evaluate 之后,返回的是一个字典(一般来说,QuerySet evaluate返回的是model 实例对象),该方法用于抽取model 记录中的部分字段,优点就是减少了构建python model 实例的花销.
values_list(*fields, flat=False, named=False)和values类似,但是Query Set中包含的是满足条件的元组列表。但flat=true时,直接返回Query Set,该queryset表示满足条件的元素列表
dates(field, kind, order=‘ASC’)
datetimes(field_name, kind, order=‘ASC’, tzinfo=None)
none()
all()返回一个当前QuerySet中一个 copy。当对该QuerySet进行了evaluate后,结果会在内存中缓存。当在evaluate后,数据库中的数据更新了,则可以再次调用QuerySe.all方法,更新缓存
union(*other_qs, all=False)合并多个Query Set,即SQL中的union操作
dintersection(*other_qs)
difference(*other_qs)多个Query set进行比较,返回只存在当前Query Set中的元素
select_related(*fields)在查询本model的满足条件的数据记录时,也会将相关的(其他model 表)的数据查询出来。并且,会将查询进行合并,减少SQL执行次数。扩展查询主要针对Foreign key 和 OneToOneField
prefetch_related(*lookups)返回一个QuerySet,该QuerySet会一次性的获取相关的对象信息(非一条SQL),但是多条SQL是一次性执行的。和select_related功能类似,但是实现策略不同。select_related是通过join语句实现的,因此,能在一条SQL中查询出所有相关的数据,缺点就是如果join的数据表数据很大,则join效率很低。prefetch_select 是通过每次搜索一条关系,使用Python自己做“join”
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)描述复杂的sql 语句。old API,尽量不要使用。
defer(*fields)
defer(*fields)当model数据项过多时,且你并不需要这个所有的字段,使用defer进行刷选,去掉fields指定的字段。当某些字段没有获取到后,以后需要访问时,会再次触发新的SQL语句
only(*fields)和defer类似,但是fields 指定是需要留下的(返回的是一个Query Set,该Query Set表示满足条件的model实例列表,但是实例中的数据不全,有的字段没有填充获取
using(alias)指定QuerySet对应的数据库
select_for_update(nowait=False, skip_locked=False, of=())返回一个Query Set,该Query Set 会锁定数据库中的相关的行,直到事务完成
raw(raw_query, params=None, translations=None)用于执行Raw SQL语句,详情见:https://docs.djangoproject.com/en/2.0/topics/db/sql/

举例
操作如下;

In [50]: cs=q.choice_set.all()

In [60]: cs_dict=cs.values('choice_text','votes')

#返回的是一个QuerySet ,但是QuerySet中的每条记录都是一个dict 普通对象。如;{'choice_text': 'not null', 'votes': 0}
In [61]: cs_dict  
Out[61]: <QuerySet [{'choice_text': 'not null', 'votes': 0}, {'choice_text': 'the sky', 'votes': 0}, {'choice_text': 'just hacking again', 'votes': 0}, {'choice_text': 'test', 'votes': 0}, {'choice_text': 'test bulk', 'votes': 1}, {'choice_text': 'create method', 'votes': 2}, {'choice_text': 'normal create', 'votes': 1}]>


In [58]: cs_list=cs.values_list('choice_text','votes')

#返回的是一个QuerySet ,但是QuerySet中的每条记录都是普通的元组
In [59]: cs_list
Out[59]: <QuerySet [('not null', 0), ('the sky', 0), ('just hacking again', 0), ('test', 0), ('test bulk', 1), ('create method', 2), ('normal create', 1)]>

#返回的是一个QuerySet,QuerySet中的每个元素都是一个model对象,只是这个对象的某些field没有填充。当获取这些没有填充的字段时,会触发SQL查询。
In [62]: cs_model=cs.only('choice_text')

In [63]: cs_model
Out[63]: <QuerySet [<Choice: Choice:Question:what's new?,not null>, <Choice: Choice:Question:what's new?,the sky>, <Choice: Choice:Question:what's new?,just hacking again>, <Choice: Choice:Question:what's new?,test>, <Choice: Choice:Question:what's new?,test bulk>, <Choice: Choice:Question:what's new?,create method>, <Choice: Choice:Question:what's new?,normal create>]>

模型定义如下:


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date pulbished')

    def was_published_recently(self):
        return self.pub_date >= timezone.now()

    def __str__(self):
        return "Question:%s" % self.question_text


class Choice(models.Model):
    question = models.ForeignKey(Question,on_delete=models.CASCADE, null=True)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return "Choice:%s,%s" % (str(self.question), self.choice_text)

2.1.1 API示例

  • values(*fields, **expressions)
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
  • values_list(*fields, flat=False, named=False)
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>

>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
  • select_related(*fields)
#普通的查询
# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

# select_related
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
  • only 与values的区别:
    见下面示例:
    假设Blabla模型含有4个字段:field1,field2,field3,field4。
    执行如下语句:
Blabla.objects.only('field1', 'field2', 'field3')[0].field4  
#执行结果:通过一个新的SQL查询,获取field4的值。

Blabla.objects.values('field1', 'field2', 'field3')[0].field4
#执行结果:抛出异常。AttributeError: 'dict' object has no attribute 'field4'

2.1.2 关于Q对象

class Q[source]
A Q() object, like an F object, encapsulates a SQL expression in a Python object that can be used in database-related operations.

In general, Q() objects make it possible to define and reuse conditions. This permits the construction of complex database queries using | (OR) and & (AND) operators; in particular, it is not otherwise possible to use OR in QuerySets.

https://docs.djangoproject.com/en/2.0/ref/models/expressions/#django.db.models.F

2.2 返回值不是QuerySet的API

The following QuerySet methods evaluate the QuerySet and return something other than a QuerySet.These methods do not use a cache (see Caching and QuerySets). Rather, they query the database each time they’re called.

(每个Query Set 对象都有对应的cache区域。每个新建的QuerySet的cache 区域都是空的。当Query Set 被首次evaluate时,数据库操作落盘,Django会将结果放到该QuerySet的cache中,以后重用数据,例如迭代。另外,如果对QuerySet不是完整的evaluate,例如进行slice或是index,则结果不会进行缓存)

  • get(**kwargs): 返回满足条件的数据。当多条数据或没有数据时,都会抛错。kwargs为filed 查询参数。

  • create(**kwargs):创建对象并将对象保存到数据库中;

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
  • get_or_create(defaults=None, **kwargs):查询或是创建对象。使用方式:
obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

等同于如下代码

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()
  • update_or_create(defaults=None, **kwargs):
  • bulk_create(objs, batch_size=None): 批量插入
  • count(): 对结果计数
  • in_bulk(id_list=None, field_name=‘pk’):field_name为model的字段名字。id_list 为一个值列表(field_name的值,即id_list 为值列表,field_name指定这些值是那些字段的值。默认情况下,field_name为主键)如果没有指定id_list,则返回Query Set中的所有的记录。该函数返回值是一个字典,字典的key 为id_list中的值,value为field_name 字段等于id_list 中的值的对象。
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
{'beatles_blog': <Blog: Beatles Blog>}
  • iterator()
    • With server-side cursors
    • Without server-side cursors
  • latest(*fields):取最近的/最新的一个对象。
  • earliest(*fields):类似于latest
  • first()
  • last()
  • aggregate()
  • exists()
  • update()
  • delete()
  • as_manager()

2.3 Field 查询参数

https://docs.djangoproject.com/en/2.0/topics/db/queries/#lookups-that-span-relationships

Filed 查询参数格式形如:field__lookuptype=value。支持的lookuptype包括:
exact,iexact,contains,icontains,in,gt,gte,lt
lte,startswith,istartswith,endswith,iendswith,range,date,year,month,day,week,week_day,quarter,time,hour,minute,second,isnull,regex,iregex

注意:在字段查询中,field 必须是model 中定义的field。但是,如果某个字段是外建关联字段,则可以使用_id

也可以通过field lookup 进行多表之间的联合查询。

查询支持正向查询(本model 中包含关联关系字段)和反向查询(本model 中不包含关联关系字段)。

正向查询
格式:‘本model的字段名’__'关联model中的字段名’

(注意:上面是双下划线)
另外,可以支持多级关联。多级关联时,直接在后面叠加。

例如:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

查询关联blog的名字为‘Beatles blog’的entry:

Entry.objects.filter(blog__name='Beatles Blog')

反向查询
格式:’被关联的model的名称的小写‘__'被关联的model的field字段‘

例如:查询至少关联了一条headline 为“Lennon”的entry的所有blog。

Blog.objects.filter(entry__headline__contains='Lennon')

2.4 聚合函数

所有的聚合一般都有如下参数

  • expression:一个表示model 字段的字符串或者是一个Query表达式
  • output_field:可选参数,表示返回值所表示的model 字段;
  • filter: 可选的Q对象,用于缩小聚合的行;
  • **extra:附加参数

支持的聚合函数包括

  • Avg(expression, output_field=FloatField(), filter=None, **extra)
  • Count(expression, distinct=False, filter=None, **extra)
  • Max(expression, output_field=None, filter=None, **extra)
  • Min(expression, output_field=None, filter=None, **extra)
  • StdDev(expression, sample=False, filter=None, **extra)
  • Sum(expression, output_field=None, filter=None, **extra)
  • Variance(expression, sample=False, filter=None, **extra)

3. Query-related tools

3.1 Q() objects

Q对象用于封装一个SQL表达式到一个Python 对象中。通过Q对象,可以构造一个的条件,如多个条件的or 和and。

3.2 Prefetch() objects

Prefetch(lookup, queryset=None, to_attr=None):用于控制prefetch_related()的执行。

3.3 prefetch_related_objects()

prefetch_related_objects(model_instances, *related_lookups)

3.4 FilteredRelation() objects

FilteredRelation(relation_name, *, condition=Q()):用于在annotate 函数中,当执行join语句时,构建on 子句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值