web-dev-qa-db-fra.com

Gestion de l'URL d'une seule page et Django url

J'ai une application d'une seule page créée dans Vue.js qui utilise le mode Historique HTML5 pour le routage, et le fichier html est servi avec Django.

rls.py de Django est comme ceci:

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

Et views.home:

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

Considérez le scénario suivant:

  1. L'utilisateur visite la page d'accueil (c'est-à-dire /)

Depuis, la page d'accueil répond avec index.html requis pour l'application Vuejs à page unique, elle fonctionne comme elle est censée le faire.

  1. De là, l'utilisateur accède à la page à propos (c'est-à-dire /username/12).

Son fonctionne toujours bien, comme sa navigation avec le routeur Vue.

  1. Maintenant, l'utilisateur rafraîchit la page.

Puisqu'il n'y a pas de /username/12 dans les modèles rls.py, il affichera Page non trouvée (404).

Maintenant, je pourrais fournir un autre modèle dans rls.py pour attraper tous les modèles dans le dernier ordre comme ceci:

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

Mais d'autres URL comme les médias ou les URL statiques pointeront également vers la même capture toutes les expressions régulières de modèle . Comment puis-je résoudre ce problème?

19
Robin

J'ai le même problème.

Comment utiliser en même temps vue-router et Django rest framework ?

Ceci est ma solution à ce problème. J'espère que cela vous aide.

Résultats attendus:

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

et j'essaye ça et ça marche!

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")),
]

L'ordre est important, url(r'^.*$', TemplateView.as_view(template_name="index.html")), est le dernier

et c'est mon vue routeur

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

Mon projet sur GitHub

17
Bllli

Puisque vous avez mentionné "une seule page":

  1. Le serveur est censé servir une seule page le index.html (ou comme vous voudriez l'appeler autrement).

  2. Le serveur et le code de l'application Web (frontal) communiqueraient via des appels API, de sorte que le serveur fournit des ressources et que l'application Web se charge d'utiliser cette ressource.

  3. En cas de ressource manquante, le serveur ne doit toujours pas répondre avec une page séparée, il doit quand même répondre avec un message que l'application web peut utiliser.

J'ai une application d'une seule page créée dans Vue.js qui utilise le mode Historique HTML5 pour le routage

Je pense que vous utilisez vue-router , qui simule l'application d'une seule page pour être une application multi-page complète.


Vous voudrez peut-être jeter un œil à this et this , mais ce qui précède est vrai pour une application d'une seule page.


Vous avez partagé vos motifs d'URL:

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

Mais d'autres URL comme les médias ou les URL statiques pointeront également vers le même catch regex de motif. Comment puis-je résoudre ce problème?

  1. Vous pouvez gérer cela en utilisant une route autre que '/' comme mentionné ci-dessus pour /app.

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

    et dans votre fichier router.js:

    new Router({
      mode: 'History',
      base: '/app'
      routes: [
        {
          path: '/',
          name: 'name',
          component: ComponentName
        }
      ]
    })
    
  2. Ou préfixer le but servi par les URL comme

    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) 
    ]
    
4
Amresh Venugopal

Étant donné que index.html est basé sur un modèle (une page dynamique) car il est servi à partir de vos vues au lieu de statique, cela devient un peu bizarre.

Pour la production, utilisez certainement nginx ou Apache pour servir le contenu statique d'une manière similaire.

Pour le développement, voici ce que je ferais:

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))
0
Kenneth

J'ai résolu le problème en utilisant l'expression rationnelle négative, donc essentiellement tout ce qui se trouve à l'intérieur (?!ignore1|ignore2) sera ignoré.

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

Remarque: J'ai essayé de ne pas inclure admin et api-token-auth à l'intérieur de l'anticipation négative et cela n'a pas fonctionné pour moi, il acheminera toujours le chemin commençant par admin vers views.home, je ne sais pas pourquoi, selon ma compréhension, Django devrait d'abord correspondre aux précédents.

0
harinsa

La réponse fournie ci-dessus par @billi fonctionne très bien, jusqu'à un certain point. Mon problème est que pour mon SPA, je veux (besoin?) D'utiliser la vue de routeur Vue <> et < router-link > system. Mais le router.js mappe les chemins vers les composants Vue, et certains de mes chemins sont à Django vues via Django urls.py - par exemple, cela se traduira par une page vierge si vous accédez à/api/places à partir du Vue nav du routeur, mais se résoudra correctement en un Django si actualisé.

Des idées?

rls.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>
0
kgeo