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

Django DRF+django-tenants单元测试创建餐厅时出现404错误求助

解决django-tenants + DRF单元测试中创建餐厅返回404的问题

可能的原因及修复步骤

1. 修复子域名拼接错误

你的get_test_tenant_domain方法中,子域名和主域名的拼接缺少点号,导致生成的域名格式错误,租户无法匹配:

@staticmethod
def get_test_tenant_domain():
    if RestaurantCreateTest.tenant:
        # 原代码缺少点号,会生成类似kangaroottest.com的错误域名
        # 修改为带点号的正确格式
        domain = f"{RestaurantCreateTest.tenant.subdomain_prefix}.{settings.ORGANIZATION_DOMAIN}"
        return domain
    else:
        return "tenant.test.com"

错误的域名会让django-tenants无法识别当前请求所属租户,进而无法加载租户对应的路由配置,最终返回404。

2. 确认路由的租户归属

确保Restaurant的URL配置放在租户专用的URLconf中(比如tenant_urls.py),而非公共的urls.py。django-tenants会根据租户域名自动切换URLconf,如果餐厅API路由在公共配置里,租户请求时会找不到对应接口。

3. 检查reverse的命名空间

如果你的租户URLconf或app设置了命名空间,调用reverse时需要加上命名空间前缀:

# 假设restaurants app的urls.py里设置了app_name="restaurants"
url = reverse("restaurants:Restaurant-list")

遗漏命名空间会导致reverse生成的URL不正确,引发404。

4. 简化测试客户端的使用

TenantTestCase已经自动配置了关联当前租户的测试客户端,不需要手动创建TenantClient,直接使用self.client即可:

def setUp(self):
    super().setUp()
    # 移除手动创建TenantClient的代码
    # self.c = TenantClient(self.tenant)

def test_create_valid_restaurant(self):
    # ...
    # 直接用self.client发起请求
    response = self.client.post(url, data, format="json")

5. 验证租户域名是否正确创建

部分版本的django-tenants需要手动为租户创建Domain对象,在setup_tenant中补充:

@classmethod
def setup_tenant(cls, tenant):
    tenant.name = "kangaroo"
    tenant.subdomain_prefix = "kangaroo"
    cls.tenant = tenant
    # 手动创建主域名关联
    Domain.objects.create(
        tenant=tenant,
        domain=cls.get_test_tenant_domain(),
        is_primary=True
    )
    return tenant

6. 调试404具体原因

在测试方法中添加调试代码,查看生成的URL和响应详情,快速定位问题:

def test_create_valid_restaurant(self):
    url = reverse("Restaurant-list")
    print(f"生成的URL: {url}")
    data = {
        # ... 测试数据 ...
    }
    response = self.client.post(url, data, format="json")
    print(f"响应内容: {response.content}")
    # ... 断言代码 ...

额外检查点

  • 确认Restaurant模型已正确关联租户:要么继承TenantMixin,要么包含tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)字段。
  • 确认视图类自动绑定租户:在perform_create中为新餐厅关联当前租户:
class RestaurantCreateView(generics.CreateAPIView):
    serializer_class = RestaurantSerializer
    queryset = Restaurant.objects.all()

    def perform_create(self, serializer):
        serializer.save(tenant=self.request.tenant)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:25:04