2010-11-22 73 views
4

我试图建立一个URL别名应用程序,它允许用户在他的网站上为现有的网址创建别名。Django:创建/修改请求对象

我试图通过中间件,其中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请求处理的知识还太未开发以评估这一点。

+1

重定向更好,不仅因为它们更容易维护的代码,而且 - 他们让你为每个页面唯一的URL。这可能对您的搜索排名更好。 – Evgeny 2010-11-22 18:10:07

+0

这可以通过阻止机器人直接访问别名的url来绕过吗? – 2010-11-24 13:47:03

回答

4

而不是你采取的方法,你有没有考虑过Redirects应用程序?

这不是无形的别名路径/富/返回查看栏(),但它会重定向/富/到/酒吧/

+0

感谢stevejalim的建议。然而,看不见的锯齿正是我所期望的。 关于请求,我错误地认为请求对象是不可变的(因为QueryDicts是)。可以添加请求的en修改属性,包括request.path,request.path_info等。尚未测试我的到期代码,但会在完成时发布结果作为答案。 – 2010-11-22 23:06:55

+0

很高兴你找到了一个你很满意的解决方案,Izz,但是我的直觉是,当你走的时候改变请求对象的路径会导致更多的痛苦 - 尤其是在调试/维护方面。是否可以为现有的Django URL设置新路径(如果需要,可能需要为contrib应用程序添加新的自定义urlconf)? – 2010-11-23 10:17:31

1

(张贴的答案,因为评论似乎将不支持换行符或其他标记)

感谢您的建议,我有同样的感觉修改请求属性。 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_routedROUTED_TO(而不是路由)部分?

依赖于原始路径的代码可以使用META中的密钥。

使用URLConfs这样做是不可能的,因为这种别名的目的是使最终用户能够配置他自己的URL,假设最终用户无法访问代码库或不知道如何写他自己的URLConf。

尽管可以编写一个将用户可读可编辑文件(例如XML)转换为有效的Django URL的函数,但感觉使用数据库记录可以更动态地生成别名(其他对象定义它们自己的别名)。

1

对不起,necro-post,但我只是找到这个线程,同时寻找答案。我的解决方案似乎更简单。也许a)我依赖于更新的django功能或b)我错过了一个陷阱。

我遇到过这个问题,因为有一个名为“Mediapartners-Google”的机器人,它要求页面的url参数仍然是从天真的刮板编码(或者根据你如何看它的方式进行双重编码)。我有它在我的日志404看起来像:

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 

一般情况下我只是忽略了一个破碎的机器人,但是这一次我想安抚,因为它应该更有针对性地提供广告(这是谷歌的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