【问题标题】:Match all urls without the prefix in Django匹配Django中所有不带前缀的url
【发布时间】:2016-04-16 02:30:52
【问题描述】:

我目前正在使用以下urls.py

api_patterns = [
    url(r'^users/', include('users.urls', namespace='user')),
]

internal_patterns = [
    # ...
]

urlpatterns = [
    url(r'^api/', include(api_patterns)),
    url(r'^internal/', include(internal_patterns)),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^(?!(?:api|internal|admin)/)', MainView.as_view()),
]

如果 url 没有 apiinternaladmin 前缀,则此配置的重点是呈现 MainView

  • /api/users/... — 找到
  • /api/foo/ — 未找到
  • /foo/ — 找到

我怎样才能使它更简单,更能揭示意图?

【问题讨论】:

    标签: python django django-urls


    【解决方案1】:

    对于 django >= 3 而不是使用 re_path

    from django.urls import re_path
    
    urlpatterns = [
        re_path(r'^.*',MainView.as_view())
    ]
    

    【讨论】:

      【解决方案2】:

      我认为如果你在两个网址中这样做,你的意图会更清楚:

      url(r'^(api|internal|admin)/', SomeView.as_view()),
      url(r'^.*', MainView.as_view())
      

      MainView 只会在 url 不以 api、internal 或 admin 开头时才会执行。

      SomeView 如果一个 url 以 api/internal/admin 开头但与上面的模式不匹配,将被执行。您可以自定义此视图以返回默认的 404 页面,或根据需要执行其他功能。

      使用你的例子:

      • /api/users 将执行 include(api_patterns)
      • /api/foo 将执行 SomeView
      • /foo 将执行 MainView

      编辑

      解决您评论中的第一点:网址模式是正则表达式,虽然您可以将它们提取到变量中以消除重复,但它会使代码难以阅读。这是删除重复的一个示例(我相信您可以提出其他示例):

      d = OrderedDict([
          (r'api', api_patterns),
          (r'internal', internal_patterns),
          (r'admin', admin.site.urls),
      ])
      
      main_view_re = r'^!({})/'.format('|'.join(d.keys()))
      
      urlpatterns = [url(r'^{}/'.format(k), include(v)) for k, v in d]
      urlpatterns.append(url(main_view_re, MainView.as_view()))
      

      【讨论】:

      • 首先,这并不能避免我重复apiinternaladmin 两次。其次,手动渲染 404 我丢失了那个漂亮的 django 错误页面,上面写着“我尝试了这个模式和那个模式”。
      • 我已经更新了答案,请看看它是否解决了您的问题。
      • 是的,我尝试过这样的事情,但你可以看到它比以前更加晦涩难懂:)(虽然确实删除了重复)
      • 此时,将 cmets 添加到您的代码中可能是最好的解决方案。我不确定是否可以在简化代码的同时删除代码重复。也许您可以尝试将更复杂的代码封装在一个函数中。尽管使用更新的解决方案,添加应该从 MainView 中排除的新 url 模式非常容易。
      • 是的,创建具有明确名称的函数将是一个很好的解决方案(比添加 cmets 好得多)。我只是想确保我不会错过阅读 URL 调度程序文档的明显内容。
      【解决方案3】:
      urlpatterns = [
          url(r'^api/', include(api_patterns)),
          url(r'^internal/', include(internal_patterns)),
          url(r'^admin/', include(admin.site.urls)),
          url(r'', MainView.as_view()),
      ]
      

      不保留前缀将允许您捕获用户在 URL conf 匹配 api、内部和管理 url 后可能尝试的任何 URL。

      【讨论】:

      • 但是/api/foo/ 会被发现,这不是我想要的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      • 2011-07-23
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      相关资源
      最近更新 更多