Django的。 get_or_create优化与延迟

时间:2014-12-22 09:26:05

标签: django django-orm

这些查询之间是否有任何区别:

category, _ = models.Category.objects.get_or_create(
    title=some_title,
    brick=node_id,
    parent=parent,
)

category, _ = models.Category.objects.defer('data').get_or_create(
    title=some_title,
    brick=node_id,
    parent=parent,
)


类别模型如下所示:

class Category(Model):
    title = models.CharField(max_length=255, blank=True, null=True)
    brick = models.IntegerField(
        primary_key=True,
    )
    parent = models.ForeignKey('self', blank=True, null=True)
    data = models.TextField(blank=True, null=True) # very large text 

1 个答案:

答案 0 :(得分:1)

这主要是按照您的预期运作。

从db中检索对象时,defer不会选择该字段,但请注意,即使该字段被延迟,也可以在get查询的WHERE子句中查看该对象必须被创造(正如人们所期望的那样)。如果该对象不可用,则会发出第二个INSERT,插入get_or_create方法中指定的所有字段,甚至是最终在defer调用中指定的字段。

唯一令人讨厌的是创建一个尚不存在的对象而你没有在get_or_create中指定一个你defer的字段,就像你的情况一样,然后尝试在创建的对象上访问此特定字段,生成一个额外的(第三个)查询以从db中获取该字段(即使我们知道它不存在)。

# Model has fields a and b, b being optional
a, c = Model.objects.defer('b').get_or_create(a=1)  # Two queries, one to get, the second to insert (ignore that sqlite does 3 queries here)
# c is True
# a is now a deferred object
a.a # doesn't hit the db again
a.b # hits the db trying to retrieve the b field

如果您插入该对象,而不指定延迟或可选字段,则不会在第三次尝试在创建的对象上获取该可选字段时命中数据库。

# Model has fields a and b, b being optional
a, c = Model.objects.get_or_create(a=1)  # Two queries as before
# c is True
# a is NOT a deferred object
a.a # doesn't hit the db
a.b # no db hit, b being empty

另一种情况是您使用延迟字段加载对象并尝试保存此对象的情况,documentation表示:

  

为具有延迟字段的实例调用save()时,仅保存已加载的字段。有关详细信息,请参阅save()。