Django:如何从QuerySet的对象列表中排除正在删除的页面

jgovgodb  于 2023-05-08  发布在  Go
关注(0)|答案(2)|浏览(145)

我正在开发一个Django网站,它有一个部分(一个应用程序)“关于”,页面有3级层次结构。此部分有相应的3级弹出菜单。为了尽量减少查询数据库,我希望这个菜单是静态的(HTML文件),重写的情况下,如果菜单的变化(即。即在页面创建、更新或删除时)。
此操作通过函数get_success_url完成:

def get_success_url(self):
    object_list = Page.objects.filter(parent=None).order_by("order").prefetch_related("subpages__subpages")
    text = render_to_string('menu_pages_template.html', {'object_list': object_list})
    f = open( 'roo/templates/includes/menu_about.html', 'w+')
    f.write(text)
    f.close()
    ...

在页面创建或更新时,一切都运行良好。但是,在删除页面时,它的菜单项不会被删除,因为页面对象仍然存在于查询集中。
我尝试从查询集中排除当前对象:

def get_success_url(self):
    object_list = Page.objects.exclude(slug=self.kwargs['page'])
    object_list = object_list.filter(parent=None).order_by("order").prefetch_related("subpages__subpages")

但是这种方法只适用于第一级页面。“child”和“grandchild”页面仍然保留在查询集中。也许它们也可以通过一些过滤被排除,但我怀疑应该有更简单和“pythonic”的方法来从查询集中排除已删除的页面。
所以请帮帮我!

zbq4xfa0

zbq4xfa01#

如果在执行get_success_url()中的查询之前确实删除了一个对象,我对如何返回它感到困惑。然而,我没有任何经验的模型,有外键自己。(我想这就是“父”与相关名称“子页面”的含义)?我想它实际上并没有被删除(还没有?)我会非常仔细地阅读Django对数据库事务提交的描述,可能还有你正在使用的数据库的文档。这是一个“特色”吗?或者甚至是不是你写的代码中的错误?一些不该被藏起来的东西?
你可以尝试的一个(简单的!)大锤是将has_been_deleted BooleanField添加到Page模型中,并执行以下操作:

# page is to be deleted
page.has_been_deleted = True
page.save()
print( f"About to delete Page instance pk={page.pk}") # for debug
page.delete()

这应该是完全多余的,但您可以在添加显式Prefetch对象以排除已删除的对象之后立即调查简单查询是否有效。在Django文档之后,类似于

object_list = Page.objects.filter(
       parent=None, 
       # has_been_deleted=False # necessary?
   ).order_by("order"
   ).prefetch_related( Prefetch( 
       "subpages__subpages",
        queryset = Page.objects.exclude(has_been_deleted=True)
        )
   )

如果你仍然有同样的问题,has_been_deleted是否在检索到的对象中设置,该对象是否具有相同的pk?
另外,如果我使用开发数据库而不是测试数据库进行测试(测试数据库开始时完全没有对象),我会非常仔细地检查是否有任何页面对象被早期代码遗留下来,而这些代码并不完全工作。
祝你好运!

67up9zun

67up9zun2#

到目前为止,我已经找到了以下方法,实际上我并不喜欢,但它很有效。首先,我为第一级(parent_list),第二级(child_list)和第三级(grandchild_list)的页面生成不同的列表,从所有列表中排除我的当前示例,即正在删除的页面。接下来,我将“孙”预取为“子”,最后将“子”预取为“父母”。代码在下面。我觉得它很丑,很复杂,所以我还是在寻找更好的方法。

class PageDeleteView(LoginRequiredMixin, DeleteView):
    model = Page
    success_url = reverse_lazy('about:detail')

    def get_object(self):
        page = Page.objects.get(slug=self.kwargs['page'])
        return page
    
    def get_success_url(self):    
        total_list = Page.objects.exclude(slug=self.kwargs['page'])
        descendant_list = total_list.filter(parent__isnull=False).order_by("order")
        grandchild_list = descendant_list.filter(parent__parent__isnull=False).order_by("order")
        child_list = descendant_list.filter(parent__parent__isnull=True).order_by("order")
        parent_list = total_list.filter(parent__isnull=True)        
        child_list = child_list.prefetch_related(
            Prefetch('subpages', queryset=grandchild_list)
            )
        object_list = parent_list.prefetch_related(
            Prefetch('subpages', queryset=child_list)
            )
        text = render_to_string('menu_pages_template.html', {'object_list': object_list})
        f = open( 'roo/templates/includes/menu_about.html', 'w+')
        f.write(text)
        f.close()
        return reverse('about:detail')

相关问题