Django 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()
>>> Student.objects.filter(name='Regina David').exists()
False
我的数据库有一个名为 Regina Johnson 的学生,因此当调用名称为“Regina Johnson”时,exists() 方法返回 True,在其他情况下则返回 False。
7、count()
count() 方法计算 QuerySet 中的条目数。它可用于对数据库表中的所有对象进行计数。
>>> Student.objects.count()
或者用于统计查询返回的对象数量:
>>> Student.objects.filter(name='Regina Johnson').count()
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