You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django类视图中调用函数的return render无法中断视图执行

问题描述

我使用基于类的ListView(CB ListView)展示对象,希望在ListView执行过程中,基于另一个模型的PK设置会话变量:

views.py

class ProduitListView(LoginRequiredMixin, ListView):

    model = Produit
    context_object_name = "produits"
    paginate_by = 10
    template_name = 'products/produits.html'
    ordering = ['-mageid', ]

    def get_context_data(self, *args, **kwargs):
        context = super(ProduitListView, self).get_context_data(
            *args, **kwargs)

        # used for incoming products (sourcing cf URLS)
        supplier_pk = self.kwargs.get('pk', None)
        if supplier_pk:
            set_incoming_supplier(self.request, supplier_pk)

        context['avail_warehouses'] = Warehouse.objects.all()
        context['js_warehouses'] = serialize(
            'json', Warehouse.objects.all(), fields=('code', 'id', ))
        context['title'] = 'Produits'
        return context

set_incoming_supplier(在另一个APP中)

@login_required
def set_incoming_supplier(request, pk):
    supplier = Supplier.objects.filter(pk=pk).first()
    supp = SupplierSerializer(instance=supplier).data
    rs = request.session
    if 'income' in rs:
        if 'cur_supplier' in rs['income']:
            prev_supplier = rs['income']['cur_supplier']
            if supp != prev_supplier:
                return render(request, 'sourcing/alert_supplier_change.html',
                              {'prev_supplier': prev_supplier, 'cur_supplier': rs['income']['cur_supplier']})
    rs['income'] = {'cur_supplier': supp}

我原本认为上述代码中的return render(request, 'sourcing/alert_supplier_change...可以中断ListView的执行,渲染警告页面,但实际并未生效,ListView仍继续执行并最终渲染ProduitListView页面。请问这是为什么?


原因分析

你调用set_incoming_supplier时,只是执行了这个函数,但完全没有处理它返回的HttpResponse对象。

在Django类视图中,只有从视图核心方法(比如get()、post())返回的HttpResponse才会被用作请求的最终响应。你现在是在get_context_data里调用这个函数,就算函数返回了警告页面的响应,这个返回值也被直接丢弃了——get_context_data的职责是准备模板上下文,它会继续执行后续代码,最终返回上下文数据,让ListView正常渲染默认页面。

另外,get_context_data本来就不该处理请求跳转或响应渲染这类逻辑,这违背了类视图的职责划分原则。


解决方法

要实现中断ListView并渲染警告页面的效果,你需要把供应商检查逻辑移到视图的get()方法中——get()是类视图处理GET请求的入口,它返回的HttpResponse会直接作为请求响应:

修改ProduitListView类

class ProduitListView(LoginRequiredMixin, ListView):
    # 原有属性保持不变
    model = Produit
    context_object_name = "produits"
    paginate_by = 10
    template_name = 'products/produits.html'
    ordering = ['-mageid', ]

    def get(self, request, *args, **kwargs):
        supplier_pk = self.kwargs.get('pk', None)
        if supplier_pk:
            # 调用函数并接收返回值
            response = set_incoming_supplier(request, supplier_pk)
            # 如果返回了HttpResponse(即需要显示警告),直接返回这个响应
            if response:
                return response
        # 无警告需求时,执行ListView原有的get逻辑
        return super().get(request, *args, **kwargs)

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        # 仅保留上下文准备逻辑
        context['avail_warehouses'] = Warehouse.objects.all()
        context['js_warehouses'] = serialize(
            'json', Warehouse.objects.all(), fields=('code', 'id', ))
        context['title'] = 'Produits'
        return context

调整set_incoming_supplier函数

确保在不需要警告时返回None,让视图继续执行原有逻辑:

@login_required
def set_incoming_supplier(request, pk):
    supplier = Supplier.objects.filter(pk=pk).first()
    if not supplier:
        return None
    supp = SupplierSerializer(instance=supplier).data
    rs = request.session
    if 'income' in rs and 'cur_supplier' in rs['income']:
        prev_supplier = rs['income']['cur_supplier']
        if supp != prev_supplier:
            return render(request, 'sourcing/alert_supplier_change.html',
                          {'prev_supplier': prev_supplier, 'cur_supplier': supp})
    rs['income'] = {'cur_supplier': supp}
    # 无警告需求时返回None
    return None

这样当检测到供应商变更时,set_incoming_supplier返回警告页面的响应,get()方法直接返回这个响应,中断ListView的后续执行;如果没有变更,函数返回None,视图继续渲染产品列表页面。


内容的提问来源于stack exchange,提问作者Abpostman1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:46:06