我正在使用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
您的项目设置中。
那么你可以启用:
'django.core.context_processors.request',
在您的settings.TEMPLATE_CONTEXT_PROCESSORS
街区中并挂出引荐来源网址,但这有点令人作呕,并且可能会到处中断。
大多数你想要这个的地方(例如SO上的编辑帖子页面)你都有一个真实的对象可以连接(在那个例子中,帖子)所以你可以很容易地计算出正确的前一页应该是什么。
<a href="{{request.META.HTTP_REFERER|escape}}">Back</a>
这里|escape
是用来摆脱" "
字符串的。
您始终可以使用非常简单的客户端选项:
<a href="javascript:history.go(1)">Back</a>
对于“返回”通常意味着更高一级的 RESTful 链接:
<a href="../"><input type="button" value="Back" class="btn btn-primary" /></a>
对于 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>
此处提到的所有 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>