我正在尝试构建一个URL别名应用,允许用户在其网站中为现有网址创建别名。
我正在尝试通过中间件执行此操作,其中根据别名的数据库记录检查request.META['PATH_INFO']
:
try:
src: request.META['PATH_INFO']
alias = Alias.objects.get(src=src)
view = get_view_for_this_path(request)
return view(request)
except Alias.DoesNotExist:
pass
return None
但是,为了使其正常工作,至少将PATH_INFO更改为目标路径是至关重要的。
现在有一些片段允许开发人员创建测试请求对象(http://djangosnippets.org/snippets/963/,http://djangosnippets.org/snippets/2231/),但这些片段表明它们是用于测试目的。
当然,可能这些片段适合在实时环境中使用,但我对Django请求处理的了解太过不发达,无法对此进行评估。
答案 0 :(得分:4)
您考虑使用Redirects应用程序吗?
而不是您正在采取的方法它不会隐藏别名路径/ foo /返回视图栏(),但它会重定向/ foo /到/ bar /
答案 1 :(得分:2)
(发布为答案,因为评论似乎不支持换行符或其他标记)
感谢您的建议,我对修改请求属性有同感。必须有一个原因,Django手册说它们应该被认为是只读的。
我提出了这个中间件:
def process_request(self, request):
try:
obj = A.objects.get(src=request.path_info.rstrip('/')) #The alias record.
view, args, kwargs = resolve_to_func(obj.dst + '/') #Modified http://djangosnippets.org/snippets/2262/
request.path = request.path.replace(request.path_info, obj.dst)
request.path_info = obj.dst
request.META['PATH_INFO'] = obj.dst
request.META['ROUTED_FROM'] = obj.src
request.is_routed = True
return view(request, *args, **kwargs)
except A.DoesNotExist: #No alias for this path
request.is_routed = False
except TypeError: #View does not exist.
pass
return None
但是,考虑到反对修改请求属性的反对意见,这不是一个更好的解决方案,只是跳过该部分,只添加is_routed
和ROUTED_TO
(而不是路由)份?
依赖于原始路径的代码可以使用来自META的密钥。
使用URLConfs执行此操作是不可能的,因为此别名旨在使最终用户能够配置自己的URL,并假设最终用户无法访问代码库或不知道如何编写他的拥有URLConf。
虽然可以编写一个将用户可读编辑文件(例如XML)转换为有效Django网址的函数,但它认为使用数据库记录可以更动态地生成别名(其他对象定义自己的别名)。
答案 2 :(得分:1)
很抱歉发帖,但我在搜索答案时发现了这个帖子。我的解决方案似乎更简单。也许a)我依赖于较新的django功能或b)我错过了一个陷阱。
我遇到了这个问题,因为有一个名为“Mediapartners-Google”的机器人要求页面的url参数仍然编码为天真的刮擦(或双重编码取决于你如何看待它。)即我有404s在我的日志中看起来像:
1.2.3.4 - - [12/Nov/2012:21:23:11 -0800] "GET /article/my-slug-name%3Fpage%3D2 HTTP/1.1" 1209 404 "-" "Mediapartners-Google
通常情况下,我只是忽略了一个破碎的机器人,但是这个我想要安抚,因为它应该更好地定位我们的广告(这是google adsense的机器人),从而带来更好的收入 - 如果它能看到我们的内容。谣言是它没有遵循重定向,所以我想找到一个类似于原始Q的解决方案。我不希望常规客户端通过这些破坏的URL访问页面,所以我检测到用户代理。其他应用程序可能不会这样做。
我同意重定向通常是正确的答案。
我的(完整?)解决方案:
from django.http import QueryDict
from django.core.urlresolvers import NoReverseMatch, resolve
class MediapartnersPatch(object):
def process_request(self, request):
# short-circuit asap
if request.META['HTTP_USER_AGENT'] != 'Mediapartners-Google':
return None
idx = request.path.find('?')
if idx == -1:
return None
oldpath = request.path
newpath = oldpath[0:idx]
try:
url = resolve(newpath)
except NoReverseMatch:
return None
request.path = newpath
request.GET = QueryDict(oldpath[idx+1:])
response = url.func(request, *url.args, **url.kwargs)
response['Link'] = '<%s>; rel="canonical"' % (oldpath,)
return response