Django dj-stripe 自定义metadata无法绑定到Product对象问题
Django+Stripe集成自定义metadata模板不渲染问题修复
问题根因
渲染失败由4个核心问题导致,和教程前置说明无关:
- 导入错误:
List类型注解错误从pip模块导入,属于无效代码 - 核心逻辑缺失:你只是单独定义了
ProductMetadata数据类,完全没有将自定义的metadata实例和djstripe同步到本地数据库的Product模型对象做关联。djstripe的Product模型自带的metadata字段是Stripe后台存储的原生键值对,不是你本地定义的数据类实例,自然读不到你写的name、features等字段 - 字段缺失:模板中使用了
product.metadata.monthly_price字段,但你定义的ProductMetadata类里没有声明这个属性,就算匹配成功也读不到值 - 上下文缺失:模板中计划切换按钮区域用到了
plans变量,但视图没有往上下文传这个值,对应区域会空白
修复步骤
1. 修正metadata.py代码
首先修正错误导入,补充产品映射字典和缺失的字段:
from dataclasses import dataclass from typing import List # 修正之前的错误导入,List来自typing模块,和pip无关 from project.subscriptions import features @dataclass class ProductMetadata: """Stripe产品自定义元数据""" stripe_id: str name: str features: List[str] description: str = '' is_default: bool = False monthly_price: str = '' # 补充模板用到的月付价格字段 PREMIUM = ProductMetadata( stripe_id='替换为Stripe后台对应Premium产品的真实ID', name='Premium', description='yerp', is_default=False, monthly_price='29', # 填写对应价格 features=[ features.UNLIMITED_WIDGETS, features.LUDICROUS_MODE, features.PRIORITY_SUPPORT, ], ) # 新增产品ID和metadata的映射字典,用于后续匹配 PRODUCT_METADATA_MAP = { PREMIUM.stripe_id: PREMIUM, # 后续新增其他套餐(比如免费版),按相同格式在这里追加即可 }
2. 修改视图层绑定逻辑
在视图中查询出Product对象后,通过Stripe产品ID匹配对应的自定义metadata,动态绑定到Product实例上再传给模板:
from django.shortcuts import render from djstripe.models import Product from project.subscriptions.metadata import PRODUCT_METADATA_MAP # 导入metadata映射 def pricing_page(request): products = Product.objects.all() # 为每个产品绑定匹配到的自定义metadata for product in products: # 匹配不到metadata时赋值None,避免模板渲染报错 product.metadata = PRODUCT_METADATA_MAP.get(product.id, None) context = { 'products': products, # 模板用到了plans变量,按需取消注释补全查询逻辑 # 'plans': Plan.objects.all() } return render(request,'subscriptions/pricing_page.html', context=context)
3. 调整模板增加空值判断
避免未配置metadata的产品渲染时报错,给metadata区域增加存在性判断:
<div class="columns plan-selector"> {% for product in products %} {% if product.metadata %} <div class="column"> <div {% if product.metadata.is_default %}class="is-selected"{% endif %}> <span class="icon"> <i class="fa {% if product.metadata.is_default %}fa-check{% else %}fa-circle{% endif %}"></i> </span> <p class="plan-name">{{ product.metadata.name }}</p> <p class="plan-description">{{ product.metadata.description }}</p> <div class="plan-price"> <span class="price">{{ product.metadata.monthly_price }}</span> / month </div> <ul class="features"> {% for feature in product.metadata.features %} <li> <span class="icon"><i class="fa fa-check"></i></span> <span class="feature">{{ feature }}</span> </li> {% endfor %} </ul> </div> </div> {% endif %} {% endfor %} </div>
校验注意点
- 填写的
stripe_id必须和Stripe后台、djstripe同步到本地数据库的Product ID完全一致,否则会匹配失败 - 配置完成后如果还是不显示,先去Django admin里确认对应的Product记录已经从Stripe同步到本地数据库
- 之前错误的
from pip import List导入直接删除即可,没有任何作用
内容的提问来源于stack exchange,提问作者Jonathan Sumner
相关产品推荐
相关产品推荐

