django基础之ORM模型与数据库
模型
模型准确且唯一的描述了数据。它包含您储存的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。
- 每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
- 模型类的每个属性都相当于一个数据库的字段。
字段
字段类型
-
AutoField() ID 自动递增。
-
BigAutoField() 与 AutoField 很相似, 1 ~ 9223372036854775807
-
SmallAutoField() 与 AutoField 很相似, 1 ~ 32767
-
IntegerField() 整型,范围 -2147483648 ~ 2147483647
-
BigIntegerField() 整型,范围 -9223372036854775808 ~ 9223372036854775807
-
SmallIntegerField() 整型,范围 -32768 ~ 32767
-
PositiveIntegerField() 整型,范围 0 ~ 2147483647
-
PositiveBigIntegerField() 整型,范围 0 ~ 9223372036854775807
-
PositiveSmallIntegerField() 整型,范围 0 ~ 32767
-
BooleanField() 布尔值
-
FloatField() 浮点型
-
DecimalField(max_digits=None, decimal_places=None) 固定精度的十进制数
max_digits,小数总长度
decimal_places,小数位长度 -
CharField(max_length=None) 字符字段,必须提供 max_length 参数
-
TextField() 文本字段
-
EmailField(max_length=254) 电子邮件地址
-
GenericIPAddressField(protocol=’both’, unpack_ipv4=False) IPv4 或 IPv6 地址,字符串格式(如 192.0.2.30 或 2a02:42fe::4 )。protocol,将有效输入限制为指定协议。接受的值是 'both' (默认)、'IPv4' 或 'IPv6'。unpack_ipv4,解压 IPv4 映射地址,只有当 protocol 设置为 'both' 时才会启用。
-
URLField(max_length=200) URL
-
SlugField(max_length=50) 字符串字段,支持 字母、数字、下划线、连接符(减号)
-
UUIDField() 通用唯一标识符
-
FilePathField(path='', match=None, recursive=False, allow_files=True, allow_folders=False, max_length=100) 选择文件系统中某个目录下的文件名
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归子文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹 -
FileField(upload_to=None, max_length=100) 文件上传
upload_to = "" 上传文件的保存路径 'uploads/'或者'uploads/%Y/%m/%d/'
storage = None 存储组件 -
ImageField(upload_to=None, height_field=None, width_field=None, max_length=100,) 字符串字段,路径保存在数据库,文件上传到指定目录
width_field=None, 模型字段的名称,每次保存模型实例时将自动填充图像的宽度。
height_field=None 模型字段的名称,每次保存模型实例时将自动填充图像的高度。 -
DateTimeField(auto_now=False, auto_now_add=False) 日期时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
auto_now,每次保存对象时,自动将该字段设置为现在。对于“最后修改”的时间戳很有用。
auto_now_add,当第一次创建对象时,自动将该字段设置为现在。对创建时间戳很有用。 -
DateField(auto_now=False, auto_now_add=False) 日期格式 YYYY-MM-DD
-
TimeField(auto_now=False, auto_now_add=False) 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField() 用于存储时间段 数据库中按照 bigint 存储,ORM 中获取的值为 datetime.timedelta 字段 -
BinaryField(max_length=None,) 二进制字段
-
JSONField(encoder=None, decoder=None) 存储 JSON 编码数据
encoder,用于序列化标准 JSON 序列化器不支持的数据字段(例如 datetime.datetime 或 UUID )
decoder,用于反序列化从数据库中获取的值
字段选项
-
null
如果是 True, Django 将在数据库中存储空值为 NULL。默认为 False。 -
blank
如果是 True ,该字段允许为空。默认为 False 。 -
choices
from django.db import models class Student(models.Model): FRESHMAN = 'FR' SOPHOMORE = 'SO' YEAR_IN_SCHOOL_CHOICES = [ (FRESHMAN, 'Freshman'), (SOPHOMORE, 'Sophomore'), ] year_in_school = models.CharField(max_length=2,choices=YEAR_IN_SCHOOL_CHOICES,default=FRESHMAN,)
-
枚举类型---TextChoices
from django.utils.translation import gettext*lazy as * class Student(models.Model): class YearInSchool(models.TextChoices): FRESHMAN = 'FR', _('Freshman') SOPHOMORE = 'SO', _('Sophomore') year_in_school = models.CharField(max_length=2,choices=YearInSchool.choices, default=YearInSchool.FRESHMAN,)
-
枚举类型---IntegerChoices
class Card(models.Model): class Suit(models.IntegerChoices): DIAMOND = 1 SPADE = 2 suit = models.IntegerField(choices=Suit.choices)
-
default
该字段的默认值 -
primary_key
如果设置为 True ,将该字段设置为该模型的主键。如果你没有为模型中的任何字段指定 primary_key=True,Django 会自动添加一个字段来保存主键 -
unique
如果设置为 True,这个字段必须在整个表中保持值唯一。 -
verbose_name
字段的人类可读名称
定义关系
-
ForeignKey 一对多的关系
from django.db import models class Car(models.Model): manufacturer = models.ForeignKey( 'Manufacturer', on_delete=models.CASCADE, ) # ... class Manufacturer(models.Model): # ... pass
-
ManyToManyField 多对多的关系
from django.db import models class Person(models.Model): #... class Group(models.Model): #... members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) #...
Meta 选项
模型的元数据即“所有不是字段的东西”,比如排序选项( ordering ),数据库表名( db_table ),或是阅读友好的单复数名( verbose_name 和 verbose_name_plural )。这些都不是必须的,并且在模型当中添加 Meta 类 也完全是可选的。
from django.db import models
class Person(models.Model):
#...
class Meta:
ordering = ["score"]
verbose_name_plural = "students"
模型属性
- objects
模型当中最重要的属性是 Manager。它是 Django 模型和数据库查询操作之间的接口,并且它被用作从数据库当中 获取实例,如果没有指定自定义的 Manager 默认名称是 objects。Manager 只能通过模型类来访问,不能通过模型实例来访问。
创建模型
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)
number_of_comments = models.IntegerField()
number_of_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
查询
一旦创建 数据模型 后,Django 自动给予你一套数据库抽象 API,允许你创建,检索,更新和删除对象。
模型对象
- 对象创建
p = Person(first_name="Bruce", last_name="Springsteen")
p.save()
- 对象更新
p.first_name='aa'
p.save()
- 对象复制
p.pk = None
p._state.adding = True
p.save()
- 对象删除
p.delete()
检索对象
要从数据库检索对象,要通过模型类的 Manager 构建一个 QuerySet。
一个 QuerySet 代表来自数据库中对象的一个集合。它可以有 0 个,1 个或者多个 filters. Filters,可以根据给定参数缩小查询结果量。在 SQL 的层面上, QuerySet 对应 SELECT 语句,而filters对应类似 WHERE 或 LIMIT 的限制子句。
通过使用你的模型的 Manager,你可以获得一个 QuerySet。每个模型至少有一个 Manager,默认情况下称为 objects。可以直接通过模型类来访问它。
链式过滤:filter 和 exclude 的结果依然是个 QuerySet,因此它可以继续被 filter 和 exclude,这就形成了链式过滤。
每一次过滤,你都会获得一个全新的 QuerySet,它和之前的 QuerySet 没有任何关系,可以完全独立的被保存,使用和重用。
QuerySets 是惰性的
创建 QuerySet 的过程不涉及任何数据库活动。你可以一直堆叠过滤条件,但 Django 实际上不会运行查询,直到 QuerySet 被 评估。一般来说, QuerySet 的结果直到你 “要使用” 时才会从数据库中拿出。当你要用时,才通过数据库 计算 出 QuerySet。
什么时候 QuerySet 被执行
QuerySet 本身可以被构造,过滤,切片,或者复制赋值等,是无需访问数据库的。只有在你需要从数据库取出数据或者,向数据库存入数据时才需要访问数据库。
-
迭代:一个 QuerySet 是可迭代的,当你第一次迭代它时,它就会执行其数据库查询。
for e in Entry.objects.all(): print(e.headline)
-
异步迭代。可以使用 async for 来迭代一个 QuerySet:
async for e in Entry.objects.all(): results.append(e)
-
切片:QuerySet 可以使用 Python 的数组切片语法进行切片。切片一个未执行的 QuerySet 通常会返回另一个未执行的 QuerySet,但如果使用切片语法的 step 参数,Django 会执行数据库查询,并返回一个列表。切片一个已经执行过的 QuerySet 也会返回一个列表。
-
Pickling/缓存:当进行序列化或者缓存的时候
-
repr():当你调用 repr() 时,所在 QuerySet 会被执行。这是为了方便 Python 交互式解释器,所以当你交互式使用 API 时,可以立即看到你的结果。
-
len():当你调用 len() 时,会执行 QuerySet。正如你所期望的,这将返回结果列表的长度。
-
list():通过调用 list() 强制执行 QuerySet。
entry_list = list(Entry.objects.all())
-
bool():在布尔语境中测试 QuerySet,如使用 bool()、or、and 或 if 语句,将导致查询被执行。如果至少有一个结果,则 QuerySet 为 True,否则为 False。
if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
检索全部对象
Entry.objects.all()
检索单个对象
如果不存在主键为 1 的 Entry 对象,那么 Django 将抛出 Entry.DoesNotExist 异常。
如果结果超过 1 个,则会抛出 Entry.MultipleObjectsReturned 异常。
Entry.objects.get(pk=1)
通过过滤器检索指定对象
Entry.objects.filter(pub_date__year=2020).exclude(pub_date__gte=datetime.date.today())
限制 QuerySet 条目数¶
利用 Python 的数组切片语法将 QuerySet 切成指定长度。这等价于 SQL 的 LIMIT 和 OFFSET 子句。
Entry.objects.all()[:5] # 返回前5个对象
Entry.objects.all()[5:10] # 返回第六到第十个对象(OFFSET 5 LIMIT 5)
字段查询
基本的查找关键字参数采用形式 field__lookuptype=value (使用双下划线)。
Entry.objects.filter(pub_date__lte='2006-01-01') # WHERE pub_date <= '2006-01-01'
Entry.objects.get(headline__exact="Cat bites dog") # WHERE headline = 'Cat bites dog'
Entry.objects.get(headline="Cat bites dog") # WHERE headline = 'Cat bites dog'
Blog.objects.get(name__iexact="beatles blog") # 不分大小写的匹配
Entry.objects.get(headline__contains='Lennon') # WHERE headline LIKE '%Lennon%';
Entry.objects.filter(id__in=[1, 3, 4]) # WHERE id IN (1, 3, 4);
Entry.objects.filter(headline__in='abc') # WHERE headline IN ('a', 'b', 'c');
Entry.objects.filter(id__gt=4) # WHERE id > 4;
Entry.objects.filter(headline__startswith='Lennon') # WHERE headline LIKE 'Lennon%';
Entry.objects.filter(headline__endswith='Lennon') # WHERE headline LIKE '%Lennon';
Entry.objects.filter(pub_date__range=(datetime.date(2005, 1, 1), datetime.date(2005, 3, 31))) # WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Entry.objects.filter(pub_date__year__gte=2005) # WHERE pub_date >= '2005-01-01';
Entry.objects.filter(pub_date__month=12) # 对于日期和日期时间字段,精确的月份匹配
Entry.objects.filter(pub_date__day=3) # 对于日期和日期时间字段,精确匹配日期
Entry.objects.filter(pub_date__week=52) # 对于日期和日期时间字段,返回星期号
Entry.objects.filter(pub_date__week_day=2) # 对于日期和日期时间字段,“星期几”匹配
Entry.objects.filter(pub_date__isnull=True) # WHERE pub_date IS NULL;
跨关系查询
Entry.objects.filter(blog__name="Beatles Blog") # 检索所有具有 name 为 'Beatles Blog' 的 Blog 的 Entry 对象
Blog.objects.filter(entry__headline__contains="Lennon") # 检索所有至少有一个 headline 包含 'Lennon' 的 Entry 的 Blog 对象
关联对象
当你在模型中定义了关联关系(如 ForeignKey, OneToOneField, 或 ManyToManyField),该模型的实例将会自动获取一套 API,能快捷地访问关联对象。
一个 Entry 对象 e 通过 blog 属性获取其关联的 Blog 对象: e.blog
e = Entry.objects.get(id=2)
e.blog
一个 Blog 对象 b 能通过 entry_set 属性 b.entry_set.all() 访问包含所有关联 Entry 对象的列表。
b = Blog.objects.get(id=1)
b.entry_set.all()
b.entry_set.filter(headline__contains='Lennon')
b.entry_set.count()
关联对象的增删改
b.entry_set.add(e)
e = b.entry_set.create(...)
b.entry_set.remove(e)
b.entry_set.clear()
e.authors.set(..)
关联关系预加载
# 沿着外键关系查询关联的对象的数据
e = Entry.objects.get(id=5) # 访问数据库。
b = e.blog # 再次访问数据库以得到关联的 Blog 对象。
# 这会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要再次数据库查询。
e = Entry.objects.select_related('blog').get(id=5) # 访问数据库。
b = e.blog # 不会访问数据库,因为 e.blog 已经在前面的查询中获得了。
# filter()和 select_related()的顺序不重要。 下面的查询集是等同的:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
字段间比较
from django.db.models import F,Min
from datetime import timedelta
Entry.objects.filter(number_of_comments__gt=F("number_of_pingbacks")+5)
Entry.objects.filter(rating__lt=F("number_of_comments") + F("number_of_pingbacks"))
Entry.objects.filter(mod_date__gt=F("pub_date") + timedelta(days=3))
Entry.objects.filter(pub_date__year=F("mod_date__year"))
Entry.objects.aggregate(first_published_year=Min("pub_date__year"))
主键 (pk) 查询
Blog.objects.get(pk=14)
Blog.objects.filter(pk__in=[1, 4, 7])
Blog.objects.filter(pk__gt=14)
Entry.objects.filter(blog__pk=3)
缓存和 QuerySet
每个 QuerySet 都带有缓存,尽量减少数据库访问。
新创建的 QuerySet 缓存是空的。一旦要计算 QuerySet 的值,就会执行数据查询,随后,Django 就会将查询结果保存在 QuerySet 的缓存中,并返回这些显式请求的缓存。后续针对 QuerySet 的计算会复用缓存结果。
queryset = Entry.objects.all()
print([p.headline for p in queryset]) # 提交查询
print([p.pub_date for p in queryset]) # 重用查询缓存
查询结果集并不总是缓存结果。当仅计算查询结果集的 部分 时,会校验缓存,若没有填充缓存,则后续查询返回的项目不会被缓存。特别地说,这意味着使用数组切片或索引的查询结果集不会填充缓存。
queryset = Entry.objects.all()
print(queryset[5]) # 查询数据库
print(queryset[5]) # 再次查询数据库
但是,如果已经遍历过整个 QuerySet,那么就相当于缓存过,后续的操作则会使用缓存,例如:
queryset = Entry.objects.all()
[entry for entry in queryset] # 查询数据库
print(queryset[5]) # 使用缓存
print(queryset[5]) # 使用缓存
下面的这些操作都将遍历 QuerySet 并建立缓存:
[entry for entry in queryset]
bool(queryset)
entry in queryset
list(queryset)
复杂查询
在类似 filter() 中,查询使用的关键字参数是通过 "AND" 连接起来的。如果你要执行更复杂的查询(例如,由 OR 语句连接的查询),你可以使用 Q 对象。
from django.db.models import Q
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
#相当于 SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
原生 SQL 查询
for p in Person.objects.raw("SELECT id, first_name,last_name FROM myapp_person"):
print(p.first_name,p.last_name)
Person.objects.raw("SELECT * FROM myapp_person WHERE last_name = %s", [lname])
汇总查询
在 QuerySet 上生成汇总
# 内置聚合函数:Avg、Count、Max、Min、StdDev(标准差)、Sum、Variance(方差)
from django.db.models import Count, Avg, Max, FloatField
q = Blog.objects.aggregate(Count('entry')) # {'entry__count': 16}
q = Blog.objects.aggregate(number_of_entries=Count('entry')) #{'number_of_entries': 16}
Book.objects.all().aggregate(Avg('price')) # {'price__avg': 34.35}
Book.objects.all().aggregate(Max('price')) # {'price__max': Decimal('81.20')}
Book.objects.aggregate(price_diff=Max('price', output_field=FloatField()) - Avg('price')) # {'price_diff': 46.85}
Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) # {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
为 QuerySet 中的每一个对象生成汇总
from django.db.models import Count,Q
q=Blog.objects.annotate(Count('entry'))
print(q[0].entry__count) # 5
above_5 = Count('book', filter=Q(book__rating__gt=5))
below_5 = Count('book', filter=Q(book__rating__lte=5))
pubs = Publisher.objects.annotate(below_5=below_5).annotate(above_5=above_5)
print(pubs[0].above_5) # 23
print(pubs[0].below_5) # 12
q = Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True))
print(q[0].authors__count) # 2
print(q[0].store__count) # 3
Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))
事务
Django 默认的事务行为是自动提交。除非事务正在执行,每个查询将会马上自动提交到数据库。
Django 自动使用事务或还原点,以确保需多次查询的 ORM 操作的一致性,特别是 delete() 和 update() 操作。
atomic 允许创建代码块来保证数据库的原子性。如果代码块成功创建,这个变动会提交到数据库。如果有异常,变动会回滚。
atomic 块可以嵌套。
# select_for_update() 返回一个锁住行直到事务结束的查询集,如果数据库支持,它将生成一个 SELECT ... FOR UPDATE 语句。
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
try:
with transaction.atomic():
for entry in entries:
pass
except DatabaseError:
pass
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。
在后台,Django 的事务管理代码:
- 当进入最外面的 atomic 块时打开事务;
- 当进入 atomic 块内部时创建一个保存点;
- 从块内部退出时释放或回滚保存点;
- 离开块的最外层时提交或回滚事务。
用法示例
# 获取数量
Entry.objects.filter(pub_date__year=2020).count()
# 排序
Entry.objects.filter(pub_date__year=2005).order_by('pub_date', 'headline')
Entry.objects.order_by('blog__name', 'headline')
# 反向排序 QuerySet 中返回的元素
queryset.reverse()[:5] #获取 QuerySet 中最后五个元素
# QuerySet 迭代器
Entry.objects.filter(pub_date__year=2020).iterator()
# QuerySet 通常会在内部缓存其结果,以便在重复计算时不会导致额外的查询。而 iterator()将直接读取结果,不在 QuerySet 级别执行任何缓存。
# 对于返回大量只需要访问一次的对象的 QuerySet,这可以带来更好的性能,显著减少内存使用。
# 查询 QuerySet 是否包含结果
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
pass
# 获得 QuerySet 中最近、最早先的对象
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
Entry.objects.filter(pub_date__isnull=False).earliest('pub_date')
# 获得结果集中第一个、最后一个对象,当没有找到时返回 None。
p = Article.objects.order_by('title', 'pub_date').first()
p = Article.objects.order_by('title', 'pub_date').last()
# 去除查询结果中重复的行
Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
# 获得包含数据字典的 queryset,而不是模型实例
Blog.objects.filter(name__startswith='Beatles') # <QuerySet [<Blog: Beatles Blog>]>列表中包含的是 Blog 对象
Blog.objects.filter(name__startswith='Beatles').values() #<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]> 列表中包含的是数据字典
Blog.objects.values('id', 'name') # <QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
from django.db.models.functions import Lower
Blog.objects.values(lower_name=Lower('name')) # <QuerySet [{'lower_name': 'beatles blog'}]>
Blog.objects.values('author').annotate(entries=Count('entry')) #<QuerySet [{'author': 1, 'entries': 33}]>
# 获得包含数据元组的 queryset,而不是模型实例
Entry.objects.values_list('id', 'headline') # <QuerySet [(1, 'First entry'), ...]>
from django.db.models.functions import Lower
Entry.objects.values_list('id', Lower('headline')) # <QuerySet [(1, 'first entry'), ...]>
Entry.objects.values_list('id', flat=True).order_by('id') # <QuerySet [1, 2, 3, ...]>
# 集合中并集
qs1.union(qs2, qs3)
# 集合中交集
qs1.intersection(qs2, qs3)
# 集合中差集
qs1.difference(qs2, qs3)
# 延迟加载
Entry.objects.defer("headline", "body")
# 查询动作仍将返回模型实例,并且被排除的字段依然可以调用。
# 每个被排除的字段将在你访问该字段时从数据库中进行一次额外的检索(每次只检索一个字段,而不是一次检索所有的延迟字段)。
# only 的意思是只有only指定的字段立刻加载,剩下的全部延迟
Entry.objects.only("headline", "body").defer("body") # 最后只有"headline"被立即检索
Entry.objects.defer("body").only("headline", "body") # 最后只有 headline 和 body 被立即检索
# 当对具有延迟字段的实例调用 save()时,仅保存加载的字段。
# 使用多个数据库
Entry.objects.all() # 使用'default' 数据库
Entry.objects.using('backup') # 使用 'backup' 数据库
p.save(using='backup')
# 删除对象
Entry.objects.filter(pub_date__year=2020).delete()
# 更新对象
Entry.objects.filter(pub_date__year=2020).update(headline='Django 教程')
# update 只能更新模型主表中的字段,不能更新关联模型中的字段。
# 创建对象
Person.objects.create(first_name="Bruce", last_name="Springsteen")
# 查询对象不存在则创建一个新对象
p, created = Person.objects.get_or_create(first_name='John',last_name='Lennon')
# 如果查找到的对象超过一个以上,将引发 MultipleObjectsReturned。
# 如果查找不到对象,get_or_create()将会实例化并保存一个新的对象,返回一个由新的对象以及 True 组成的元组。
# 更新对象,如果没找到对象,则创建一个新的对象
obj, created = Person.objects.update_or_create(first_name='John', last_name='Lennon')
# 批量创建对象
Entry.objects.bulk_create([
Entry(headline='This is a test'),
Entry(headline='This is only a test'),
])
# 批量更新对象
objs[0].headline = 'This is entry 1'
objs[1].headline = 'This is entry 2'
Entry.objects.bulk_update(objs, ['headline'])
# 根据主键批量查询
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>}
# 打印 SQL 语句
print(Blog.objects.all().query)
# QuerySet 的执行计划
print(Blog.objects.filter(title='My Blog').explain())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix