在Django模板中如何通过JSONField存储的B模型外键获取B实例?
解决思路与实现方案
方法一:视图层构建ID-实例映射(推荐)
先在视图里把所有B实例按ID做成字典映射,这样模板里能直接通过ID快速获取对应对象,避免模板里做复杂逻辑,还能减少数据库查询次数。
修改views.py:
def myView(request): a_list = A.objects.all() # 将B实例按ID存入字典,方便模板通过ID直接查找 b_map = {b.id: b for b in B.objects.all()} context = { 'a_list': a_list, 'b_map': b_map, } template = loader.get_template('my_template.html') return HttpResponse(template.render(context, request))
Django模板不支持直接用b_map[b_id]的语法,需要自定义一个模板过滤器:
在你的app目录下创建templatetags文件夹(记得添加空的__init__.py文件),新建custom_filters.py:
from django import template register = template.Library() @register.filter def get_item(dictionary, key): return dictionary.get(key)
然后修改my_template.html,先加载过滤器再使用:
{% load custom_filters %} {% for my_a in a_list %} {% for b_id in my_a.foreignKeysOfB %} <tr> <td>{{ b_map|get_item:b_id.someField }}</td> </tr> {% endfor %} {% endfor %}
方法二:给模型A添加属性方法
直接在模型A里定义一个属性,返回对应的B实例列表,模板里直接调用这个属性就行。
修改models.py:
class A(models.Model): foreignKeysOfB = models.JSONField(null=True) @property def b_instances(self): # 先过滤掉无效ID,避免查询不存在的对象报错 valid_ids = [b_id for b_id in self.foreignKeysOfB if B.objects.filter(id=b_id).exists()] # 批量查询有效ID对应的B实例 b_list = B.objects.filter(id__in=valid_ids) # 保持原JSON列表里的顺序 id_order = {b_id: idx for idx, b_id in enumerate(self.foreignKeysOfB)} return sorted(b_list, key=lambda x: id_order[x.id])
修改views.py,不需要再传递B的查询集:
def myView(request): a_list = A.objects.all() context = { 'a_list': a_list, } template = loader.get_template('my_template.html') return HttpResponse(template.render(context, request))
模板my_template.html简化为:
{% for my_a in a_list %} {% for b_instance in my_a.b_instances %} <tr> <td>{{ b_instance.someField }}</td> </tr> {% endfor %} {% endfor %}
避坑提醒
- 绝对不要在模板里直接写
B.objects.get(id=b_id),这会触发N+1查询,数据量一大性能直接崩。 - 如果JSON里的ID可能无效(比如对应的B已删除),一定要提前过滤,避免抛出DoesNotExist异常。
内容的提问来源于stack exchange,提问作者arennuit
相关产品推荐
相关产品推荐

