当前位置: 首页 > 后端技术 > Python

Django搭建个人博客:自定义模板过滤器和标签

时间:2023-03-26 00:31:02 Python

现在我们对Django的MTV模式已经非常熟悉了。模板(template)负责如何展示数据,视图(view)负责过滤出正确的数据。所以通常逻辑都是放在view里面的,但是template也需要一些和presentation相关的逻辑:比如循环显示(比如{%for...%}),或者以特定的格式输出(比如{{...|date:'Y-m-d'}})等,这些功能都是通过模板过滤器(filters)和标签(tags)来实现的。Django的模板语言包括许多内置的过滤器和标签,旨在满足应用程序的占位符逻辑要求。但有时这些常用功能并不能满足您的某些需求。这时候就需要自定义过滤器和标签来实现了。前提条件要在Django中使用模板过滤器或标签,必须先注册它们。注册方法如下:在APP中新建一个名为templatetags的目录(为了方便,教程选择APP篇),并在该目录下新建一个名为__init__.py的空文件,这样该目录就被认为是一个Python包在这个目录下新建一个python文件(比如my_filters_and_tags.py),就可以愉快的在里面写代码了。完成后的目录结构如下:article/__init__.pyviews.pymodels.py#Addnewdirectorytemplatetags/__init__.py#Emptyfilemy_filters_and_tags.py#即将写入代码的地方...请注意:该目录必须位于已注册的APP中,这是出于安全考虑创建新目录后,必须手动重启服务器,里面的过滤器和标签才能完成验证的前提条件。接下来,让我们看看如何编写模板过滤器。模板过滤器过滤器过滤器的表达形式是管道符号|紧跟在上下文之后,管道符号后跟过滤器的名称:{{...|filter_name}}。一些过滤器还可以有参数:{{...|filter_name:var}}。请注意,过滤器名称中的冒号后不能有空格。filter这个名字可能会让你误以为它只是用来过滤一些特定的数据,但实际上它的功能远不止这个。它可以改变上下文的最终显示效果,也可以通过操作将上下文输出为一个特定的值。要使其成为一个可用的过滤器,该文件必须包含一个名为register的模块级变量,它是template.Library的一个实例,所有过滤器都在其中注册。所以在my_filter_and_tags.py文件中输入:article/templatetags/my_filter_and_tags.pyfromdjangoimporttemplateregister=template.Library()然后就可以像普通的Python函数一样写过滤器了:article/templatetags/my_filter_and_tags.pyfromdjangoimporttemplateregister=template。Library()@register.filter(name='transfer')deftransfer(value,arg):"""强制输出到字符串arg"""returnarg@register.filter()deflower(value):"""将字符串转换为小写字符"""返回值。lower()过滤器可以通过装饰器注册。如果注册装饰器中携带了name参数,则其值为过滤器的名称;如果不携带,函数名就是过滤器的名字。filter必须是带有一个或两个参数的Python函数。第一个参数是context本身,第二个参数是filter提供的。例如,在过滤器{{var|foo:"bar"}}中,变量var是第一个参数,变量bar是第二个参数。调用这些过滤器的方法是使用{%load...%}在模板文件中加载过滤器文件的名称,像这样:#{%loadmy_filters_and_tags%}在任何模板文件中{{'ABC'|transfer:'cool'}}#Output:'cool'{{'ABC'|lower}}#Output:'abc'更人性化的时间了解了过滤器的使用方法后,我们来写一些更实用的函数。对于像人类这样的生物,相对时间通常比绝对时间更容易阅读。发表于3天前,你可以轻松知道这篇文章发表于不久前;并于2019年8月10日发布,您必须考虑今天是什么日子。所以写一个显示相对日期的time_since_zh过滤器:article/templatetags/my_filter_and_tags.py...fromdjango.utilsimporttimezoneimportmath#Getrelativetime@register.filter(name='timesince_zh')deftime_since_zh(value):now=timezone.now()diff=now-valueifdiff.days==0anddiff.seconds>=0anddiff.seconds<60:return'just'ifdiff.days==0anddiff.seconds>=60anddiff.seconds<3600:返回str(math.floor(diff.seconds/60))+"分钟前"如果diff.days==0且diff.seconds>=3600且diff.seconds<86400:returnstr(math.floor(diff.seconds/3600))+"小时前"如果diff.days>=1且diff.days<30:returnstr(diff.days)+"daysago"如果diff.days>=30且diff.days<365:返回str(math.floor(diff.days/30))+“几个月前”如果diff.days>=365:返回str(math.floor(diff.days/365))+"Yearsago"代码功能很简单,就是比较文章的发表时间和当前时间,然后返回合适的字符串。修改文章列表模板文件中发布时间相关的代码,使用刚才写的过滤器:templates/article/list.html...{%loadmy_filters_and_tags%}...{{article.created|timesince_zh}}...效果如下:其实Django内置了timesince过滤器,但只显示日期是英文的,不够友好。模板标签模板标签(tags)比过滤器更复杂、更强大。tag标签的形式是{%tag_name...%},比如我们非常熟悉的内置标签{%url...%}、{%static...%}。如果内置标签不能满足您的需求,Django提供了许多快捷方式,可以简化大多数类型标签的编写过程。简单标签simple_tag是最重要的标签类型。标签注册方式和过滤器很像:@register.simple_tagdefchange_http_to_https(url):new_url=url.replace('http://','https://')returnnew_url也记得用在调用{%load...%}导入时的模板文件。你应该猜到用法:{%change_http_to_https...%},这个标签的作用是将http链接替换为https链接。使用django-allauth登录微博,默认返回的用户头像是http链接(虽然微博有https版本的头像)。如果你的网站已经升级到https,又不想花时间去研究微博的界面,那么这个标签就可以派上用场了。对了,Django-allauth第三方登录的头像url存放在User.socialaccount_set.all.0.get_avatar_url中。下面的例子可以返回指定格式的时间字符串:importdatetime@register.simple_tagdefcurrent_time(format_string):returndatetime.datetime.now().strftime(format_string)调用时可以保存为模板变量,这样你可以Expectedlocationcalledmultipletimes:{%current_time"%Y-%m-%d%I:%M%p"asthe_time%}

Thetimeis{{the_time}}.

同样,时间是{{the_time}}。

模板标签也可以访问当前上下文,注册标签时传入takes_context参数即可:@register.simple_tag(takes_context=True)defcurrent_time(context,format_string):timezone=context['timezone']returnyour_get_current_time_method(timezone,format_string)注意第一个参数必须是context。与过滤器不同,标签可以接受任意数量的位置或关键字参数。示例:@register.simple_tagdefmy_tag(a,b,*args,**kwargs):warning=kwargs['warning']profile=kwargs['profile']...return...在模板中调用时,任何要传递给模板标记的多个以空格分隔的参数。与Python类似,关键字参数的赋值使用等号(“=”),必须在位置参数后提供:{%my_tag123"abcd"book.titlewarning=messageprofile=user.profile%}containstagscontains标签允许另一个模板为当前模板呈现数据。听起来很别扭,但是让我们通过例子来理解它。假设需要在文章详情页显示所有相关评论的发布时间。所以在my_filter_and_tags.py中这样写:my_filter_and_tags.py...@register.inclusion_tag('article/tag_list.html')defshow_comments_pub_time(article):"""显示文章评论的发表时间"""comments=article.comments.all()return{'comments':comments}函数传入的参数可以是模板中的上下文变量。在函数体内,获取所有相关评论的查询集,然后返回结果评论。注意返回的结果是输入到模板tag_list.html中的,所以创建它并写:templates/article/tag_list.html
    {%forcommentincomments%}
  • {{comment.created}}
  • {%endfor%}
然后在文章详情页的模板中,找个地方写:templates/article/detail.html...{%loadmy_filters_and_tags%}...{%show_comments_pub_timearticle%}刷新详情页,顺利的话可以看到显示了所有评论的发布时间。另一个包含标签的应用场景是各种按钮。有些按钮看起来很相似,但根据页面的不同,它们的功能也不同。这时候也可以使用include标签来实现。总之,include标签可以将常用的模板代码打包成小组件,方便复用。include标签暂时没有在当前博客项目中使用,所以随意删除上面的代码。综上所述,模板过滤器和标签可以完成和表达相关逻辑,使视图可以专注于业务的核心逻辑,有利于组件化和逻辑分离。随着你了解的越来越多,你会逐渐意识到它的重要性。本章对它们进行介绍,以便读者对它们有一个初步的概念。更详细的解释请进一步阅读Django官方文档。如有任何问题,请在杜赛个人网站留言,我会尽快回复。或者私信给我:dusaiphoto@foxmail.com项目完整代码:Django_blog_tutorial