Django如何在HTML模板中获取关联模型的最新价格记录
实现方案
你写的{{ product.id.price }}逻辑不成立:product.id是产品主键的整数值,没有关联价格的属性,自然取不到值。正确实现优先在视图层完成数据预处理,避免模板层查询导致的N+1性能问题,步骤如下:
1. 修正视图层逻辑,预取最新价格
原代码有两个基础问题:一是模型名笔误,定义的模型是Product不是Products;二是没有提前关联价格数据,直接在模板查会产生大量重复数据库请求。
修改views.py,使用Django内置的Prefetch对象提前把每个产品的最新价格绑定到产品实例上:
from django.db.models import Prefetch from .models import Product, PriceHistory @login_required def overview(request): # 定义价格历史的预取规则:按创建时间倒序,第一条就是最新价格 latest_price_prefetch = Prefetch( lookup='pricehistory_set', # 外键默认反向关联名 queryset=PriceHistory.objects.order_by('-creation_date'), to_attr='latest_price_list' # 把预取结果存在这个自定义属性上 ) all_products = Product.objects.filter( user=request.user ).prefetch_related(latest_price_prefetch) general_context = {'all_products': all_products} return render(request, 'overview.html', general_context)
说明:因为
PriceHistory关联Product的外键字段没有指定related_name,Django默认生成的反向关联名为小写模型名_set,也就是pricehistory_set。
2. 修正模板代码,渲染价格
原模板存在标签闭合错误:<tr>写在循环内,</tr>却写在循环外,会导致表格结构错乱。修正后直接读取预取的最新价格即可:
<h4>Overview Products</h4> <table> <thead> <tr> <th>#</th> <th>Name</th> <th>Url</th> <th>Last price</th> </tr> </thead> <tbody> {% for product in all_products %} <tr> <td>{{ forloop.counter }}</td> <td>{{ product.name|default:"未命名产品" }}</td> <td>{{ product.url|default:"未录入链接" }}</td> <td> {% with latest=product.latest_price_list.0 %} {{ latest.price|default:"暂无价格记录" }} {% endwith %} </td> </tr> {% endfor %} </tbody> </table>
这里用with标签取预取列表的第一个元素(也就是创建时间最新的价格记录),同时加了默认值处理,避免没有价格数据时页面显示空白或者报错。
可选优化
如果觉得默认反向关联名不好记,可以给外键加related_name参数,修改models.py中的PriceHistory外键字段:
product_info = models.ForeignKey( Product, on_delete=models.CASCADE, related_name='price_records' # 自定义反向关联名 )
修改后执行数据库迁移命令python manage.py makemigrations、python manage.py migrate,之后视图里Prefetch的lookup参数替换为'price_records'即可,代码语义更清晰。
内容的提问来源于stack exchange,提问作者Gerhand
相关产品推荐
相关产品推荐

