You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django TemplateView传Dict报500错误,求ListView/DetailView解决方案

问题修复与优化方案

一、当前问题的核心原因

  1. 模板变量缺失:BucketView未将coins变量传入模板上下文,导致模板中{% for coin in coins %}循环触发变量未定义错误,这是500服务器错误的主要诱因。
  2. Django模板语法限制:Django模板不支持prices[coin]这类直接通过变量键取值的写法——coin是Coin对象,即使__str__返回ticker,模板也不会自动将其转换为字典的字符串键;同时prices.get(coin, 'N/A')也无法直接生效,因为模板不支持传递变量作为字典get方法的参数。
  3. API调用无异常处理:循环调用Yahoo Finance API时未做异常捕获,若代币代码无效或请求失败,会直接抛出异常导致500错误。

二、修复步骤

1. 修正View层代码

补充coins变量到上下文,同时优化价格获取逻辑并增加异常处理,还可直接给Coin对象附加价格属性,避免模板处理字典取值:

class BucketView(LoginRequiredMixin, TemplateView):
    template_name = 'coinbucket/bucket.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        coins = Coin.objects.all()
        
        for coin in coins:
            try:
                ticker = yf.Ticker(coin.ticker)
                price = ticker.history(period='1d')['Close'][0]
                coin.price = f'$ {price:.6f}'
            except (IndexError, Exception):
                # 处理API请求失败或无数据的情况
                coin.price = 'N/A'
        
        context["coins"] = coins
        return context

2. 简化模板代码

现在模板可直接调用coin.price,无需处理字典:

{% for coin in coins %}
    <div class="col-12 col-md-8 my-2">
        <div class="card">
            <div class="card-body">
                <div class="row">
                    <div class="col">{{ coin.ticker }}</div>
                    <div class="col">{{ coin.price }}</div>
                </div>
            </div>
        </div>
    </div>
{% endfor %}

备选方案:自定义模板过滤器(保留prices字典场景)

若坚持使用prices字典,可自定义模板过滤器实现变量键取值:

  • 在app目录下创建templatetags文件夹,新建custom_filters.py:
from django import template

register = template.Library()

@register.filter
def get_item(dictionary, key):
    return dictionary.get(key, 'N/A')
  • 模板中加载过滤器并使用:
{% load custom_filters %}

{% for coin in coins %}
    <div class="col-12 col-md-8 my-2">
        <div class="card">
            <div class="card-body">
                <div class="row">
                    <div class="col">{{ coin.ticker }}</div>
                    <div class="col">{{ prices|get_item:coin.ticker }}</div>
                </div>
            </div>
        </div>
    </div>
{% endfor %}

同时确保View中传入coins和prices(记得给prices的获取逻辑加异常处理)。

三、ListView+DetailView实现建议

1. ListView实现(代币列表页)

用ListView替代TemplateView,贴合Django列表展示规范,同时注入价格数据:

class CoinListView(LoginRequiredMixin, ListView):
    model = Coin
    template_name = 'coinbucket/coin_list.html'
    context_object_name = 'coins'

    def get_queryset(self):
        queryset = super().get_queryset()
        for coin in queryset:
            try:
                ticker = yf.Ticker(coin.ticker)
                price = ticker.history(period='1d')['Close'][0]
                coin.current_price = f'$ {price:.6f}'
            except (IndexError, Exception):
                coin.current_price = 'N/A'
        return queryset

模板直接遍历coins并调用coin.current_price即可。

2. DetailView实现(代币详情页)

展示单个代币的详细价格信息(如历史走势、涨跌幅):

class CoinDetailView(LoginRequiredMixin, DetailView):
    model = Coin
    template_name = 'coinbucket/coin_detail.html'
    context_object_name = 'coin'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        coin = self.get_object()
        try:
            ticker = yf.Ticker(coin.ticker)
            # 获取近7天价格数据
            hist = ticker.history(period='7d')
            context['price_history'] = hist.reset_index().values.tolist()
            # 当前价格
            context['current_price'] = f'$ {hist["Close"].iloc[-1]:.6f}'
            # 24小时涨跌幅
            context['daily_change'] = f'{((hist["Close"].iloc[-1] - hist["Close"].iloc[-2])/hist["Close"].iloc[-2])*100:.2f}%'
        except Exception:
            context['price_history'] = []
            context['current_price'] = 'N/A'
            context['daily_change'] = 'N/A'
        return context

模板可展示核心数据,还可结合Chart.js等工具渲染历史价格走势:

<div class="card">
    <div class="card-body">
        <h2>{{ coin.ticker }}</h2>
        <p>当前价格:{{ current_price }}</p>
        <p>24小时涨跌幅:{{ daily_change }}</p>
        <!-- 此处可添加Chart.js图表渲染price_history数据 -->
    </div>
</div>

额外优化建议

  • 缓存价格数据:Yahoo Finance API有请求频率限制,且实时请求会拖慢页面,建议用Django缓存将价格数据缓存15-30分钟,避免重复请求。
  • 异步任务处理:若代币数量较多,API请求耗时久,可使用Celery等异步框架在后台更新价格,而非请求时同步获取。

内容的提问来源于stack exchange,提问作者Akshay Saambram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 11:52:38