在Django Rest框架中,您能否帮助建议如何保持编码风格的有序性,以保持端点与HTML和JSON的分离
在Flask中,我习惯于将用于服务Json的端点和用于服务HTML的端点分开,例如:
@application.route('/api/')
def api_root():
#...
return jsonify({'data' : data})
以及
@application.route('/home/<string:page>/', endpoint='page_template')
#...
return render_template(template, page)
所以我可以提供如下API:
/api/page => serve the json for the page, say for AJAX etc.
/page => serve the corresponding html page
在Django RF中,我读到ModelViewSet可以同时提供这两种服务
所以我可以把所有东西都放在一个地方
然而,当我在路由器上映射视图时,我会让所有端点都按照与我的模型相关的路径服务,它们都是/api
的子路径
您能否帮助建议一个好的编码实践来使用ModelViewSet,并为html路由与API分离的端点
这是我正在做的例子,我的疑问在评论中:
from rest_framework import viewsets
from rest_framework import generics
from rest_framework.decorators import action
from rest_framework.response import Response
from .serializers import PersonSerializer
from .models import Person
class PersonViewSet( viewsets.ModelViewSet):
queryset = Person.objects.all().order_by('name')
serializer_class = PersonSerializer
# this will return last person
# I can see it registered at: 127.0.0.1:8000/api/people/last_person/
@action(detail=False)
def last_person(self, request):
queryset = Person.objects.all().order_by('timestamp').reverse()[0]
serializer = self.get_serializer(queryset)
return Response(serializer.data)
# this will return a template:
# I can see it registered at: ../api/people/greetings : I wanted at /greetings
@action(detail=False)
def greetings(self, request):
queryset = Person.objects.all().order_by('timestamp').reverse()[0]
serializer = self.get_serializer(queryset)
return render(
request,
'myapi/greetings.html',
{
'person': serializer.data
}
)
另外,请注意我是如何为方法greetings
提供服务的:这里我重复queryset和serialising部分。我想做:
def greetings(self, request):
person = self.last_person(request)
return render(
request,
'myapi/greetings.html',
{
'person': person
}
)
但是它会给出错误,因为person
将是Response
对象,并且找不到将其传递给render
的方法
哪种编码风格可以避免重复,保持api和模板的分离
在/myapi/url.py
中,我注册了如下端点:
router = routers.DefaultRouter()
router.register(r'people', views.PersonViewSet)
app_name = 'myapi'
urlpatterns = [
path('', include(router.urls)),
]
在主url.py
中,如下所示:
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapi.urls')),
path('', include('myapi.urls')) # How to keep views for templates and for Json separated ??
]
如果响应阶段之前的所有内容都是相同的,则除了渲染器之外,不应触碰任何内容。您可以根据用户的请求选择正确的呈现器,精确地在媒体类型
Accept
头上,以所需的格式提供响应例如,假设您希望基于媒体类型(
Accept
头)发送JSON和HTML响应。因此,当您传递时(仅传递一种媒体类型以保持示例简单):Accept: application/json
它应该返回JSON中的responseAccept: text/html
它应该返回HTML响应在开始实施之前,让我们先讨论一下DRF如何处理呈现器:
呈现器可以在
settings.py
中全局地定义为DEFAULT_RENDERER_CLASSES
集合,或者在每个视图(从技术上讲,视图集是带有方法操作映射和关联逻辑的视图)的基础上定义为renderer_classes
类属性渲染器的顺序非常重要。DRF根据
Accept
值选择最具体的呈现器。对于更通用的one或catch all(*/*
),选择满足媒体类型的第一个呈现器如果使用DRF的
DefaultRouter
进行URL映射,还可以使用format
扩展来过滤掉任何不支持传递格式的呈现器。例如,如果有一个端点/foo/1/
,则可以添加类似/foo/1.json/
的格式。然后,只有将format = json
作为属性的呈现器类才会被选择(然后前面提到的最终选择将只在这些呈现器中发生)因此,基于上述内容,您需要从API使用者传递正确的
Accept
头,如果使用DefaultRouter
,那么最好添加format
扩展来对呈现器进行预过滤在API上,执行以下操作:
format
,请确保呈现器具有格式名称作为属性Response
(rest_framework.response.Response
)类,该类传递正确的呈现器上下文并调用呈现器的render
方法以发回正确的响应如果您想发送一个JSON响应,实际上可以利用
JSONRenderer
(rest_framework.renderers.JSONRenderer
)来实现这一目的。如果只想定制一些东西,可以创建自己的子类JSONRenderer
在发送HTTP响应的情况下,您可以从
TemplateHTMLRenderer
(rest_framework.renderers.TemplateHTMLRenderer
)中获得灵感,或者扩展它以满足您的需要。它有样板:序列化程序传入的数据已经可以作为模板上下文使用。因此,您可以设置上面的
template_name
(或者在重写时使用Response
传入),并在那里添加所有HTML表示。如果需要,您还可以重写render
以进行更多的定制最后,如果你想自己做一个定制的,the DRF doc is pretty awesome in explaining what you need to do
相关问题 更多 >
编程相关推荐