覆盖现有的Django模板标签

20

是否可以覆盖现有的Django模板标签?还是必须自定义模板文件并创建新的模板标签?


是的,这是可能的。例如 https://dev59.com/kmcs5IYBdhLWcg3wJQi7#13106661 - okm
7个回答

22

我也在寻找同样的答案,所以想在这里分享我的解决方案。我希望覆盖Django中默认的URL模板标签,而不必使用自定义模板标签并在每个模板文件中加载它。

目标是将 %20(空格)替换为 + (加号)。这是我想出来的解决方法...

__init__.py 中:

from django.template.defaulttags import URLNode

old_render = URLNode.render
def new_render(cls, context):
  """ Override existing url method to use pluses instead of spaces
  """
  return old_render(cls, context).replace("%20", "+")
URLNode.render = new_render

这个页面很有用 https://github.com/django/django/blob/master/django/template/defaulttags.py


为了提高代码质量,这个功能与Rails的alias_method_chain非常相似,只是没有“without”的语义。 - ncavig
5
你好,@ncavig,请问你是在哪个"init.py"文件中做了这件事? - EralpB

10
我认为“现有的Django模板标签”是指不同应用程序中的标签。
创建一个名为templatetags/tagfile.py的文件,并注册相同名称的标签。 确保tagfile是模板使用{% load tagfile %}加载原始标签的相同名称。
此外,请确保您的应用程序在INSTALLED_APPS中列在原始应用程序之后。

2
一个类似的想法:你可以从另一个库中加载register对象(另一个库应该有类似于register = template.Library()的东西,然后通过执行@register.tag等来注册标签)。你可以导入register而不是实例化自己,并执行@register.tag(tag_name='existing_tag') - floer32
这可能是最好的解决方案! - Andrey
很不幸,它给了我一个警告:(templates.E003) 'admin_list' 被多个模板标签模块使用:'myapp.templatetags.admin_list','someapp.templatetags.admin_list' - mdr

4

我非常确定您正在要求完全覆盖 Django 的 templatetag

简短的回答是——是的,您可以覆盖现有的 templatetag

以下是如何实现:

  • 您必须将您的模板目录包含在 settings 中:
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'your_app/templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                    'django.template.context_processors.static',
                ],
            },
        },
    ]
  • 您必须将想要覆盖templatetag的应用程序包含在INSTALLED_APPS中:
INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'your_app_name',
        ...
    ]

重要的一点是将您的应用程序放在django应用程序之后!
这是由于django的工作方式。我们将利用它。
现在,在您的应用程序内创建一个名为“templatetags”的文件夹。在templatetags中有一个__init__.py文件非常重要,这样django才能理解它是一个python包!:
your_app_name /templatetags/__init__.py。
创建您想要覆盖的templatetag。在那个例子中,我将使用admin_list.py标签。
在这种情况下,它应该放在这里:
your_app_name/templatetags/admin_list.py
现在复制整个django的admin admin_list.py内容(非常重要!)从django.contrib.admin.templatetags.admin_list.py并修改您想要的任何内容。
重要的是拥有整个django的admin admin_list.py的内容,而不仅仅是一段代码,否则它将无法工作!
它的工作原理: Django正在查找您的应用程序中的templatetags文件夹,并使用其中的模板标记。它将您的模板标记放在admin标记之后,简而言之 - 它在INSTALLED_APPS中将它们放在django.admin之后,从而覆盖它们。
不要忘记: ./manage.py collectstatic 设置DEBUG = False 在生产中。
我已经为result_list(cl)函数覆盖进行了测试,并且它正在工作。
此解决方案即使没有自定义html模板文件也可以工作。
希望这有所帮助。

有没有办法“扩展”现有的templatetag文件,就像我们在Django模板中所做的那样? - user9057586

2

是的。

Django基本上是一个Python库(与Python中的所有内容一样),因此您可以覆盖任何想要的内容。

不清楚您想要做什么,但编写自定义模板标签真的非常容易,文档非常清晰:https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags

这很基础,但这是我用来开始构建自定义模板标签的模板:

myapp/templatetags/my_custom_tags.py (此目录中必须有__init__.py

from django import template
register = template.Library()

class CustomTag(template.Node):
    def render(self, context):
        context['my_custom_tag_context'] = "this is my custom tag, yeah"
        return ''

@register.tag(name='get_custom_tag')
def get_custom_tag(parser, token):
    return CustomTag()

在模板中使用的方法如下:

{% load my_custom_tags %}
{% get_custom_tag %}
{{my_custom_tag_context}}

您可能需要解析 token,并且您可能需要在类中添加某种形式的 __init__,但这表明它有多基础。


您可以浏览现有的“默认”模板标签,复制并修改它们以符合您的需求。

那里确实有一些很棒的东西: https://github.com/django/django/blob/master/django/template/defaulttags.py


10
这个例子展示了如何创建一个新的标签,但是如何在另一个py文件中覆盖现有的标签呢?我不想在模板文件不必要的情况下去修改它。 - tom

1

实际上得票最多的解决方案对我来说有一个主要的缺点-您需要重新定义所有标记。 对于某些项目,这可能是一个很大的缺点。 如何解决?正如m_floer所提到的那样,最好从外部模块导入注册实例。那么它应该是什么样子?代码来自Django Jazzmin:

我想做什么?覆盖唯一的模板标记:get_side_menu标记。
该标记位于jazzmin.templatetags.jazzmin中,因此在我们的应用程序中,我们将创建带有文件jazzmin.py的模块templatetags。内容如下:

...
from jazzmin.templatetags.jazzmin import register


@register.simple_tag(takes_context=True, name="get_side_menu")
def get_side_menu(context: Context, using: str = "available_apps") -> List[Dict]:
    ...  # your template tag code

这将以最简单的方式覆盖仅选择的Django模板标签。请注意,这适用于给定项目中的所有应用程序!


1
如果您不想依赖于settings.py中的app顺序INSTALLED_APPS,那么可以尝试以下方法:
像往常一样创建templatetag函数/类。假设您想要覆盖名为otherapp_tags.current_time的templatetag,该templatetag来自名为other_app的app。首先,创建您自己的版本的函数/类:
def my_current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

那么,不要在您的应用程序命名空间中注册此函数/类,而是修补来自其他应用程序的现有函数:

from other_app.templatetags import otherapp_tags

otherapp_tags.register.tags['current_time'] = my_current_time

通常应该在您的AppConfigready()方法中执行此操作。


0
你可以覆盖Django模板标签。*你可以看到我的回答,解释了如何创建Django模板标签。
首先,在settings.py所在的core文件夹中创建templatetags文件夹,并在其中创建__init__.py(空文件)和custom_tags.py,如下所示。然后不要忘记重新启动服务器,以应用custom_tags.py到Django项目。*对于custom_tags.py,其他名称也可以,你可以看到我的回答,解释了templatetags文件夹加载标签
django-project
 |-core
 |  |-settings.py
 |  └-templatetags # Here
 |     |-__init__.py
 |     └-custom_tags.py
 |-templates
 |  └-index.html
 |-app1
 └-app2

而且,不要忘记在`settings.py`中将`core`设置为`INSTALLED_APPS`,以便将`custom_tags.py`应用到Django项目中,如下所示。*将`core`设置为`INSTALLED_APPS`还可以使用`python manage.py collectstatic`将`core`文件夹中的静态文件收集到根Django项目文件夹中。我建议在开始构建Django项目之前将`core`设置为`INSTALLED_APPS`。
# "core/settings.py"

INSTALLED_APPS = [
    # ...
    'core', # Here
    'app1',
    'app2',
]

下一步,在custom_tags.py中覆盖comment标签,如下所示。*您可以在/django/template/defaulttags.py中查看原始的评论标签:
# "custom_tags.py"

from django.template import Library, Node

register = Library()

@register.tag
def comment(parser, token):
    parser.skip_past('endcomment')
    return CommentNode()

class CommentNode(Node):
    def render(self, context):
        return 'This is not a comment.' # This part is changed.

然后,如下所示使用重写的注释标签:

然后,如下所示使用重写的注释标签:

# "templates/index.html"

{% load custom_tags %}

{% comment %}{% endcomment %}

然后,下面显示的是:
This is not a comment.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接