如何在 Django 模板上实现“返回”链接?

Posted

技术标签:

【中文标题】如何在 Django 模板上实现“返回”链接?【英文标题】:How to implement a "back" link on Django Templates? 【发布时间】:2010-10-06 05:11:07 【问题描述】:

我正在处理Django,我想知道是否有一种简单的方法可以使用模板系统创建指向上一页的“返回”链接。

我认为在最坏的情况下,我可以从视图函数中的请求对象中获取此信息,并将其传递给模板渲染方法,但我希望我能以某种方式避免所有这些样板代码。

我查看了 Django 模板文档,但没有看到任何明确提及这一点的内容。

【问题讨论】:

当您返回时,页面会重新呈现,这意味着任何处理(数据库查询、资源下载等)都会重新发生。为防止这种情况,请使用 @cache_page 装饰器。 【参考方案1】:

其实是go(-1)

<input type=button value="Previous Page" onClick="javascript:history.go(-1);">

【讨论】:

对其他答案的回复属于 cmets 而非新答案。 对我来说在 safari 中不起作用。对于所有浏览器都使用这个:onClick="window.history.back();return false;" 如果禁用 Javascript,这些方法都不起作用。【参考方案2】:

这个解决方案对我有用:

<a href="request.META.HTTP_REFERER">Go back</a>

但这之前是在您的项目设置中将'django.core.context_processors.request', 添加到TEMPLATE_CONTEXT_PROCESSORS

【讨论】:

这行得通,但在 django 1.10 之后是:'django.template.context_processors.request', 如果您的settings.py 文件的模板部分中有'django.template.context_processors.request',,那么您只需将html 部分添加到您的模板中即可。 只有在您点击带有链接的按钮时才有效,否则如果您手动输入源并点击“返回”按钮,则不会发生任何事情。【参考方案3】:

你可以启用:

'django.core.context_processors.request',

在您的 settings.TEMPLATE_CONTEXT_PROCESSORS 块中并挂出引荐来源网址,但这有点令人作呕,并且可能会到处中断。

您希望在大多数地方(例如 SO 上的编辑帖子页面)都有一个真实的对象可以连接(在该示例中为帖子),因此您可以轻松计算出正确的上一页应该是什么.

【讨论】:

这是一个很好的信息,我在阅读后偶然发现了文档中的“Model.get_absolute_url”。这实际上解决了我的问题,但是如果您没有指向对象,我仍然很好奇最佳行动方案。 真的要视情况而定。如果有某种方法可以确定哪个页面“应该”是上一页,我会那样做。但有时这是不可能的,推荐人检查可能是你唯一的选择(除了让用户使用他们的后退按钮) . 我曾经尝试通过会话变量来做到这一点,但那是一个错误;易碎且一直断裂。您的选择是 Oli 提到的那些,或者使用 JavaScript 为它们单击“后退”按钮。【参考方案4】:
<a href="request.META.HTTP_REFERER|escape">Back</a>

这里|escape是用来跳出" "字符串的。

【讨论】:

简单、优雅、有效。 感谢它的工作。简单直接。【参考方案5】:

您始终可以使用非常简单的客户端选项:

<a href="javascript:history.go(1)">Back</a>

【讨论】:

我真的很讨厌这样的链接。首先,当您从保存的链接/另一个站点访问页面时,它们不起作用。其次,我只为受信任的站点启用 Javascript(使用 NoScript firefox 扩展)。还有其他原因,但评论空间有限。 我同意这不是最好的编码。但最大的优势是超级简单并且有效。如果您来自不同的站点,它也可以使用,因为它使用浏览器的 BACK 功能,无论您来自哪里。 你的意思是go(-1)【参考方案6】:

对于“返回”通常意味着更高一级的 RESTful 链接:

<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>

【讨论】:

【参考方案7】:

对于 Django 管理员更改表单中的“后退”按钮,我最终要做的是自定义模板过滤器,用于解析和解码模板中的“preserved_filters”变量。我将以下内容放在自定义模板/管理员/submit_line.html 文件中:

<a href="../% if original../% endif %? preserved_filters | decode_filter ">
    % trans "Back" %
</a>

然后创建了一个自定义模板过滤器:

from urllib.parse import unquote
from django import template

def decode_filter(variable):
    if variable.startswith('_changelist_filters='):
        return unquote(variable[20:])
    return variable

register = template.Library()
register.filter('decode_filter', decode_filter)

【讨论】:

【参考方案8】:

使用客户端解决方案将是正确的解决方案。

<a href="javascript:history.go(-1)" class="btn btn-default">Cancel</a>

【讨论】:

【参考方案9】:

这里提到的所有 Javascript 解决方案以及 request.META.HTTP_REFERER 解决方案有时都有效,但两者都在相同的情况下中断(可能还有其他情况)。

我通常在创建或更改对象的表单下有一个取消按钮。如果用户提交表单一次并且服务器端验证失败,则再次向用户呈现表单,其中包含错误的数据。猜猜看,request.META.HTTP_REFERER 现在指向显示表单的 URL。您可以按取消一千次,并且永远不会回到最初的编辑/创建链接所在的位置。

我能想到的唯一可靠的解决方案有点复杂,但对我有用。如果有人知道一个更简单的解决方案,我很乐意听到它。 :-) “诀窍”是将初始 HTTP_REFERER 传递到表单中并从那里使用它。因此,当表单被 POST 到时,它会传递正确的初始引用。

这是我的做法:

我为完成大部分工作的表单创建了一个 mixin 类:

from django import forms
from django.utils.http import url_has_allowed_host_and_scheme

class FormCancelLinkMixin(forms.Form):
    """ Mixin class that provides a proper Cancel button link. """
    cancel_link = forms.fields.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        """
        Override to pop 'request' from kwargs.
        """
        self.request = kwargs.pop("request")
        initial = kwargs.pop("initial", )
        # set initial value of 'cancel_link' to the referer
        initial["cancel_link"] = self.request.META.get("HTTP_REFERER", "")
        kwargs["initial"] = initial
        super().__init__(*args, **kwargs)

    def get_cancel_link(self):
        """
        Return correct URL for cancelling the form.

        If the form has been submitted, the HTTP_REFERER in request.meta points to
        the view that handles the form, not the view the user initially came from.
        In this case, we use the value of the 'cancel_link' field.

        Returns:
            A safe URL to go back to, should the user cancel the form.

        """
        if self.is_bound:
            url = self.cleaned_data["cancel_link"]
            # prevent open redirects
            if url_has_allowed_host_and_scheme(url, self.request.get_host()):
                return url

        # fallback to current referer, then root URL
        return self.request.META.get("HTTP_REFERER", "/")

用于编辑/创建对象的表单(通常是 ModelForm 子类)可能如下所示:

class SomeModelForm(FormCancelLinkMixin, forms.ModelForm):
    """ Form for creating some model instance. """

    class Meta:
        model = ModelClass
    # ...

视图必须将当前请求传递给表单。对于基于类的视图,您可以覆盖 get_form_kwargs():

class SomeModelCreateView(CreateView):
    model = SomeModelClass
    form_class = SomeModelForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["request"] = self.request
        return kwargs

在显示表单的模板中:

<form method="post">
  % csrf token %
   form 
  <input type="submit" value="Save">
  <a href=" form.get_cancel_link ">Cancel</a>
</form>

【讨论】:

以上是关于如何在 Django 模板上实现“返回”链接?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jinja 中实现类似 Django 的标签

如何在 Facebook 应用内消息上实现深层链接

如何在社交网络上实现一个可以让不同人获得 5 次奖励的链接?

Django:返回上一个 HTML 中的同一点

如何使用 OkHttp 在 Android 上实现 cookie 处理?

如何使用 ModelAndView 在 RestController 上实现 REST API