ORM常用操作

我们都知道 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([1, 4])
>>> 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=?)'

posted @ 2023-03-05 05:26  Python喵  阅读(63)  评论(0编辑  收藏  举报