In Django, how do you keep a module's url conf

2019-07-23 16:20发布

问题:

Currently, I import url configurations into my Django project with:

from django.conf.urls import include
from django.contrib import admin
from django.urls import path, re_path
from rest_framework import routers
from greeter.views import GreeterViewSet

ROUTER = routers.DefaultRouter()
ROUTER.register(r'greeters', GreeterViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^', include(ROUTER.urls)),
]

Is there a way where I can move these parts of the code:

ROUTER = routers.DefaultRouter()
ROUTER.register(r'greeters', GreeterViewSet)

into a separate file in greeter/urls.py?

And still keep these URLs:

  • GET /greeter/ to fetch list of greeters
  • POST /greeter/ to create a new greeter

I have tried:

my_project/urls.py

from django.conf.urls import include
from django.contrib import admin
from django.urls import path, re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^greeters/', include('greeter.urls')),
]

greeter/urls.py

from django.conf.urls import url, include
from rest_framework import routers
from .views import GreeterViewSet

ROUTER = routers.DefaultRouter()
ROUTER.register(r'^', GreeterViewSet)

urlpatterns = [
    url(r'^', include(ROUTER.urls)),
]

But got:

$ curl -H 'Accept: application/vnd.api+json; indent=2' -X POST http://localhost:8000/greeters/
{
  "errors": [
    {
      "detail": "Method \"POST\" not allowed.",
      "source": {
        "pointer": "/data"
      },
      "status": "405"
    }
  ]
}

In case it helps, here is my original question that has been resolved: Method "POST" not allowed with Django Rest Framework

Update:

With the help of the answers, I was able to arrive at this solution:

my_project/urls.py

from django.conf.urls import include
from django.contrib import admin
from django.urls import re_path

urlpatterns = [
    re_path('admin/', admin.site.urls),
    re_path('greeters/', include('greeter.urls')),
]

greeter/urls.py

from django.conf.urls import include
from django.urls import re_path
from rest_framework import routers
from .views import GreeterViewSet

ROUTER = routers.DefaultRouter()
ROUTER.register(r'', GreeterViewSet)

urlpatterns = [
    re_path(r'', include(ROUTER.urls)),
]

With this:

  • all of the greeter url configuration is kept inside of the greeter module
  • the project url configuration ties 'greeter' resource to the greeter module
  • it seems like additional greeter views can be added to the greeter url configuration (I haven't tested this)

I think this is as good as I can get it. Thanks again for all of the help :)

回答1:

As I said to you before, the Router needs a prefix. You need to remove that prefix from your main URLs and use it in the router itself.

main:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('greeter.urls')),
]

app:

ROUTER = routers.DefaultRouter()
ROUTER.register(r'^greeter/', GreeterViewSet)

urlpatterns = ROUTER.urls

(Since you don't have any URLs other than the router ones, you don't need to use include there, you can just use the router urls directly.)

Also note, this whole thing is almost certainly not what you want to do; it means you can never have any URLs other than those for your viewset.



回答2:

Removing the ^ (the Caret symbol) from regex expression will do the job

# greeter/urls.py
# your code

urlpatterns = [
    url(r'', include(ROUTER.urls)),
]