Django URL匹配异常:重写第三方视图后命名空间错误排查
解决Django视图重写后URL命名空间错误问题
问题根源分析
你遇到的核心问题是:重写的视图所在URL未纳入pipeline子命名空间,导致self.request.resolver_match.namespace仅返回主应用的cash;而第三方应用的URL通过include((pipeline_urls,'pipeline'))引入,其命名空间是完整的cash:pipeline。这种上下文不一致,导致get_task_url生成了错误的URL。
下面提供三种针对性的解决方案:
解决方案1:将重写URL纳入pipeline子命名空间
把重写的URL和第三方URL合并到同一个include块中,确保它们共享pipeline子命名空间,让视图的命名空间上下文和第三方视图保持一致。
修改主应用的urls.py:
from django.urls import path, include from .views import OverrideTaskView from .flows import Pipeline # 获取第三方应用生成的URL pipeline_urls = FlowViewSet(Pipeline).urls # 合并重写URL和第三方URL(重写URL放在前面,优先匹配) custom_pipeline_urls = [ path('<process_pk>/documents/<task_pk>/assign/', OverrideTaskView.as_view(), {'flow_class': Pipeline, 'flow_task': Pipeline.documents}, name="{}__assign".format(Pipeline.documents.name)), ] + pipeline_urls urlpatterns = [ # 将合并后的URL纳入pipeline子命名空间 path('pipeline/', include((custom_pipeline_urls, 'pipeline'))), ]
然后修改views.py中的get_success_url方法,直接使用当前视图的完整命名空间:
def get_success_url(self): """Continue on task or redirect back to task list.""" url = self.activation.flow_task.get_task_url( self.activation.task, url_type='guess', user=self.request.user, namespace=self.request.resolver_match.namespace # 现在自动为cash:pipeline ) back = self.request.GET.get('back', None) if back and not is_safe_url(url=back, allowed_hosts={self.request.get_host()}): back = '/' if '_continue' in self.request.POST and back: url = "{}?back={}".format(url, urlquote(back)) elif back: url = back return url
解决方案2:手动指定完整命名空间
如果不想调整URL结构,可以直接在视图中拼接出正确的完整命名空间,避免依赖resolver_match的上下文:
def get_success_url(self): """Continue on task or redirect back to task list.""" # 手动拼接主应用命名空间和子命名空间 full_namespace = f"{self.request.resolver_match.namespace}:pipeline" url = self.activation.flow_task.get_task_url( self.activation.task, url_type='guess', user=self.request.user, namespace=full_namespace ) back = self.request.GET.get('back', None) if back and not is_safe_url(url=back, allowed_hosts={self.request.get_host()}): back = '/' if '_continue' in self.request.POST and back: url = "{}?back={}".format(url, urlquote(back)) elif back: url = back return url
解决方案3:利用ViewFlow Flow类的命名空间配置
ViewFlow的Flow类支持配置namespace属性,你可以通过Flow实例动态获取子命名空间,让代码更灵活:
首先在你的Pipeline Flow类中配置命名空间:
from viewflow import Flow class Pipeline(Flow): namespace = 'pipeline' # ... 其他Flow配置项
然后修改视图的get_success_url方法:
def get_success_url(self): """Continue on task or redirect back to task list.""" # 从Flow实例中动态获取子命名空间 full_namespace = f"{self.request.resolver_match.namespace}:{self.activation.flow.namespace}" url = self.activation.flow_task.get_task_url( self.activation.task, url_type='guess', user=self.request.user, namespace=full_namespace ) back = self.request.GET.get('back', None) if back and not is_safe_url(url=back, allowed_hosts={self.request.get_host()}): back = '/' if '_continue' in self.request.POST and back: url = "{}?back={}".format(url, urlquote(back)) elif back: url = back return url
内容的提问来源于stack exchange,提问作者neowenshun
相关产品推荐
相关产品推荐

