django官方文档——构造查询(数据库查询 查询数据库)

构造查询

一旦创建完 数据模型 , Django 会自动给你一套数据库抽象的 API ,以用于创建、检索、更新和删除对象。本文为你介绍如何使用这套 API 。所有不同种类的搜索参数详见数据模型参考

本文所有内容(包括本手册)全部围绕以下模型展开,这些模型组成了一个博客应用:

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

    def __unicode__(self):
        return self.name

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

    def __unicode__(self):
        return self.name

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

    def __unicode__(self):
        return self.headline

创建对象

为在 Python 对象中表现数据库表中的数据, Django 使用一个非常直观的系统:一个模型类表现一个数据库表,并且一个该类的实例表现表中一个指定的记录。

要创建一个对象,只要通过使用关键参数实例化模型类,然后调用 save() 把对象保存到数据库就行了。

你可以从任何 Python 路径导入模型类。(我们之所以要指出这点是因为旧版本 Django 导入模型没有这么方便。)

假设模型存在于文件 mysite/blog/models.py 中,示例如下:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

上例在后执行了一个 INSERT SQL 语句。 Django 不会执行数据库操作,除非显式调用save()

save() 方法没有返回值。

 

See also

save() 有许多高级参数这里没有提到,详见其文档。

要一步完成创建并且同时保存对象参见 `create()` 方法。

修改对象

要修改数据库中已存在的对象,请使用 save()

假设一个 Blog 的实例 b5 ,这个实例已经保存进了数据库,以下例子会修改其 name 并且会修改数据库中相应的数据:

>> b5.name = 'New name'
>> b5.save()

上例在后执行了一个 UPDATE SQL 语句。 Django 不会执行数据库操作,除非显式调用save()

保存 外键 多对多字段 字段

更新一个 外键 字段的方法与一般的字段一样,只要设置正确的字段类型就可以了。本例更新了一个Entry 实例的blog 属性:

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

更新一个 多对多字段 稍有不同,要对更新的字段使用add() 方法来为关系增加一个记录。本例在entry 对象中加入了Author 实例 joe

>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)

如果你尝试使用不正确的对象类型,那么 Django 会有意见的。

获取对象

要从你的数据库中获得对象,你必须通过你的模型类的 管理器(Manager 来构建一个 查询集(QuerySet

一个 查询集 表现为数据库中对象的集合。它可以没有、有一个或有多个过滤器( filters ) 。过滤器是限制集合范围的准则。在 SQL 语句中,一个查询集 等于一个 SELECT 语句,一个过滤器相当于一个WHERELIMIT 子句。

你可以通过使用模型的 管理器 得到一个查询集 。每个模型至少有一个管理器 ,``管理器`` 一般也称作 对象(objects 管理器 可以通过模型类直接操作,就如下例:

>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
    ...
AttributeError: "Manager isn't accessible via Blog instances."

Note

管理器 只能由模型类操作,而不能由模型实例操作。这样用以区别表级别 操作和记录级别 操作。

管理器 是一个模型的 查询集 的主要来源,它类似于模型的数据库表中所有对象的“根” 查询集 。例如, Blog.objects 是包含Blog 数据库表中所有对象的初始查询集

获得所有对象

从数据库表中获得对象的最简单的方法就是获得所有对象。在一个 管理器 上使用all() 方法可以获得所有对象:

>>> all_entries = Entry.objects.all()

all() 方法返回一个包含所有数据库表中对象的查询集

(既然 Entry.objects 是一个查询集 ,为什么不使用Entry.objects ?这是因为 Entry.objects ,是一个根查询集 ,是一个不能表现出来的东西。all() 方法返回的是 可以 表现出来的查询集

用过滤器获得特定对象

查询集 通过 管理器 提供数据库表的所有对象的描述。但是通常你只需要全部对象的一个子集。

要得到这个子集,就必须改进原始的 查询集 ,增加一些过滤条件,通常使用以下两种方法:

filter(**kwargs)
返回一个新的包含符合查询条件对象的 查询集
exclude(**kwargs)
返回一个新的 包含符合查询条件对象的 查询集

查询参数(即上例中的 **kwargs )应当遵循下文字段查找 一节中描述的规则。

例如,要获得一个包含所有 2006 年的博客条目的 查询集 ,可以这样使用filter()

Entry.objects.filter(pub_date__year=2006)

这里我们不需要添加一个 all() --Entry.objects.all().filter(...) 。当然添加了也可以,但是一般只有在需要从根查询集 中获取所有对象时才使用 all()

连环过滤器

过滤器 可以连环使用,例如:

>>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.now()
... ).filter(
...     pub_date__gte=datetime(2005, 1, 1)
... )

上例中在原始的包含所有记录的 查询集 上加上了一个过滤器,再加上了一个排除,最后再加上了一个过滤器。最后得到的是一个 headline 以 "What" 开头的,发布时间介于 2005 年 1 月 1 日和当前时间之间的查询集

过滤后的查询集是独立唯一的

每一次提取的 查询集 都是独立的、唯一的,是与前一次的查询集 无关的,是可以储存、使用和再使用的。

例如:

>> q1 = Entry.objects.filter(headline__startswith="What")
>> q2 = q1.exclude(pub_date__gte=datetime.now())
>> q3 = q1.filter(pub_date__gte=datetime.now())

以上三个 查询集 是独立的。第一个是一个基础查询集 ,包含所有 headline 以 "What" 开头的记录。第二个查询集 是第一个的子集,去除了发布时间晚于当前时间的记录。第三个查询集 是第一个的子集,只含有发布时间晚于当前时间的记录。原始的查询集q1 )不会因为后面的添加限制条件而改变。

查询集是惰性的

查询集 是惰性的,即创建一个 查询集 不会触动数据库。你可以不停地创建过滤器,但 Django 不会真正运行查询,除非 查询集执行 了。来看以下的例子:

>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.now())
>>> q = q.exclude(body_text__icontains="food")
>>> print q

上例中表面看执行了三个数据库查询,但实质只有最后一行代码( printq )执行了一次数据库查询。通常,只到你“要求”返回结果时,查询集 才会从数据库中抓取数据, 查询集执行 了。更多关于执行的精确时间的内容参见 When QuerySets are evaluated

使用 get 获取一个单一的对象

.filter() 总是给你一个 查询集 ,即使只有一个对象符合查询条件也会返回只包含一个对象的 查询集

如果你确定你的查询只有一个符合条件的对象,那么你可以使用在 管理器 上使用 get() 方法直接获取这个对象:

>>> one_entry = Entry.objects.get(pk=1)

你可以象 filter() 一样在 get() 上使用任何查询表达式。参见下文的 字段查找

注意, filter() get() 有一点不同。如果没有找到符合条件的对象,那么 .get() 会抛出一个 DoesNotExist 异常。这个异常是被执行查询的模型类的一个属性。在上面的例子中,如果没有这键为 1 的Entry ,那么 Django 会抛出Entry.DoesNotExist 异常。

同样,如果多个对象符合条件, Django 也会不爽,会抛出 MultipleObjectsReturned 异常。这个异常也是模型类的一个属性。

其他查询集方法

大多数时间,当需要在数据库中查找对象时会使用 all()get()filter()exclude() 。但是,这还是远远不够的。要得到所有查询集 方法的完整列表,请参阅查询集 API 手册

限制查询集

可以使用 Python 序列切片语法的子集来限制你的 查询集 。这将相当于 SQL 的LIMITOFFSET 子句。

例如,下例返回前五个对象( LIMIT 5 ):

>>> Entry.objects.all()[:5]

下例返回第六到第十个对象( OFFSET 5 LIMIT 5 ):

>>> Entry.objects.all()[5:10]

负数索引(如: Entry.objects.all()[-1] )是不支持的。

通常,对一个 查询集 切片只会返回一个新的查询集 ,不会执行这个查询 。但是有一个例外:假如使用 Python 语法中的“步长”参数,那么就会执行查询。下例用于返回前十个对象中的第偶数个对象,查询会立即执行:

>>> Entry.objects.all()[:10:2]

要得到一个 单一 的对象而不是一个列表(如: SELECTfooFROM barLIMIT1 ),可以使用一个简单的索引,而不使用切片。例如下例返回数据中按字母排序后的第一条记录:

>>> Entry.objects.order_by('headline')[0]

上例基本上等同于:

>>> Entry.objects.order_by('headline')[0:1].get()

注意:当查询结果为空时,第一个例子会产生 IndexError 异常,而第二个例子则产生DoesNotExist 异常。详见get()

字段查找

字段查找的定义相当于书写 SQL 的 WHERE 子句。定义方法是把条件作为查询集filter()exclude()get() 方法的关键字参数。

基本的查找关键字参数形如: 字段__查找类型=值 (注意:是双下划线)。例如:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')

翻译为 SQL 语句大致如下:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

这是如何做到的

Python 中的函数可以接受独特的名称-值参数,并且这些参数可以动态赋值。更详细的信息参见官方 Python 教程的 关键字参数

如果你传递了一个非法的关键字参数,会产生 TypeError

查找类型约有二十多个,详见 字段查找手册 。以下是一些常用的查找例子:

exact

“精确”匹配。例如:

>>> Entry.objects.get(headline__exact="Man bites dog")

相当于以下 SQL 语句:

SELECT ... WHERE headline = 'Man bites dog';

如果没有定义查找类型,即没有使用双下划线,那么默认类型为 exact

例如以下两句是等价的:

>>> Blog.objects.get(id__exact=14)  # 显式声明
>>> Blog.objects.get(id=14)         # __exact 隐含在内了

这样做是为了方便,因为 exact 查找是最常用的。

iexact

一个大小写不敏感的匹配。所以下例:

>>> Blog.objects.get(name__iexact="beatles blog")

将会匹配标题为 “Beatles Blog ”、“ beatles blog ”或甚至是 “ BeAtlES blOG ”的 Blog

contains

大小写敏感的包含测试。例如:

Entry.objects.get(headline__contains='Lennon')

基本相当于以下 SQL:

SELECT ... WHERE headline LIKE '%Lennon%';

注意这个查找会匹配 'Today Lennon honored' ,但是不会匹配 'today lennon honored'.

当然也有大小不敏感的: icontains

startswith, endswith
大小写敏感的匹配开头和结尾。相应大小写不敏感的是 istartswithiendswith

再次重申,以下介绍只是一些皮毛。完整的手册详见 字段查找手册

跨关系查找

Django 提供一个有力且直观的方法来“追踪”查找中的关系,即会在后台自动处理 SQL 中的 JOIN 。要跨越一个关系,只要使用跨模块的关联字段即可,并用两个下划线分隔,直到得到你想要的字段为止。

以下例子可以获得名称为 'Beatles Blog'Blog 的所有条目。

>>> Entry.objects.filter(blog__name__exact='Beatles Blog')

这种跨越的深度是无限的。

跨越也可以是反向的。要指向一个“反向”的关系,请使用模型的小写名称。

下例可以获得至少一个条目的头条包含 'Lennon' 的所有Blog 对象:

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

如果你跨越了多重关系并且其中的一个模型没有符合条件的值,那么 Django 会把模型视作空对象(即所有值为 NULL ),而不是非法对象。因此在前述情况下不会引发错误。例如:

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

假设有一个相关联的 作者``( Author )模型,如果没有 ``作者 与任何一个条目关联,那么就会视作也没有名称 与之关联。这样处理比因为作者 缺失而引发错误要好。通常这也是你想要的处理方式。唯一会产生混淆的是当你使用isnull 的时候。就象下例:

Blog.objects.filter(entry__authors__name__isnull=True)

会返回包括 名字 为空的 作者作者 为空的条目 两种情况的Blog 对象。如果你不希望包括后一种情况的对象,你可以这样写:

Blog.objects.filter(entry__authors__isnull=False,
        entry__authors__name__isnull=True)
跨越多值关系

当你基于一个 多对多字段 对象或一个反向外键 过滤时,有两种不同的过滤方法值得注意。对于博客条目 关系( 博客 对于条目 是一对多关系),我们可能会想要查找一个博客,这个必须博客包括一个符合以下条件的条目:在条目的头条中包含"Lennon" 字样,并且发布日期为 2008 年。或者我们也可以会想要查找一个博客,这个博客必须符合以下条件:包含一个头条中有"Lennon" 字样的条目,并且包含一个发布日期为 2008 年的条目。因为一个博客 对应于多个条目 ,所以上述两种查询都是可能的,在特定情况下都是有用的。

同样,一个 多对多字段 也会引发类似情况。例如,假设一个条目 字段有一个名为标记 ( tags )的多对多字段。我们可以会想要查找既有"music" 标记又有"bands" 标记的条目。或者我们也可能会想要查找标记为 "music" ,状态为"public" 的条目。

对于上述两种方法, Django 中的 filter()exclude() 使用相同的方式来处理。在一个filter() 中的所有条件必须同时符合。在连续的filter() 中的条件对于多值关系情况下,这些条件是并列的(都对应于主模型的对象),而不是嵌套的(对应于前一个filter() 产生的对象)。

都迷糊了吧,来一个例子清醒一下。要查找一个博客,这个必须博客包括一个符合以下条件的条目:在条目的头条中包含 "Lennon" 字样,并且发布日期为 2008 年。即条目必须同时符合两个条件。我们这样写:

Blog.objects.filter(entry__headline__contains='Lennon',
        entry__pub_date__year=2008)

要查找一个博客,这个博客必须符合以下条件:包含一个头条中有 "Lennon" 字样的条目,并且包含一个发布日期为 2008 年的条目。但对于同一个条目不一定要同时符合两个条件。我们这样写:

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

在第二个例子中,第一个过滤器限定了特定条件的博客,第二个过滤器 进一步 限定了同时符合第二个条件的博客。匹配第二个过滤器的条目不一定匹配第一个过滤器。两个过滤器的条件都是针对某个博客而言的,而不是针对某个条目而言的。

以上方式也同样用于 exclude()

过滤器可以引用模型中的字段

迄今为止的例子中,我们构建的过滤器都是比较字段和常量的,但是如果我们要比较同一模型中的两个不同字段怎么办?

Django 提供了 F() 对象来做这样在比较。F() 对象查询中可以作为模型字段的引用,这样就可以在查询中比较同一模型实例中的不同字段了。

例如,我们要查找评论比广播( pingback )多的条目,那么先构建一个引用评论数量的 F() 对象,然后在查询中使用这个F() 对象:

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

Django 支持 F() 对象的加减乘除和取模运算。要查找广播数为评论数两倍的条目可以使用如下查询:

>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

要查找广播数和评论数之和大于级别的条目可以使用如下查询:

>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

你也可以在 F() 对象中使用双下划线来跨越关系。带有双下划线的F() 对象会自动使用必须联合。例如查找所有作者为博客名称的条目,可以使用如下查询:

>>> Entry.objects.filter(authors__name=F('blog__name'))
New in Django Development version.

对于日期和日期时间字段你可以加上或减去一个 datetime.timedelta 对象。下例可以返回所有在发布三天后修改过条目:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

pk 缩写

为了方便, Django 提供了一个 pk 缩写来代表“主键”。

在博客模型例子中,主键是 id 字段,所以以下三条语句是等价的:

>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact

pk 的用法不只局限于 __exact 查询,任何查询短语都可以:

# Get blogs entries with id 1, 4 and 7
>>> Blog.objects.filter(pk__in=[1,4,7])

# Get all blog entries with id > 14
>>> Blog.objects.filter(pk__gt=14)

pk 查询还可以用于联合。例如以下语句是等价的:

>>> Entry.objects.filter(blog__id__exact=3) # Explicit form
>>> Entry.objects.filter(blog__id=3)        # __exact is implied
>>> Entry.objects.filter(blog__pk=3)        # __pk implies __id__exact

LIKE 语句中的百分号和下划线的转义

在相当于 LIKE SQL 语句的字段查找(iexactcontainsicontainsstartswithistartswithendswithiendswith )中的百分号和下划线会被自动转义。(在LIKE 语句中,百分号是一个代表多个字符的通配符,下划线是一个代表单个字符的通配符。)

这种方式使用语句看起来比较直观。例如,要查询所有包含百分号的条目,可以象对待其它字符一样对待百分号:

>>> Entry.objects.filter(headline__contains='%')

Django 会帮你处理引号,上例的相应的 SQL 如下:

SELECT ... WHERE headline LIKE '%\%%';

对下划线的处理方法与之相同。这样可以直观地处理百分号和下划线。

缓存和查询集

每个 查询集 都包含一个缓存,用于最小化数据库使用。为了写出最有效率的代码,理解缓存的工作方式是非常重要的。

当一个 查询集 新建时,其缓存是空的。当查询集 第一次被执行时,数据库就会使用一次, Django 会把查询结果保存在查询集 的缓存中并返回结果。以后的查询就会重复使用缓存。

你要小心缓存的行为,如果不正确使用 查询集 ,那么有可能上当。例如下列语句会创建两个查询集 并执行它们,然后把它们抛在一边:

>>> print [e.headline for e in Entry.objects.all()]
>>> print [e.pub_date for e in Entry.objects.all()]

这意味着两个同样的查询被执行了两次,浪费啊。同时,两条语句的条目还可能不一致,因为在两次查询之间可能会有条目增减。

要避免以上问题,只要保存 查询集 并且重复使用就可以了:

>>> queryset = Entry.objects.all()
>>> print [p.headline for p in queryset] # 执行查询集。
>>> print [p.pub_date for p in queryset] # 重复使用缓存。

使用 Q 对象进行复杂查询

filter() 等语句中的关键字查询参数都是“逻辑与”的关系。如果要进行更复杂的查询(如条件之间为“逻辑或”的关系),那么可以使用Q 对象。

Q 对象( django.db.models.Q )是用于封装一堆关键字查询参数的对象。这些关键字查询参数在上文“字段查找”中已描述过。

例如,下面的 Q 对象封装了一个单一的LIKE 查询:

from django.db.models import Q
Q(question__startswith='What')

Q 对象可以用 &| 操作符联结,联结之后会产生一个新的Q 对象。

下例产生了一个新的 Q 对象,这个对象表示两个"question__startswith" 查询的OR 的联结:

Q(question__startswith='Who') | Q(question__startswith='What')

上例相当于下面的 SQL WHERE 子句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

可以用 & | 操作符及圆括号来组合任意复杂的 Q 对象,还可以使用~ 符号来表示“逻辑非”。例如:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

每个有关键字参数的查询函数(如 filter() 、``exclude()`` 和get() )可以接受一个或多个Q 对象作为位置参数(不是命名参数)。如果你提供了多个Q 对象,则参数之间是“逻辑与”的关系。例如:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

... 相当于以下 SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

在查询函数中可以混合使用 Q 对象和关键字参数。查询函数中的所有参数(包括Q 对象和关键字参数)都是“逻辑与”的关系。如果混合使用这两种参数,Q 对象应当放在关键字参数之前。例如:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

... 是合法的查询,相当于上一个例子,但:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

... 是不合法的。

See also

Django 单元测试中的 逻辑或查询例子 中有一些 Q 对象的使用例子。

比较对象

使用标准的 Python 比较操作符双等于号 == 来比较两个模型实例。这种比较在后台实质是比较两个模型的主键的值。

在博客条目的例子中,以下两个语句是等价的:

>>> some_entry == other_entry
>>> some_entry.id == other_entry.id

上例中的等价是基于主键为 id 的情况,如果主键是name ,那么以下的两个语句是等价的:

>>> some_obj == other_obj
>>> some_obj.name == other_obj.name

删除对象

删除对象方法是 delete() 。这个方法立即删除对象且没有返回值。例如:

e.delete()

也可以批量删除对象。每个 查询集 都有一个删除所有成员的delete() 方法。

例如以下例子删除所有 pub_date 为 2005 年的条目:

Entry.objects.filter(pub_date__year=2005).delete()

请记住,批量删除对象方法是直接执行 SQL 语句的,不会执行模型中的针对每个单独实例的 delete() 方法。如果你要执行自定义的delete() 方法,那么必须“手动” 删除。(例如遍历一个查询集 ,对每个单独的对象执行 delete() 方法。)

当 Django 删除一个对象,缺省情况下它会模拟 SQL 的约束 ONDELETECASCADE ,换句话说,任何有外键指向被删除对象的对象都会同时被删除。例如:

b = Blog.objects.get(pk=1)
# 以下语句会删除博客和它所有的条目。
b.delete()
New in Django Development version: 这种联动行为可以通过在 ForeignKey 上面加上 on_delete 参数来定制。

注意, delete() 方法是唯一没有暴露给“管理器”的查询集 方法。这是一个保护机制,以防止你意外地使用了Entry.objects.delete() ,删除了所有 条目。如果你确实要删除所有对象,那么必须显式地使用如下语句:

Entry.objects.all().delete()

一次更新多个对象

有时需要把一个 查询集 中所有对象的某个字段的值设置为同一个特定值,你可以使用update() 方法。例如:

# 更新所有 pub_date 为 2007 年的条目的头条。
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

这个方法只能用于更新非关系型字段和 外键 字段。要更新非关系字段,应当提供一个常量。要更新外键 字段,应当把指向的新模型实例赋于新值。例如:

>>> b = Blog.objects.get(pk=1)

# 改变属于这个博客的所有条目
>>> Entry.objects.all().update(blog=b)

update() 方法是立即执行的并且返回受到查询影响的行数。唯一的限制是只能更新一个数据库的表,即模型的主表。你可以使用基于关系字段的过滤器,但只能更新模型主表中的列。例如:

>>> b = Blog.objects.get(pk=1)

# Update all the headlines belonging to this Blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')

要明确的是 update() 方法直接转换为 SQL 语句,它只是对 SQL 直接更新的封装。它不会运行任何模型中save() 方法,也不会发出pre_savepost_save 信号(这些信号是调用save() 方法而产生的)。如果要保存查询集 中的每一项,并确保每个实例都调用了 save() 方法,那么不需要任何特殊的函数来处理,只要遍历每个实例并调用 save()

for item in my_queryset:
    item.save()

也可以通过使用 F() 对象 来基于模型中的其他字段的值来更新。这种方法对于基于字段当前值来增加计数特别有用。例如,要给博客中的每个条目增加广播的计数,可以这样写:

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

然而,与在过滤器和排除子句中的 F() 对象不同,在使用F() 对象更新时不能引入联合。你只能引用被更新模型本身的字段。否则会引发一个FieldError

# 这会引发一个 FieldError
>>> Entry.objects.update(headline=F('blog__name'))

回退到原始 SQL

如果你觉得 Django 的数据库映射用起来太复杂了,那么你可以手工撰写 SQL 语句。 Django 可以为原始 SQL 语句提供许多选择,参见 执行原始 SQL 查询

最后,要注意重要的一点: Django 的数据库层只是数据库的一个接口。你可通过其他工具、编程语言或数据库框架来操作数据库, Django 没有强制性的要求。

 
 
 
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值