问题
I have a single page application created in Vue.js that utilizes the HTML5 History Mode for routing, and the html file is served with Django.
The urls.py of django is like so:
urlpatterns = [
url(r'^$', views.home),
url(r'^admin/', admin.site.urls),
url(r'^api-token-auth/', obtain_jwt_token),
]
And views.home:
def home(request):
return render(request, 'index.html')
Consider the following scenario:
- User visits the home page (i.e.,
/)
Since, the home page responds with required index.html for the Single page Vuejs app, it works like its supposed to.
- From there the user navigates to the about page (i.e.,
/username/12).
Its still working fine, as its navigating with the Vue router.
- Now, the user refreshes the page.
Since there's no /username/12 in the urls.py patterns, it will show Page not found (404).
Now, I could provide another pattern in urls.py to catch all pattern in the last order as this:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^.*$', views.home),
]
But other urls like the media or static urls will also point to the same catch all pattern regex. How can I solve this problem?
回答1:
I have a similar problem.
How can I use vue-router and django rest framework the same time?
This is my solution to this problem. Hope it helps you.
Expected results:
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
and I try this and it works!
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")),
]
The order is important,
url(r'^.*$', TemplateView.as_view(template_name="index.html")),is the last one
and this is my vue router
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [{
path: '/courses',
component: CourseSet
}, {
path: '/',
component: hello
}]
})
My project on GitHub
回答2:
Since you have mentioned "single page":
The server is supposed to serve just one page the
index.html(or whatever else you would like to call it).The server and the web application (front-end) code would communicate via api calls, such that the server provides resources and the web-app takes care of using that resource.
In case of a missing resource, the server still must not respond with a separate page, it should still respond with a message that the web-app can use.
I have a single page application created in Vue.js that utilizes the HTML5 History Mode for routing
I believe you are using vue-router, which simulates the single-page app to be a full-featured, multi-page application.
You may want to take a look at this and this, but the above holds true for a single page application.
You shared your urlpatterns:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^.*$', views.home),
]
But other urls like the media or static urls will also point to the same catch all pattern regex. How can I solve this problem?
A way you can manage that would be either by, serving on a route other than
'/'like mentioned above for/app.urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api-token-auth/', obtain_jwt_token), url(r'^.*$/app', views.home), ]and in your router.js file:
new Router({ mode: 'History', base: '/app' routes: [ { path: '/', name: 'name', component: ComponentName } ] })Or prefixing the purpose served by the urls like
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) ]
回答3:
Since index.html is templated (a dynamic page) because it's served from your views instead of static, this becomes a bit weird.
For production, definitely use nginx or apache to serve the static content in a similar fashion.
For development, this is what I would do:
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))
回答4:
The answer provided above by @billi works fine, up to a point. My problem is that for my SPA I want (need?) to use the Vue <router-view> and <router-link> system. But the router.js maps paths to Vue components, and some of my paths are to Django views via Django urls.py - for example, this will result in a blank page if navigating to /api/places from the Vue router nav, but will resolve correctly to a Django if refreshed.
Ideas?
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>
回答5:
I solved the issue by using the negative look-ahead regex, so basically anything inside (?!ignore1|ignore2) will be ignored.
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^(?!admin|api-token-auth|static).*$', views.home),
]
Note: I tried not including admin and api-token-auth inside the negative look-ahead and it didn't work for me, it will still route path that starts with admin to the views.home, not sure why as according to my understanding, django should match the earlier ones first.
回答6:
I'm using VueJS router enabled history mode with Django 2.x by this way:
From app urls.py you need to repath your frontend url like this:
# 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")),
]
Now history mode working smoothly!
http://sample.com/#/users/login/
Become:
http://sample.com/users/login/
来源:https://stackoverflow.com/questions/42864641/handling-single-page-application-url-and-django-url