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

Django如何测试应用所有URL需登录认证 适配带pk参数路由

Django全URL未认证重定向测试实现

核心问题解决方案

  • 完整URL列表获取:不要直接导入单文件的urlpatterns变量遍历,这种方式会漏掉include()引入的子路由、嵌套路由。直接使用Django内置的URL解析器get_resolver递归遍历全量已注册路由,可自动识别路由所属的应用、命名空间,拿到完整可访问路径。
  • 带pk参数的URL自动传值:完全支持自动填充测试参数,遍历路由时识别路径内的所有占位参数,统一传入pk=1即可适配你预先通过fixture生成的测试资源。

可直接复用的测试代码

from django.test import TestCase
from django.urls import reverse, get_resolver, URLPattern, URLResolver
from my_app import apps  # 替换为你自己的待测试应用

# 配置不需要认证校验的公开URL名称,比如登录页、公开首页等
EXEMPT_URL_NAMES = {"login_app:login"}
# 默认测试参数值,适配你预先生成的pk=1的fixture数据
DEFAULT_TEST_KWARGS = {"pk": 1, "id": 1}


def get_all_app_urls(app_config, resolver=None, parent_namespace=None):
    """递归获取指定应用下所有可访问的完整URL路径"""
    if resolver is None:
        resolver = get_resolver()
    url_list = []

    for url_pattern in resolver.url_patterns:
        # 处理嵌套的路由分发(include引入的子路由)
        if isinstance(url_pattern, URLResolver):
            current_namespace = f"{parent_namespace}:{url_pattern.namespace}" if parent_namespace and url_pattern.namespace else url_pattern.namespace or parent_namespace
            url_list.extend(
                get_all_app_urls(app_config, url_pattern, current_namespace)
            )
            continue

        # 只处理目标应用下的路由
        if not hasattr(url_pattern.callback, "__module__"):
            continue
        if app_config.name not in url_pattern.callback.__module__:
            continue

        # 拼接完整的路由命名
        pattern_name = f"{parent_namespace}:{url_pattern.name}" if parent_namespace and url_pattern.name else url_pattern.name
        if not pattern_name or pattern_name in EXEMPT_URL_NAMES:
            continue

        # 识别路由需要的参数,自动填充默认测试值
        try:
            required_kwargs = set(url_pattern.pattern.converters.keys())
            reverse_kwargs = {k: v for k, v in DEFAULT_TEST_KWARGS.items() if k in required_kwargs}
            # 其余未识别的参数统一传1,适配其他类似主键的路径参数
            for kwarg in required_kwargs - set(reverse_kwargs.keys()):
                reverse_kwargs[kwarg] = 1
            full_url = reverse(pattern_name, kwargs=reverse_kwargs)
            url_list.append(full_url)
        except Exception:
            # 遇到特殊参数无法自动生成URL的,可手动加入EXEMPT列表跳过
            continue

    return url_list


class AuthRedirectTest(TestCase):
    # 加载你预先准备好的pk=1的fixture
    fixtures = ["your_test_fixture.json"]

    @classmethod
    def setUpTestData(cls):
        cls.test_urls = get_all_app_urls(apps.MyAppConfig)  # 替换为你自己的AppConfig类

    def _test_unauth_redirect(self, url):
        response = self.client.get(url)
        # 校验未登录访问自动302跳转到登录页,且携带next参数
        self.assertRedirects(
            response,
            expected_url=f"{reverse('login_app:login')}?next={url}",
            target_status_code=200
        )

    def test_all_urls_redirect_to_login_when_unauth(self):
        for url in self.test_urls:
            with self.subTest(url=url):
                self._test_unauth_redirect(url)

使用注意事项

  • 把代码里的应用配置、fixture路径、豁免URL列表替换成你项目对应的实际值即可
  • 如果有特殊路径参数不是主键类型、传1会报错的,把对应URL名称加入EXEMPT_URL_NAMES单独处理即可
  • 这套逻辑会自动遍历所有嵌套路由,不需要手动维护URL列表,新增路由时测试会自动覆盖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:36:21