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

如何在Django模板中为模型属性传递request.session日期参数?

问题描述

我有两个Django模型,通过validity_range字段记录不同时间段对应的信息:

class Person(models.Model):
    validity_range = DateTimeRangeField(default=(None, None))

class PersonData(models.Model):
    person = models.ForeignKey(Person, on_delete=models.RESTRICT)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    validity_range = DateTimeRangeField(default=(None, None))

举个实际场景:1980年1月1日出生的Eva Smith在2022年3月22日结婚后更名为Eva Novak,对应数据如下:

Person{id:1, validity_range:(1980-01-01, None)}
PersonData{id:1, person_id:1, first_name:'Eva', last_name:'Smith', validity_range:[1980-01-01, 2022-03-22)}
PersonData{id:2, person_id:1, first_name:'Eva', last_name:'Novak', validity_range:[2022-03-22, None)}

我将context_date存储在request.session['context_date']中,希望根据这个日期展示Person对应的姓名。当前视图代码:

def index(request):
   person = Person.objects.get(pk=1)
   context ={
      'person' : person,
      'context_date' : request.session.get('context_date')
   }
   html_template = loader.get_template('index.html')
   return HttpResponse(html_template.render(context, request))

模板代码:

Context_date is: {{ context_date }}

At that date Person no {{ person.id }} was called {{ person.person_data.first_name }} {{ person.person_data.last_name }}

显然模板写法错误,因为person_data是关联集合而非单个对象。我尝试给Person模型添加带参数的属性:

class Person(models.Model):
    validity_range = DateTimeRangeField(default=(None, None))
    @property
    def first_name(self, date):
        try: 
           person_data = PersonData.objects.get(validity_range__contains=date) # 假设时间段无重叠(数据库约束)
           return person_data.first_name
        except PersonData.DoesNotExist:
           return None # 该日期无对应PersonData!

但不知道如何在模板中给这个属性传递context_date参数,请问该如何解决?


解决方案

方法1:视图预查询对应PersonData

直接在视图层根据context_date查询出匹配的PersonData,将结果放入上下文,模板直接调用即可:

def index(request):
    person = Person.objects.get(pk=1)
    context_date = request.session.get('context_date')
    # 根据日期查询对应PersonData
    try:
        person_data = PersonData.objects.get(person=person, validity_range__contains=context_date)
    except PersonData.DoesNotExist:
        person_data = None
    context = {
        'person': person,
        'context_date': context_date,
        'current_person_data': person_data
    }
    html_template = loader.get_template('index.html')
    return HttpResponse(html_template.render(context, request))

模板修改为:

Context_date is: {{ context_date }}

{% if current_person_data %}
At that date Person no {{ person.id }} was called {{ current_person_data.first_name }} {{ current_person_data.last_name }}
{% else %}
No name record found for this date.
{% endif %}

这种方法逻辑集中在视图层,模板仅负责展示,符合Django MTV设计理念,简单直接。

方法2:自定义模板过滤器

如果需要在多个模板中复用该逻辑,可以编写自定义模板过滤器:

  1. 在你的app目录下创建templatetags文件夹,新建person_tags.py文件:
from django import template
from .models import PersonData

register = template.Library()

@register.filter
def get_person_name(person, date):
    try:
        person_data = PersonData.objects.get(person=person, validity_range__contains=date)
        return f"{person_data.first_name} {person_data.last_name}"
    except PersonData.DoesNotExist:
        return "No name record found"
  1. 在模板中加载并使用过滤器:
{% load person_tags %}

Context_date is: {{ context_date }}

At that date Person no {{ person.id }} was called {{ person|get_person_name:context_date }}

注意:需确保你的app已添加到settings.py的INSTALLED_APPS中,否则模板无法识别自定义过滤器。

方法3:修改模型方法(替换带参数的@property)

Django的@property不支持传递参数,可改为普通方法,再通过视图调用传递结果到模板:

模型修改:

class Person(models.Model):
    validity_range = DateTimeRangeField(default=(None, None))
    
    def get_name_at_date(self, date):
        try: 
           person_data = PersonData.objects.get(person=self, validity_range__contains=date)
           return (person_data.first_name, person_data.last_name)
        except PersonData.DoesNotExist:
           return (None, None)

视图中调用方法并传递结果:

def index(request):
    person = Person.objects.get(pk=1)
    context_date = request.session.get('context_date')
    first_name, last_name = person.get_name_at_date(context_date)
    context = {
        'person': person,
        'context_date': context_date,
        'first_name': first_name,
        'last_name': last_name
    }
    html_template = loader.get_template('index.html')
    return HttpResponse(html_template.render(context, request))

模板直接使用:

Context_date is: {{ context_date }}

{% if first_name and last_name %}
At that date Person no {{ person.id }} was called {{ first_name }} {{ last_name }}
{% else %}
No name record found for this date.
{% endif %}

内容的提问来源于stack exchange,提问作者Tomasz Brzezina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:13:20