Django模板渲染问题:Model中带变量的HTML代码无法解析
问题描述
我在数据库中存储了带Django模板变量的HTML代码,但渲染时Django无法识别product.price这类变量,直接把它们当成字符串输出了。
相关代码
Model代码(model.py)
class Badge(models.Model): name = models.CharField(max_length=255) code = models.CharField(max_length=700, default='<h5><span class="badge bg-primary ms-2">New</span></h5>') code_price = models.CharField(max_length=700, default='<s>{{product.price | safe}}</s><strong class="ms-2 text-danger">{{product.get_price_with_discount() | safe}}</strong>') # product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='badges') def __str__(self): return self.name class Product(models.Model): """产品模型""" name = models.CharField(max_length=255) price = models.DecimalField(max_digits=10, decimal_places=2) image = models.ImageField(upload_to='static/img/' , default='/static/img/404.png') category = models.ForeignKey(Category, on_delete=models.CASCADE) type = models.ForeignKey(Badge, on_delete=models.CASCADE, related_name= "products") def get_price_with_discount(self): discount = (self.price) * (10 / 100) return self.price - discount
模板代码(services.html)
<section> <div class="text-center container py-5"> <h4 class="mt-4 mb-5"><strong>畅销品</strong></h4> <div class="row"> {% for product in products %} <div class="col-lg-4 col-md-12 mb-4"> <div class="card"> <div class="bg-image hover-zoom ripple ripple-surface ripple-surface-light" data-mdb-ripple-color="light"> <img src="{{product.image.url}}" class="w-100" style="height: 500px;" /> <a href="#!"> <div class="mask"> <div class="d-flex justify-content-start align-items-end h-100"> {% comment %} <h5><span class="badge bg-primary ms-2">New</span></h5> {%endcomment %} {{product.type.code|safe}} </div> </div> <div class="hover-overlay"> <div class="mask" style="background-color: rgba(251, 251, 251, 0.15);"></div> </div> </a> </div> <div class="card-body"> <a href="" class="text-reset"> <h5 class="card-title mb-3">{{ product.name}}</h5> </a> <a href="" class="text-reset"> <p>{{ product.category.name}}</p> </a> <h6 class="mb-3">${{ product.type.code_price | safe }}</h6> </div> </div> </div> {% endfor %} </div> </section>
效果差异
- 预期效果:页面渲染出带划线的原价和红色字体的折扣价
- 实际效果:页面直接显示
{{product.price | safe}}、{{product.get_price_with_discount() | safe}}这类未解析的字符串
解决方案
Django默认只会解析模板文件中写死的变量,数据库存储的模板代码不会被二次渲染。要实现需求,需要手动编写自定义模板标签来解析这些字符串。
步骤1:创建自定义模板标签
在你的Django应用目录下创建templatetags文件夹,里面新建两个文件:__init__.py(空文件即可)和render_db_template.py,代码如下:
# templatetags/render_db_template.py from django import template from django.template import Template, Context register = template.Library() @register.simple_tag(takes_context=True) def render_template(context, template_string): # 从当前模板上下文获取product对象 product = context.get('product') # 创建模板实例并传入上下文渲染 template = Template(template_string) return template.render(Context({'product': product}))
步骤2:修改模板使用自定义标签
在services.html开头加载自定义标签,替换原来的|safe用法:
{% load render_db_template %} <section> <div class="text-center container py-5"> <h4 class="mt-4 mb-5"><strong>畅销品</strong></h4> <div class="row"> {% for product in products %} <div class="col-lg-4 col-md-12 mb-4"> <div class="card"> <div class="bg-image hover-zoom ripple ripple-surface ripple-surface-light" data-mdb-ripple-color="light"> <img src="{{product.image.url}}" class="w-100" style="height: 500px;" /> <a href="#!"> <div class="mask"> <div class="d-flex justify-content-start align-items-end h-100"> {% render_template product.type.code %} </div> </div> <div class="hover-overlay"> <div class="mask" style="background-color: rgba(251, 251, 251, 0.15);"></div> </div> </a> </div> <div class="card-body"> <a href="" class="text-reset"> <h5 class="card-title mb-3">{{ product.name}}</h5> </a> <a href="" class="text-reset"> <p>{{ product.category.name}}</p> </a> <h6 class="mb-3">$ {% render_template product.type.code_price %}</h6> </div> </div> </div> {% endfor %} </div> </section>
注意事项
- 确保
templatetags文件夹结构正确,__init__.py必须存在(可以为空) - 自定义标签已处理HTML安全渲染,无需额外添加
|safe过滤器 - 如果数据库中的模板字符串包含其他变量,可在
Context中添加对应变量传递
内容的提问来源于stack exchange,提问作者Dhrumil Shah
相关产品推荐
相关产品推荐

