【问题标题】:Django URL with dynamic prefix带有动态前缀的 Django URL
【发布时间】:2014-12-04 19:54:50
【问题描述】:

我需要为我的应用中的所有 URL 设置一个动态 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

要求规定用户能够访问诸如http://host/<lab_name>/app 之类的URL,然后lab_name 将在我的LabMiddleware 中使用。正因为如此,我显然不想在我的每一个观点中都接受lab_name,因为它既麻烦又矫枉过正。


更新:

基于 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 中删除它,它不会传递给视图函数,并且一切都按我的预期工作。

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

【问题讨论】:

  • IMO 在您的所有视图函数中接受另一个参数并不过分,而且只是非常麻烦。我认为如果视图参数直接匹配 routes.py 中的结构,你的应用会更容易维护和理解
  • 问题在于,对于每个视图函数,都需要包含一个lab_name 参数,然后需要在每个视图函数中调用一个函数来处理该信息。对于大型应用程序(目前是这样),这很麻烦且容易出错,尤其是对于多个开发人员。最后,如果我不能让它以任何其他方式工作,那么这将是我将采取的实现,但我试图避免它。
  • 啊,我明白了——实际上一个好的解决方案可能是使用装饰器。您的装饰器可以处理和“吞下”lab_name 参数。让我写一个例子......

标签: python django


【解决方案1】:

您可以创建一个包装每个视图函数的装饰器。装饰器可以处理您对实验室名称参数的任何处理工作,并且每个视图都不需要看到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&lt;lab_name&gt;\w+)/app'

【讨论】:

  • 谢谢。它实际上将我引向了类似的方向,而是使用定义 process_view() 的中间件类来有效地执行您在此处显示的操作。然后我从kwargs 中删除lab_name,然后再调用视图函数。稍后我将使用我使用的特定解决方案更新我的帖子,但我将您的答案标记为已接受,因为它确实解决了问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-24
  • 2013-11-07
  • 1970-01-01
  • 2016-04-16
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
相关资源
最近更新 更多