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
相关产品推荐
相关产品推荐

