Django-tenants公共域获取租户Appointment数据时模板渲染异常排查
问题原因
你遇到的报错核心在于Django QuerySet的延迟执行特性:
在get_context_data里的print(context['appointments'])会触发数据库查询(因为要输出内容),此时还处于schema_context(self.schema_name)上下文内,能正确从租户schema取数据;但模板渲染阶段,上下文已经切回公共schema,这时候遍历QuerySet会再次执行数据库查询,而公共schema不存在appointment_app_appointment表,因此报错。
修复方案
方案1:将QuerySet转为列表(推荐)
把QuerySet转换成Python列表,提前在租户schema上下文内执行查询,避免模板渲染时触发跨schema的数据库操作:
修改get_queryset方法:
def get_queryset(self): tenant_id = self.kwargs.get('pk') try: tenant = Organization.objects.get(id=tenant_id) self.schema_name = tenant.schema_name with schema_context(self.schema_name): # 转为列表,提前执行查询 queryset = list(Appointment.objects.all()) return queryset except Organization.DoesNotExist: raise Http404("Tenant not found") except Exception as e: raise Http404(f"Error accessing tenant data: {e}")
修改get_context_data方法:
def get_context_data(self, **kwargs): with schema_context(self.schema_name): context = super().get_context_data(**kwargs) tenant_id = self.kwargs.get('pk') context['tenant_id'] = tenant_id # 转为列表,避免模板渲染时再次查询 context['appointments'] = list(Appointment.objects.all()) print(context['appointments']) return context
方案2:让模板渲染全程处于租户schema上下文
重写render_to_response方法,确保模板渲染的整个过程都使用指定租户的schema:
def render_to_response(self, context, **response_kwargs): with schema_context(self.schema_name): return super().render_to_response(context, **response_kwargs)
这种方式不需要转换QuerySet为列表,所有模板内的数据库操作都会自动使用租户schema。
额外优化
你的get_context_data里重复执行了Appointment.objects.all()查询,其实ListView默认已经把get_queryset的结果存入context['object_list'],可以直接复用,减少一次数据库查询:
def get_context_data(self, **kwargs): with schema_context(self.schema_name): context = super().get_context_data(**kwargs) tenant_id = self.kwargs.get('pk') context['tenant_id'] = tenant_id # 复用已查询的结果,避免重复请求数据库 context['appointments'] = context['object_list'] print(context['appointments']) return context
内容的提问来源于stack exchange,提问作者Timon Basnet
相关产品推荐
相关产品推荐

