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
相关产品推荐
相关产品推荐

