Python 从单个视图到不同端点的方法:将HTML和JSON的API分开(Django Rest框架)
在Django Rest框架中,您能否帮助建议如何保持编码风格的组织,以使端点与HTML和JSON分开 在Flask中,我习惯于将用于服务Json的端点和用于服务HTML的端点分开,如:Python 从单个视图到不同端点的方法:将HTML和JSON的API分开(Django Rest框架),python,django,api,templates,django-rest-framework,Python,Django,Api,Templates,Django Rest Framework,在Django Rest框架中,您能否帮助建议如何保持编码风格的组织,以使端点与HTML和JSON分开 在Flask中,我习惯于将用于服务Json的端点和用于服务HTML的端点分开,如: @application.route('/api/') def api_root(): #... return jsonify({'data' : data}) 及 在Django RF中,我了解到ModelViewSet可以同时提供这两种功能 所以我可以把所有的东西都放在一个地方 然而,当我
@application.route('/api/')
def api_root():
#...
return jsonify({'data' : data})
及
在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
}
)
另外,请注意我是如何提供方法问候语的
:这里我重复了queryset和serialising部分。我想做:
def greetings(self, request):
person = self.last_person(request)
return render(
request,
'myapi/greetings.html',
{
'person': person
}
)
但是它会给出错误,因为person
将是响应
对象,并且无法找到将其传递给渲染
的方法
哪种编码风格可以避免复制,并保持API和模板的分离
在/myapi/url.py
中,我注册了以下端点:
router = routers.DefaultRouter()
router.register(r'people', views.PersonViewSet)
app_name = 'myapi'
urlpatterns = [
path('', include(router.urls)),
]
在mainurl.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
header)发送JSON和HTML响应。因此,当您传递(仅传递一种媒体类型以保持示例的简单性)时:
它应该返回json格式的响应Accept:application/json
它应该返回html响应Accept:text/html
- 渲染器可以在
集合中全局定义为settings.py
集合,也可以基于每个视图(从技术上讲,视图集是具有方法动作映射和关联逻辑的视图)定义为DEFAULT\u RENDERER\u CLASSES
类属性RENDERER\u CLASSES
- 渲染器的顺序非常重要。DRF根据
值选择最具体的渲染器。对于更通用的一个或全部捕获(Accept
),将选择满足媒体类型的第一个渲染器*/*
- 如果使用DRF的
进行URL映射,还可以使用DefaultRouter
扩展来过滤掉任何不支持传递格式的呈现器。例如,如果您有一个端点format
,则可以添加类似/foo/1/
的格式。然后,将只选择属性为/foo/1.json/
的渲染器类(然后,前面提到的最终选择将仅在这些渲染器中进行)format=json
Accept
头,如果使用DefaultRouter
,最好添加格式
扩展来对渲染器进行预过滤
在API上,执行以下操作:
- 按照前面提到的正确顺序定义渲染器类
- 如果使用者传递了
,请确保渲染器具有格式名称作为属性格式
- 如果您自己发送响应,请确保使用
(response
)类,该类传递正确的渲染器上下文,并调用渲染器的rest\u framework.response.response
方法以发回正确的响应render
JSONRenderer
(rest\u framework.renderers.JSONRenderer
)来实现这一目的。如果只想定制一些东西,可以创建自己的子类化JSONRenderer
在发送HTTP响应的情况下,您可以从templatehtmlender
(rest\u framework.renders.templatehtmlender
)中获得灵感,或者扩展它以满足您的需要。它有一个样板:
media_type = 'text/html'
format = 'html'
template_name = None
exception_template_names = [
'%(status_code)s.html',
'api_exception.html'
]
charset = 'utf-8'
序列化程序传入的数据已经作为模板上下文可用。因此,您可以在上面设置template\u name
(或者在覆盖时使用Response
传入),并在那里添加所有HTML表示。如果需要,还可以覆盖渲染
,以便在那里进行更多自定义
最后,如果你想自己做一个定制的 嗨@heemayl,很抱歉没有早点回来,我在最后期限内:|。我想再次感谢你的回答和清晰,你擅长解释事情!我感觉到了同理心,这对我来说是一件非常重要的事情,尤其是当我把人际关系“虚拟化”时,而不是经常看到笔记本电脑的同一个“视域”。。啊哈……)我看了你的个人资料:恭喜你!(p.s.YNWA+PinkFloyed真是太棒了)| | |/@user305883非常感谢你的客气话,这意味着很多!YNWA和PF——是的:)
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 ??
]
media_type = 'text/html'
format = 'html'
template_name = None
exception_template_names = [
'%(status_code)s.html',
'api_exception.html'
]
charset = 'utf-8'