Django ORM 中常用的方操作

马哥Linux运维

共 8400字,需浏览 17分钟

 ·

2021-09-22 02:40

我们都知道 Django 提供了开箱即用的强大的 ORM,用ORMk可以让我们不懂SQL也可以很方便的去完成对数据库的修改操作,例如查询,删除等。在日常工作中,我们大多数人只会处理来自 ORM 的 filter()、get()、all()、update() 和 delete() 方法。

但除此之外,Django ORM 还提供了许多其他功能强大的方法,今天我们就来介绍下这些方法的实际使用:

  • exclude()

  • values()

  • values_list()

  • select_related()

  • order_by()

  • exists()

  • count()

  • first() and last()

  • in_bulk()

  • explain()

我将使用以下学生表为上述方法提供示例。这个 Student 类来自 models.py 文件:

class Student(models.Model):
    name = models.CharField(max_length=100)
    grade = models.IntegerField()
    section = models.CharField(max_length=10)
    school = models.ForeignKey(School, on_delete=models.CASCADE)
    blood_group = models.CharField(max_length=10)
    mobile = models.CharField(max_length=20)
    address = models.TextField()
    def __str__(self):
        return self.name

学生表与学校表有外键关系。

class School(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(null=True, blank=True)
    address = models.TextField()
    def __str__(self):
        return self.name

让我们正式开始。

1、exclude()

第一种方法是 exclude() 方法。这个方法基本上会返回一个查询集,不包括我们给出的值。我的学生桌上有 4 个学生。首先,让我使用 all() 方法获取它们。

>>> queryset = Student.objects.all()
>>> queryset
<QuerySet [<Student: Regina Johnson>, <Student: Eva Smith>, <Student: Jessie Smith>, <Student: John David>]>

我不希望“Eva Smith”出现在查询集中。所以我可以做这样的事情。我可以在 Student 模型上用她的名字调用 exclude() 方法。

>>> queryset = Student.objects.exclude(name='Eva Smith')
>>> queryset
<QuerySet [<Student: Regina Johnson>, <Student: Jessie Smith>, <Student: John David>]>

从查询的结果可以看到,已从查询集中排除

2、values()

下一个方法是 values() 方法。此方法返回 Python 字典,而不是 QuerySet 对象。

>>> Student.objects.values()<QuerySet [{'id'1'name''Regina Johnson''grade'10'section''A''school_id'1'blood_group''A+''mobile''9791684645''address''93 Jessica Ln, Depew, NY, 14043'}, {'id'3'name''Eva Smith''grade'12'section''A''school_id'1'blood_group''A1+''mobile''8907896543''address''2012 Walnut Ave #J, Ceres, CA, 95307'}, {'id'4'name''Jessie Smith''grade'12'section''A''school_id'1'blood_group''A1+''mobile''8907896543''address''503 Courtney Dr, Brusly, LA, 70719'}, {'id'5'name''John David''grade'12'section''A''school_id'1'blood_group''A1+''mobile''2675431231''address''34 Leaman Pl, Lynbrook, NY, 11563'}]>

我们还可以通过提供字段名称作为 values() 方法的参数来仅检索我们需要的字段。假设我只需要学生的“id”和“name”。我可以做这样的事情。

>>> Student.objects.values('id''name')<QuerySet [{'id'1'name''Regina Johnson'}, {'id'3'name''Eva Smith'}, {'id'4'name''Jessie Smith'}, {'id'5'name''John David'}]>

3、values_list()

values_list() 方法类似于 values() 方法,但它返回元组而不是返回字典。

>>> Student.objects.values_list('id''name')<QuerySet [(1'Regina Johnson'), (3'Eva Smith'), (4'Jessie Smith'), (5'John David')]>

如果我们只需要一个单一的值,比如一个列表而不是一个元组,我们可以将一个额外的参数 flat=True 传递给 values_list 方法。如果我只想将名称作为列表,可以做这样的事情。

>>> Student.objects.values_list('name', flat=True)<QuerySet ['Regina Johnson''Eva Smith''Jessie Smith''John David']>

注意:这仅适用于单个字段。如果提供多个字段,则会出现错误。

>>> Student.objects.values_list('id''name', flat=True)
TypeError: 'flat' is not valid when values_list is called with more than one field.

4、select_related()

这是我非常喜欢的方法之一。正如我所说,我的学生表与学校表有外键关系。所以为了从学生那里检索学校,我可以这样查询。

>>> student = Student.objects.get(pk=1)
>>> student.school
<School: Montfort>

首先,使用学生 ID 查询学生表以获取特定学生。然后再次为了获得学校,我们执行额外的数据库查找。

注意:每个外键关系都需要额外的数据库查找。

对于我们的简单示例,这不是问题,但是在具有许多外键关系的大型数据库中,数据库的负载可能会令人望而却步。

我们可以使用 select_related() 通过在第一次命中数据库时检索所有相关数据来提高数据库性能。

>>> student = Student.objects.select_related('school').get(pk=1)
>>> student.school # school has already been retrieved. Database is not hit again.
<School: Montfort>

在这种情况下,学校数据是在进行第一次查询时从预取数据中检索出来的,而不是再次查询数据库。

5、order_by()

order_by() 方法更改了 QuerySet 的默认顺序。默认情况下,排序基于主键(id)字段。如果我希望我的 QuerySet 根据名称排序,我可以将名称字段提供给 order_by() 方法。如果我希望我的 QuerySet 根据名称升序排序,我可以做这样的事情.

>>> Student.objects.order_by('name')<QuerySet [<Student: Eva Smith>, <Student: Jessie Smith>, <Student: John David>, <Student: Regina Johnson>]>
如果我想按降序排列名称,我可以像这样查询数据库。

>>> Student.objects.order_by('-name')<QuerySet [<Student: Regina Johnson>, <Student: John David>, <Student: Jessie Smith>, <Student: Eva Smith>]>

字段名称的符号将起作用。

6、exists()

如果返回的 QuerySet 包含一个或多个对象,exists() 方法返回 True,如果 QuerySet 为空,则返回 False。

>>> Student.objects.filter(name='Regina Johnson').exists()
True
>>> Student.objects.filter(name='Regina David').exists()
False

我的数据库有一个名为 Regina Johnson 的学生,因此当调用名称为“Regina Johnson”时,exists() 方法返回 True,在其他情况下则返回 False。

7、count()

count() 方法计算 QuerySet 中的条目数。它可用于对数据库表中的所有对象进行计数。

>>> Student.objects.count()
4

或者用于统计查询返回的对象数量:

>>> Student.objects.filter(name='Regina Johnson').count()
1

count() 在功能上等同于使用aggregate() 函数,但它具有更清晰的语法,并且在大型数据集上可能更快。

8、first()和last()

first() 方法返回 QuerySet 中的第一个元素。

>>> Student.objects.all()
<QuerySet [<Student: Regina Johnson>, <Student: Eva Smith>, <Student: Jessie Smith>, <Student: John David>]>>>> Student.objects.all().first()
<Student: Regina Johnson>

last() 方法将从 QuerySet 返回最后一个元素。

>>> Student.objects.all()
<QuerySet [<Student: Regina Johnson>, <Student: Eva Smith>, <Student: Jessie Smith>, <Student: John David>]>>>> Student.objects.all().last()
<Student: John David>

尽管 QuerySet 类似于列表,可以使用 queryset[0] 之类的索引检索第一个元素,但不能像 queryset[-1] 那样检索最后一个元素。这将引发错误。在这种情况下,last() 方法会派上用场。

>>> Student.objects.all()[0]
<Student: Regina Johnson>
>>> Student.objects.all()[-1]    "Negative indexing is not supported."
AssertionError: Negative indexing is not supported.

9、in_bulk()

in_bulk() 接受一个 id 值列表并返回一个字典,将每个 id 映射到具有该 id 的对象实例。如果不将列表传递给 in_bulk() 方法,则将返回所有对象。

假设我只想检索 id 为 1 和 4 的学生,我可以这样做。

>>> 
students = Student.objects.in_bulk([14])
>>> students[1].name
'Regina Johnson'
>>> students[4].name
'Jessie Smith'

然后我可以使用 id 作为索引访问该对象。

10、explain()

此方法返回 QuerySet 执行计划的字符串。用于分析查询性能

>>> Student.objects.filter(pk=1).explain()
'2 0 0 SEARCH TABLE student_student USING INTEGER PRIMARY KEY (rowid=?)'

写在最后,希望这篇文章对大家有帮助。

文章转载:Python运维技术
(版权归原作者所有,侵删)

点击下方“阅读原文”查看更多

浏览 68
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报