2014-12-04 57 views
3

我需要为我的应用中的所有网址使用动态网址前缀。具有动态前缀的Django URL

我熟悉做一个静态前缀,如url(r'^myprefix/app', include('app.urls'))

相反,我需要myprefix是动态的,如url(r'^(?P<prefix>\w+)/app', include('app.urls'))

这很有效,但这里是踢球者。我不希望将prefix作为关键字参数发送给所有视图。我希望能够捕获它并将其用于中间件或类似的东西。


为了说明我的具体用例,我们使用软件(这个Django项目)来管理各种测试实验室。该应用程序需要知道它在哪个实验室上运行。

目前,我用下面这样:

class LabMiddleware(object): 
    def process_request(self, request): 
     request.current_lab = 'lab1' # Note that this is currently hard coded 

要求指出,用户可以去一个URL,如http://host/<lab_name>/app其中lab_name随后将得到我的LabMiddleware使用。正因为如此,我显然不想接受lab_name在我的每一个观点,因为它是繁琐和矫枉过正。


UPDATE:

建立在什么Sohan给他的回答,我结束了使用自定义的中间件类:

urls.py

url(r'^(?P<lab_name>\w+)/', include('apps.urls')), 

apps/urls.py

url(r'^app1/', include('apps.app1.urls', namespace='app1')), 

middleware.py

class LabMiddleware(object): 
    def process_view(self, request, view_func, view_args, view_kwargs): 
     lab_name = view_kwargs.get('lab_name') 
     if lab_name: 
      request.current_lab = Lab.objects.get(name=lab_name) 
      # Remove the lab name from the kwargs before calling the view 
      view_kwargs.pop('lab_name') 
      return view_func(request, *view_args, **view_kwargs) 

settings.py

MIDDLEWARE_CLASSES = (
    # Default Django middleware classes here... 
    'raamp.middleware.LabMiddleware', 
) 

这让我在URL中有实验室名称,将其添加到该请求。然后通过从view_kwargs中删除它,它不会传递给视图函数,并且一切都按照我的意图工作。

另请注意,我上面的代码不是最优化的(例如,我正在为每个请求查询数据库)。我删除了用于缓存的代码,因为它不是显示如何解决此问题的重要信息,但值得一提的是,如果您在生产系统中使用此代码,则应对此代码进行一些改进。

+0

IMO接受另一种说法为所有的视图功能是不是大材小用,只有最低限度的繁琐。我认为如果视图参数直接匹配routes.py – 2014-12-04 21:29:41

+0

中的结构,你的应用将更易于维护和理解。问题是,对于每个单一视图函数,需要包含'lab_name'参数,则函数需要在每一个人都会被召唤来处理这些信息。对于大型应用程序(目前这是),这很麻烦并且容易出错,尤其是对于多个开发人员。最后,如果我不能以其他方式工作,那么这将是我将采取的实施,但我试图避免它。 – Jared 2014-12-04 21:34:52

+0

我看到了 - 实际上一个好的解决方案可能是使用装饰器来代替。你的装饰器可以处理和“吞下”lab_name' arg。让我写一个例子... – 2014-12-04 21:44:36

回答

2

您可以创建一个包装每个视图函数的装饰器。修饰器可以处理你在实验室名称参数上的任何处理工作,并且每个视图不需要看到lab_name参数。

def process_lab_name(request, lab_name): 
    request.current_lab = lab_name 

def lab(view_func): 
    def _decorator(request, lab_name, *args, **kwargs): 
     # process the lab_name argument 
     process_lab_name(request, lab_name) 
     # when calling the view function, exclude the lab_name argument 
     response = view_func(request, *args, **kwargs) 
     return response 
    return wraps(view_func)(_decorator) 

@lab 
def some_view(request): 
    return render(...) 

而且你的路线将像url(r'^(?P<lab_name>\w+)/app'

+0

谢谢你。它实际上引导我朝着相似的方向发展,而是使用定义process_view()的中间件类来有效地完成您在此处显示的内容。然后在关闭视图函数之前,从'kwargs'中删除'lab_name'。稍后我会使用我提供的特定解决方案更新我的文章,但我将您的答案标记为已接受,因为它确实解决了问题。谢谢! – Jared 2014-12-05 04:26:37