我在尝试使用django rest框架实现Web服务时遇到了一个奇怪的问题。我有这两个API-一个用于根据类别(作为URL参数提供)获取新闻列表,另一个用于在提供新闻ID(作为url参数提供)的情况下获取新闻的详细信息。以下是我的应用的urls.py
代码:
from django.urls import path
from rest_framework import routers
...
router = routers.DefaultRouter()
router.register('news_contents', NewsContentViewSet)
router.register('news_infos', NewsInfoViewSet)
router.register('categories', CategoryViewSet)
router.register(r'^articles/(?P<category_name>[-\w]+)', NewsItemViewSet, base_name="NewsInfo")
router.register(r'^articles/(?P<news_id>\d+)/details', NewsDetailViewSet, base_name="NewsInfo")
urlpatterns = router.urls
上面的调用代码: http://localhost:8000/rest/articles/categoryname 返回正确的输出,但调用: http://localhost:8000/rest/articles/4057/details/ 返回以下内容:
{"detail":"Not found."}
但是当我更改这两个API的注册顺序时,两个API都可以按预期工作。
工作urls.py
:
from django.urls import path
from rest_framework import routers
...
router = routers.DefaultRouter()
router.register('news_contents', NewsContentViewSet)
router.register('news_infos', NewsInfoViewSet)
router.register('categories', CategoryViewSet)
router.register(r'^articles/(?P<news_id>\d+)/details', NewsDetailViewSet, base_name="NewsInfo") #brought to above the listing API
router.register(r'^articles/(?P<category_name>[-\w]+)', NewsItemViewSet, base_name="NewsInfo")
urlpatterns = router.urls
为什么会这样?我感觉到,随着我添加更多API,无论其背后的原因是什么,都会使我陷入困境。
我在调试时注意到的另一件事是,我不想将许多其他端点自动列为可用端点:
Using the URLconf defined in restnews.urls, Django tried these URL patterns, in this order:
rest/ ^news_contents/$ [name='newscontent-list']
rest/ ^news_contents\.(?P<format>[a-z0-9]+)/?$ [name='newscontent-list']
rest/ ^news_contents/(?P<pk>[^/.]+)/$ [name='newscontent-detail']
rest/ ^news_contents/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='newscontent-detail']
rest/ ^news_infos/$ [name='newsinfo-list']
rest/ ^news_infos\.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-list']
rest/ ^news_infos/(?P<pk>[^/.]+)/$ [name='newsinfo-detail']
rest/ ^news_infos/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-detail']
rest/ ^^categories/$/$ [name='newsinfo-list']
rest/ ^^categories/$\.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-list']
rest/ ^^categories/$/(?P<pk>[^/.]+)/$ [name='newsinfo-detail']
rest/ ^^categories/$/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='newsinfo-detail']
rest/ ^^articles/(?P<news_id>\d+)/details/$ [name='NewsInfo-list']
rest/ ^^articles/(?P<news_id>\d+)/details\.(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-list']
rest/ ^^articles/(?P<news_id>\d+)/details/(?P<pk>[^/.]+)/$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<news_id>\d+)/details/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<category_name>[-\w]+)/$ [name='NewsInfo-list']
rest/ ^^articles/(?P<category_name>[-\w]+)\.(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-list']
rest/ ^^articles/(?P<category_name>[-\w]+)/(?P<pk>[^/.]+)/$ [name='NewsInfo-detail']
rest/ ^^articles/(?P<category_name>[-\w]+)/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='NewsInfo-detail']
rest/ ^$ [name='api-root']
rest/ ^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']
我只提供了5个端点,不需要所有其余端点,因此需要将其删除。这些问题是否以某种方式联系在一起?我该怎么解决?
答案 0 :(得分:1)
这是ModelViewset和DefaultRouter类的组合的行为方式。在DRF Doc中,它默认提供了一堆端点
如果您要进行CRUD
Operations,则非常方便。
根据您的描述,我了解到您不是在处理 CRUD
操作,因此无法使用DefaultRouter
和ModelViewset
。
因此,我建议您使用 rest_framework.views.APIView
类。
Example
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class MyViewClass(APIView):
def get(self, *args, **kwargs): # This fucntion will handle your "HTTP GET" requests
# put your logic here
return Response(data={"mymsg": "this is my response"})
def post(self, *args, **kwargs):
return Response("This is post method")
并在您的urls.py
from django.conf.urls import url
urlpatterns = [
url(r'mysample/', MyViewClass.as_view())
]
参考
1. DRF Router
2. DRF viewset
3. DRF APIview
UPDATE-1
阅读Django document
Django如何处理请求
当用户请求您的页面 由Django驱动的网站,这是系统遵循的算法 确定要执行的Python代码:
- Django确定要使用的根URLconf模块。通常,这是ROOT_URLCONF设置的值,但是如果传入 HttpRequest对象具有一个称为urlconf的属性(由中间件设置 请求处理),其值将代替 ROOT_URLCONF设置。
- Django加载该Python模块并查找变量urlpatterns。这应该是一个Python列表,格式为 函数django.conf.urls.patterns()。
- Django按顺序运行每个URL模式,并在与请求的URL匹配的第一个URL模式处停止。
- 一旦其中一个正则表达式匹配,Django就会导入并调用给定的视图,这是一个简单的Python函数。视图通过了 HttpRequest作为其第一个参数以及正则表达式中捕获的所有值 作为剩余的参数。
- 如果没有正则表达式匹配,或者在此过程中的任何时候引发异常,则Django都会调用相应的错误处理视图。 请参阅下面的错误处理。