代码之家  ›  专栏  ›  技术社区  ›  Serge Rogatch

如果我从django查询集中删除行,然后再次筛选,会怎么样?

  •  1
  • Serge Rogatch  · 技术社区  · 7 年前

    请考虑以下代码:

    questions = Question.objects.only('id', 'pqa_id', 'retain')
    del_questions = questions.filter(retain=False)
    # Some computations on del_questions
    del_questions.delete()
    add_questions = questions.filter(pqa_id=None)
    

    威尔 add_questions 不包含问题 retain=False ?即 questions 运行时重新评估对象 delete() 关于它的子集 del_questions ?

    1 回复  |  直到 7 年前
        1
  •  2
  •   willeM_ Van Onsem    7 年前

    简短回答 :您在这里使用不同的 QuerySet 因此,您将在这里通过创建一个副本,进行另一个查询。如果你想用同样的 查询集 ,Django将删除缓存,因此它将 再评价 这个 查询集 . 但是,可以让对象在 .delete() 调用,因为缓存在另一个 查询集 已经评估过了 之前 .

    是 questions 运行时重新评估对象 delete() 关于它的子集del_问题

    问题 S是 从未 首先评估。一 查询集 是可Iterable的,如果您对它进行迭代(或获取长度,或其他内容),将导致查询。但是如果你写 Model.objects.all().filter(foo=3) 那么姜戈会的 不 首先“评估”一下 .all() 取走全部 Model 对象进入内存。

    一 查询集 本质上是一个构建查询的工具,通过链接操作和每次构造 新的 查询设置。最终,您可以评估其中一个查询集。

    这里通过应用 .filter(..) 两个电话。因此我们建造了两个 不同的 查询集 如果您对前者进行评估,那么这将不会在后者中产生任何缓存。

    第二个重要注意事项是 删除() 做 不 评估查询集,因此不缓存结果。如果我们检查 .delete() method [GitHub] 我们看到:

    def delete(self):
        """Delete the records in the current QuerySet."""
        assert self.query.can_filter(), \
            "Cannot use 'limit' or 'offset' with delete."
    
        if self._fields is not None:
            raise TypeError("Cannot call delete() after .values() or .values_list()")
    
        del_query = self._chain()
    
        # The delete is actually 2 queries - one to find related objects,
        # and one to delete. Make sure that the discovery of related
        # objects is performed on the same database as the deletion.
        del_query._for_write = True
    
        # Disable non-supported fields.
        del_query.query.select_for_update = False
        del_query.query.select_related = False
        del_query.query.clear_ordering(force_empty=True)
    
        collector = Collector(using=del_query.db)
        collector.collect(del_query)
        deleted, _rows_count = collector.delete()
    
        # Clear the result cache, in case this QuerySet gets reused.
        self._result_cache = None
        return deleted, _rows_count
    

    用 self._chain() 一个创造了一个 复制 关于槲皮素。所以即使这会改变 查询集 ,那么它不会改变这个的状态 查询集 .

    另一个有趣的部分是 self._result_cache = None 在这里 重置 高速缓存。因此,如果已经对查询集进行了计算 之前 你打电话来 删除() (例如,在调用 删除() 然后,它会 去除 那个缓存。所以如果你想重新评估 查询集 ,这将导致另一个查询来获取项。

    然而,在这种情况下,数据仍然可能过时。例如以下内容:

    questions = Question.objects.all()  # create a queryset
    list(questions)                     # materialize the result
    questions2 = questions.all()        # create a copy of this queryset
    questions2.delete()                 # remove the entries
    

    如果我们现在打电话 list(questions) 因此,我们在缓存中获取 问题 和这个 查询集 是 不 无效,因此元素“生存”a 删除() 来自另一个查询集(来自此查询集的副本,尽管这不是必需的,但是 Questions.objects.all().delete() 也会成功的)。

    推荐文章