我正在使用 Django,我想知道是否有一种简单的方法可以使用模板系统创建指向上一页的“返回”链接。
我认为在最坏的情况下,我可以从视图函数中的请求对象获取此信息,并将其传递给模板渲染方法,但我希望我能以某种方式避免所有这些样板代码。
我检查了 Django 模板文档,但没有看到任何明确提到这一点的内容。
其实是
go(-1)
。
<input type=button value="Previous Page" onClick="javascript:history.go(-1);">
这个解决方案对我来说很有效:
<a href="{{request.META.HTTP_REFERER}}">Go back</a>
但这是之前在项目设置中将
'django.core.context_processors.request',
添加到 TEMPLATE_CONTEXT_PROCESSORS
中。
<a href="{{request.META.HTTP_REFERER|escape}}">Back</a>
这里
|escape
用于脱离 " "
字符串。
那么您可以启用:
'django.core.context_processors.request',
在你的
settings.TEMPLATE_CONTEXT_PROCESSORS
块中并勾出引荐来源网址,但这有点令人恶心,并且可能会到处破坏。
大多数你想要这个的地方(例如SO上的编辑帖子页面)你都有一个真实的对象可以挂钩(在这个例子中,帖子),这样你就可以轻松地找出正确的上一页应该是什么。
您始终可以使用非常简单的客户端选项:
<a href="javascript:history.go(1)">Back</a>
对于 RESTful 链接,“返回”通常意味着更高一级:
<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>
这里提到的所有 Javascript 解决方案以及
request.META.HTTP_REFERER
解决方案有时都可以工作,但两者都会在同一场景中出现问题(也许还有其他情况)。
我通常在创建或更改对象的表单下有一个取消按钮。如果用户提交表单一次并且服务器端验证失败,则会再次向用户提供包含错误数据的表单。你猜怎么着,
request.META.HTTP_REFERER
现在指向显示表单的 URL。您可以按取消一千次,并且永远不会回到最初编辑/创建链接所在的位置。
我能想到的唯一可靠的解决方案有点复杂,但对我有用。如果有人知道更简单的解决方案,我很高兴听到它。 :-) “技巧”是将初始的 HTTP_REFERER 传递到表单中并从那里使用它。因此,当表单被发布时,它会传递正确的初始引用者。
这是我的做法:
我为表单创建了一个 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 管理员更改表单中的“后退”按钮,我最终要做的是自定义模板过滤器来解析和解码模板中的“preserved_filters”变量。我将以下内容放在自定义的 templates/admin/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)
使用客户端解决方案将是正确的解决方案。
<a href="javascript:history.go(-1)" class="btn btn-default">Cancel</a>
在Web开发中,有多种方法来实现后退按钮。我想分享两种常见的方法。
<button onclick="history.back()">Back</button>
此方法利用JavaScript的history.back()函数导航到浏览器历史记录中的上一页。这是一个简单而有效的解决方案。
<a href="{{request.META.HTTP_REFERER}}">Back</a>
所有这些方法都可以存储页面的历史记录,因此,如果您打开没有历史记录的页面并尝试返回,它将不起作用,只需重新加载页面即可。这按预期工作。