如何在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:自定义模板过滤器
如果需要在多个模板中复用该逻辑,可以编写自定义模板过滤器:
- 在你的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"
- 在模板中加载并使用过滤器:
{% 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
相关产品推荐
相关产品推荐

