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

如何将两个逻辑与模板有差异的Django TemplateView合并为单个视图以符合DRY原则

实现方案

两个视图的核心差异仅为模板路径、不同状态下的过滤条件,我们可以通过提取公共逻辑的方式遵循DRY原则,以下是两种常用实现方案:

方案1:抽象公共基类(推荐,扩展性更强)

将通用逻辑封装到父类,子类仅声明差异化配置:

# 公共基类,所有通用逻辑仅实现一次
class BaseProgressView(LoginRequiredMixin, TemplateView):
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['progress'] = self.kwargs.get('progress', 'in_progress')
        # 调用子类实现的方法获取对应场景的过滤条件
        filters = self.get_filters(context['progress'])
        context['objects'] = Model.objects.filter(**filters)
        return context

    def get_filters(self, progress):
        if progress == 'in_progress':
            base_filters = {'progress': 'in_progress'}
            extra_filters = self.get_in_progress_extra_filters()
        else:
            base_filters = {'progress__iexact': progress}
            extra_filters = self.get_other_progress_extra_filters()
        return {**base_filters, **extra_filters}

    # 子类按需重写以下两个方法返回额外过滤条件
    def get_in_progress_extra_filters(self):
        return {}
    def get_other_progress_extra_filters(self):
        return {}

# 原View1仅需写差异化逻辑
class View1(BaseProgressView):
    template_name = 'temp1.html'
    def get_other_progress_extra_filters(self):
        return {'accepted': self.request.user}

# 原View2仅需写差异化逻辑
class View2(BaseProgressView):
    template_name = 'temp2.html'
    def get_in_progress_extra_filters(self):
        return {'created': self.request.user}
    def get_other_progress_extra_filters(self):
        return {'created_by': self.request.user}

方案2:单视图+URL注入配置(更简洁,适合无后续扩展需求的场景)

如果不需要保留多个视图类,可以直接通过as_view()传递差异化参数,仅用单个视图实现:
首先修改urls.py,在注册路由时注入配置:

# urls.py
urlpatterns = [
    # 原View1的路由,注入对应配置
    path('view1/<str:progress>/', MergedProgressView.as_view(
        template_name='temp1.html',
        filter_config={
            'in_progress_user_field': None,
            'other_user_field': 'accepted'
        }
    ), name='view1'),
    # 原View2的路由,注入对应配置
    path('view2/<str:progress>/', MergedProgressView.as_view(
        template_name='temp2.html',
        filter_config={
            'in_progress_user_field': 'created',
            'other_user_field': 'created_by'
        }
    ), name='view2'),
]

然后实现合并后的视图:

# views.py
class MergedProgressView(LoginRequiredMixin, TemplateView):
    # 由as_view方法注入配置,不需要修改核心逻辑
    filter_config = None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['progress'] = self.kwargs.get('progress', 'in_progress')
        filters = {}
        
        if context['progress'] == 'in_progress':
            filters['progress'] = 'in_progress'
            user_field = self.filter_config['in_progress_user_field']
        else:
            filters['progress__iexact'] = context['progress']
            user_field = self.filter_config['other_user_field']
        
        # 配置了用户关联字段就添加过滤条件
        if user_field:
            filters[user_field] = self.request.user
        
        context['objects'] = Model.objects.filter(**filters)
        return context

内容的提问来源于stack exchange,提问作者乂TØXIC乂

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:45:05