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

Django DetailView中如何通过self获取对应日期的Expense查询集

家庭预算管理应用:Date详情页展示对应Expense数据的正确实现

我正在开发一款家庭预算管理应用,包含Date、Expense、Category、Income这几个模型,代码如下:

class Date(models.Model):
    name = models.CharField(max_length = 15)    
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='date')

class Category(models.Model):
    name = models.CharField(max_length=100)
    budget = models.DecimalField(max_digits=8, decimal_places=2)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='category')
    date = models.ForeignKey(Date, on_delete=models.CASCADE, related_name='date', default='Styczeń 2022')

class Expense(models.Model):
    name = models.CharField(max_length=100)
    amount = models.DecimalField(max_digits=8, decimal_places=2)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="account")
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='expense')
    date = models.ForeignKey(Date, on_delete=models.CASCADE, default='Styczeń 2022')

class Income(models.Model):
    name = models.CharField(max_length=100)
    amount = models.DecimalField(max_digits=8, decimal_places=2)
    account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="account_income")
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='income')

用户选择某个Date后进入DateDetailView,我希望在该详情页仅展示对应Date的Expense数据。尝试了两种写法但都不对,代码如下:

第一种写法:

class DateDetailView(DetailView):
    model = Date
    template_name = 'expense/date_detail.html'
    context_object_name = 'date'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['expense'] = Expense.objects.filter(date=F('pk'))
        return context

第二种写法:

class DateDetailView(DetailView):
    model = Date
    template_name = 'expense/date_detail.html'
    context_object_name = 'date'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['expense'] = Expense.objects.filter(date=self.date)
        return context

正确实现方案

方案1:利用DetailView的get_object()方法获取当前Date实例

class DateDetailView(DetailView):
    model = Date
    template_name = 'expense/date_detail.html'
    context_object_name = 'date'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 获取当前详情页对应的Date对象
        current_date = self.get_object()
        # 过滤出该Date关联的所有Expense
        context['expenses'] = Expense.objects.filter(date=current_date)
        return context

方案2:通过URL参数直接过滤

class DateDetailView(DetailView):
    model = Date
    template_name = 'expense/date_detail.html'
    context_object_name = 'date'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 从URL参数中获取当前Date的主键
        date_pk = self.kwargs.get('pk')
        # 通过主键关联过滤Expense
        context['expenses'] = Expense.objects.filter(date__pk=date_pk)
        return context

方案3:利用反向关联(更简洁)

先修改Expense模型的date字段,添加自定义反向关联名称:

# Expense模型中修改date字段
date = models.ForeignKey(Date, on_delete=models.CASCADE, default='Styczeń 2022', related_name='expenses')

之后无需修改DateDetailView,直接在模板date_detail.html中调用反向关联数据:

{% for expense in date.expenses.all %}
    <!-- 渲染Expense数据 -->
{% endfor %}

原写法错误说明

  • 第一种写法中F('pk')指向的是Expense表自身的主键,并非当前Date的主键,过滤条件完全错误。
  • 第二种写法中self.date不存在,DetailView获取当前对象需调用self.get_object()方法。

内容的提问来源于stack exchange,提问作者Filip Kania

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:55:44