【问题标题】:Handling single page application url and django url处理单页应用程序 url 和 django url
【发布时间】:2017-08-09 10:21:17
【问题描述】:

我在 Vue.js 中创建了一个单页应用程序,它利用 HTML5 历史模式进行路由,并且 html 文件由 Django 提供。

django的urls.py是这样的:

urlpatterns = [
    url(r'^$', views.home),
    url(r'^admin/', admin.site.urls),
    url(r'^api-token-auth/', obtain_jwt_token),
]

还有views.home

def home(request):
    return render(request, 'index.html')

考虑以下场景:

  1. 用户访问主页(即/

由于主页响应了单页 Vuejs 应用所需的 index.html,因此它的工作方式与预期一样。

  1. 用户从那里导航到关于页面(即/username/12)。

它仍然可以正常工作,因为它使用 Vue 路由器导航。

  1. 现在,用户刷新页面。

由于 urls.py 模式中没有/username/12,它会显示Page not found (404)

现在,我可以在 urls.py 中提供另一个模式来捕获最后一个顺序中的所有模式,如下所示:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api-token-auth/', obtain_jwt_token),
    url(r'^.*$', views.home),
]

但媒体或静态 url 等其他 url 也将指向相同的 catch all pattern regex。我该如何解决这个问题?

【问题讨论】:

  • 包罗万象的 URL 是要走的路。这不会影响媒体或静态,因为 Django 在生产中不提供它们。

标签: django vue.js single-page-application vuejs2


【解决方案1】:

我也有类似的问题。

如何使用 vue-router 和 django rest 框架同时

这是我对这个问题的解决方案。希望对你有帮助。

预期结果:

http://127.0.0.1:8000/       <-- TeamplateView index.html using vue
http://127.0.0.1:8000/course <-- vue-router
http://127.0.0.1:8000/api    <-- rest framework
http://127.0.0.1:8000/admin  <-- django admin

我试试这个,效果很好!

urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^api/', include(router.urls)),
    url(r'^.*$', TemplateView.as_view(template_name="index.html")),
]

顺序很重要, url(r'^.*$', TemplateView.as_view(template_name="index.html")), 是最后一个

这是我的 vue 路由器

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [{
      path: '/courses',
      component: CourseSet
    }, {
      path: '/',
      component: hello
    }]
})

My project on GitHub

【讨论】:

  • 这不适用于 /admin(没有斜杠)。该路径将被 '^.*$' 捕获,并且斜杠不会附加中间件以检查 /admin/。它对您有用的原因可能是因为 http 缓存。所以消极的前瞻 (?!admin) 是唯一的选择
【解决方案2】:

既然你提到了“单页”:

  1. 服务器应该只提供一页index.html(或任何你想叫它的名字)。

  2. 服务器和 Web 应用程序(前端)代码将通过 api 调用进行通信,以便服务器提供资源,而 Web 应用程序负责使用该资源。

  3. 在缺少资源的情况下,服务器仍不得以单独的页面响应,它仍应以 Web 应用可以使用的消息进行响应。

我在 Vue.js 中创建了一个单页应用程序,它利用 HTML5 历史模式进行路由

我相信您正在使用vue-router,它将单页应用程序模拟为功能齐全的多页应用程序。


您可能想看看thisthis,但以上内容适用于单页应用程序。


你分享了你的 urlpatterns:

urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r'^api-token-auth/', obtain_jwt_token),
  url(r'^.*$', views.home),
]

但像媒体或静态 url 等其他 url 也将指向相同的 catch all 模式正则表达式。我该如何解决这个问题?

  1. 您可以通过在'/' 以外的路线上提供服务,就像上面提到的/app 一样。

    urlpatterns = [
      url(r'^admin/', admin.site.urls),
      url(r'^api-token-auth/', obtain_jwt_token),
      url(r'^.*$/app', views.home),
    ]
    

    在你的 router.js 文件中:

    new Router({
      mode: 'History',
      base: '/app'
      routes: [
        {
          path: '/',
          name: 'name',
          component: ComponentName
        }
      ]
    })
    
  2. 或为 URL 所服务的目的添加前缀,例如

    urlpatterns = [
      url(r'^api/admin/', admin.site.urls),
      url(r'^api/api-token-auth/', obtain_jwt_token),
      url(r'^.*$', views.home),
      url(r'^.*$/assets', your-static-assets) 
    ]
    

【讨论】:

  • your-static-assets 到底是什么?这是views.py 中的函数吗?
  • 干得好!我将选项号 1 更改为 url(r'^app/.*$', views.home),非常适合我。
【解决方案3】:

我通过这种方式在 Django 2.x 中使用 VueJS 路由器启用历史模式:

从 app urls.py 你需要repath 你的前端 url 像这样:

# urls.py

from django.urls import path, include
from django.urls import re_path

urlpatterns = [
    path('', TemplateView.as_view(template_name="application.html"), name="app", ),
    # ... rest of your urls
]

urlpatterns += [
    re_path('^.*$', TemplateView.as_view(template_name="application.html")),
]

现在历史模式运行顺利!

http://sample.com/#/users/login/

变成:

http://sample.com/users/login/

【讨论】:

    【解决方案4】:

    我通过使用负前瞻正则表达式解决了这个问题,所以基本上(?!ignore1|ignore2) 中的任何内容都将被忽略。

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api-token-auth/', obtain_jwt_token),
        url(r'^(?!admin|api-token-auth|static).*$', views.home),
    ]
    

    注意:我尝试在负前瞻中不包括 adminapi-token-auth,但这对我不起作用,它仍会将以 admin 开头的路径路由到 views.home,不确定为什么根据我的理解,django应该先匹配早期的。

    【讨论】:

      【解决方案5】:

      由于 index.html 是模板化的(一个动态页面),因为它是从您的视图而不是静态提供的,这变得有点奇怪。

      对于生产,绝对使用 nginx 或 apache 以类似的方式提供静态内容。

      对于开发,我会这样做:

      from django.contrib.staticfiles.views import serve
      
      urlpatterns = [
          url(r'^admin/', admin.site.urls),
          url(r'^api-token-auth/', obtain_jwt_token),
      ]
      
      # Serve your static media (regex matches *.*)
      if settings.DEBUG:
          urlpatterns.append(url(r'(?P<path>.*\..*)$', serve))
      
      # Serve your single page app in every other case
      urlpatterns.append(url(r'^.*$', views.home))
      

      【讨论】:

        【解决方案6】:

        @billi 上面提供的答案在一定程度上可以正常工作。我的问题是,对于我的 SPA,我希望(需要?)使用 Vue router-view> 和 router-link> 系统。但是 router.js 将路径映射到 Vue 组件,而我的一些路径是通过 Django urls.py 到 Django 视图 - 例如,如果从 Vue 路由器导航导航到 /api/places,这将导致空白页面,但是如果刷新,将正确解析为 Django。

        想法?

        urls.py

        urlpatterns = [
            # Django
            path('admin', admin.site.urls),
            url(r'^api-auth/', include('rest_framework.urls')),
            url(r'^api/places$', views.PlaceList.as_view()),
        
            # catchall to Vue single page app
            url(r'^.*$', TemplateView.as_view(template_name='myapp/spa.html'), name='home'),
        ]
        

        router.js

        export default new Router({
          mode: 'history',
          routes: [
            {path: '/search', component: Search},
            {path: '/about', component: About},
            {path: '/', component: Home},
            {path: '/api/places', }
          ]
        })
        

        App.vue

        <template>
          <div id="app">
            <div>
            <router-link to="/search">Search</router-link> ::
            <router-link to="/about">About</router-link>
            <router-link to="/">Home</router-link> ::
            <router-link to="/api/places">Place API</router-link> ::
          </div>
          <router-view></router-view>
          </div>
        </template>
        

        【讨论】:

        • 我遇到了同样的问题。你找到什么了吗?如果我将模板视图的 Django url 从 url 更改为 re_url,它似乎可以解决,但它会阻止文件上传功能正常工作。
        • 不,抱歉。停止尝试为该应用使用 Vue
        【解决方案7】:

        不知道是否还有人在寻找解决方案。 我完全以独立的方式构建 Django Rest API 和 Vue 前端。然后,当我尝试将 dist 文件夹项放在 Django 的静态文件中并尝试通过 gunicorn 和 NGINX 提供服务时,我只是无法让 spa 工作。 终于做到了,非常令人惊讶的是它的工作原理。

        基本上,

        将错误页面转发到 Vue 的 index.html

        这是我的 NGINX 配置:

        location /static/ {
            root /root/bdn/bdn/server/;
        }
        
        location /media/ {
            root /root/bdn/bdn/server/;
        }
        
        location ^~ /admin/ { # Define routes to be directed to backend as proxy
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://unix:/run/gunicorn.sock;
        }
        
        location ^~ /api/ { # Define routes to be directed to backend as proxy
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://unix:/run/gunicorn.sock;
        }
        
        location ^~ /api-auth/ {
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://unix:/run/gunicorn.sock;
        }
        
        location ^~ /{
            root /root/bdn/bdn/server/templates/;
            index index.html;
        }
        
        error_page 404 /;  # THIS IS WHAT IT CAME DOWN TO AFTER HOURS AND HOURS OF SEARCHING
        

        【讨论】:

          猜你喜欢
          • 2015-09-05
          • 1970-01-01
          • 2012-08-18
          • 2011-08-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-15
          • 1970-01-01
          相关资源
          最近更新 更多