如何在路由器上注册单个视图(不是视图集)?
Posted
技术标签:
【中文标题】如何在路由器上注册单个视图(不是视图集)?【英文标题】:How can I register a single view (not a viewset) on my router? 【发布时间】:2015-08-04 00:52:53 【问题描述】:我正在使用 Django REST 框架,并且一直在尝试创建一个返回少量信息的视图,并将其注册到我的路由器上。
我有四个存储信息的模型,它们都有一个created_time
字段。我正在尝试创建一个在单个视图中返回最新对象(基于created_time
)的视图,其中仅返回四个创建时间。
因此,视图中可能的 JSON 输出如下所示
"publish_updatetime": "2015.05.20 11:53",
"meeting_updatetime": "2015.05.20 11:32",
"training_updatetime": "2015.05.20 15:25",
"exhibiting_updatetime": "2015.05.19 16:23"
我还希望在我的路由器上注册此视图,以便在加载 API 根时它与我的其他端点一起出现。
router.register(r'updatetime', views.UpdateTimeView)
这是我正在尝试使用的四个模型
class Publish(models.Model):
user = models.ForeignKey(MyUser)
name = models.CharField(max_length=50)
created_time = models.DateTimeField( default=datetime.now)
class Meeting(models.Model):
user = models.ForeignKey(MyUser)
name = models.CharField(max_length=50)
file_addr = models.FileField(upload_to=get_file_path)
created_time = models.DateTimeField(default=datetime.now)
class Training(models.Model):
user = models.ForeignKey(MyUser)
name = models.CharField(max_length=50)
image = models.ImageField(upload_to=get_file_path, max_length=255)
created_time = models.DateTimeField(default=datetime.now)
class Exhibiting(models.Model):
user = models.ForeignKey(MyUser)
name = models.CharField(max_length=50)
file_addr = models.FileField(upload_to=get_file_path)
created_time = models.DateTimeField(default=datetime.now)
可以这样做吗?又是怎么做的?
【问题讨论】:
您是否有任何已编写的视图、序列化程序或模型可以包含在您的问题中?也不完全清楚您的主要问题是什么,因为这里没有太多工作可做。 嗨 Kevin,我已经添加了所有模型和序列化程序。如何使用视图集来处理此问题并使用“路由器”注册 url。谢谢! 目前还不清楚所有这些模型应该如何分组。显然不是created_time
(这将导致它们都相同)。应该如何检索这四个模型?通常如何在视图中完成?
只想返回这四个模型的最新创建时间。返回的 json 包括 4 个 tiems:publish_updatetime -> Publish.created_time、 meeting_updatetime -> Meeting.created_time、training_updatetime -> Training.created_time、exhibitioning_updatetime->Exhibiting.created_time。我们可以像这样获取最新的 created_time:Publish.objects.latest('created_time')。
完美,所有这些都是应该首先包含的信息。现在我意识到你的问题更接近于“我怎样才能有一个只返回列表方法的视图集”而不是“我怎样才能将多个模型聚合成一个响应”。
【参考方案1】:
路由器工作with a ViewSet
并且不是为普通视图设计的,但这并不意味着您不能在普通视图中使用它们。通常它们与模型(和ModelViewSet
)一起使用,但它们可以在没有它们的情况下使用GenericViewSet
(如果您通常使用GenericAPIView
)和ViewSet
(如果您只使用@987654327 @)。
对于列表视图,请求方法被映射到ViewSet
这样的方法
GET
-> list(self, request, format=None)
POST
- > create(self, request, format=None)
对于详细视图(url中带有主键),请求方法使用以下映射
GET
-> retrieve(self, request, pk, format=None)
PUT
-> update(self, request, pk, format=None)
PATCH
-> partial_update(self, request, pk, format=None)
DELETE
-> destroy(self, request, pk, format=None)
因此,如果您想在路由器上的视图中使用这些请求方法中的任何一种,则需要覆盖正确的视图方法(因此list()
而不是get()
)。
现在,特别是在您的情况下,您通常会使用看起来像的APIView
class UpdateTimeView(APIView):
def get(self, request, format=None):
latest_publish = Publish.objects.latest('created_time')
latest_meeting = Meeting.objects.latest('created_time')
latest_training = Training.objects.latest('created_time')
latest_exhibiting = Exhibiting.objects.latest('created_time')
return Response(
"publish_updatetime": latest_publish.created_time,
"meeting_updatetime": latest_meeting.created_time,
"training_updatetime": latest_training.created_time,
"exhibiting_updatetime": latest_exhibiting.created_time,
)
可比较的ViewSet
将是
class UpdateTimeViewSet(ViewSet):
def list(self, request, format=None):
latest_publish = Publish.objects.latest('created_time')
latest_meeting = Meeting.objects.latest('created_time')
latest_training = Training.objects.latest('created_time')
latest_exhibiting = Exhibiting.objects.latest('created_time')
return Response(
"publish_updatetime": latest_publish.created_time,
"meeting_updatetime": latest_meeting.created_time,
"training_updatetime": latest_training.created_time,
"exhibiting_updatetime": latest_exhibiting.created_time,
)
注意两个必需的更改:APIView
-> ViewSet
和 get
-> list
。我还更新了名称以表明它不仅仅是一个普通视图(因为 ViewSet
不能以相同的方式初始化),但这不是必需的。
因此,有了这个新视图,您可以像其他任何方式一样在路由器中注册它。你需要一个base_name
以便生成 url 名称(通常这会从查询集中提取)。
router.register(r'updatetime', views.UpdateTimeViewSet, base_name='updatetime')
所以现在updatetime
端点将在 API 根中可用,您只需调用端点(一个简单的 GET 请求)即可获取最新时间。
【讨论】:
所以无法在router
中注册APIView
?
我的情况是,我想公开几个不适用于具体资源(定义为 Django 模型)的 API,我还想将它们放入一个 ViewSet 并在下面公开它们一个特定的url前缀,如scheduler/get_job
、scheduler/report_result
等。您的解决方案如何适用于这种情况?
@ChenxiongQi 我有这个确切的问题-你找到答案了吗?
你可以在这些情况下使用@list_route
装饰器@dkhaupt @chenxiongqi
我还能这样解析更复杂的url吗,比如myurl/<int:a>/<int:b>
,或者routeur只能接受简单的字符串?【参考方案2】:
还有另一种方法:
urlpatterns = [
# ...
url(r'^you_path/', include(router.urls)),
url(r'^you_path/you_sub_path', views.UpdateTimeView.as_view()),
# ...
]
但是像 Swagger 这样的东西不能用它
【讨论】:
以上是关于如何在路由器上注册单个视图(不是视图集)?的主要内容,如果未能解决你的问题,请参考以下文章
Django REST framwork-06-使用 ViewSets 视图集和 Routers 路由
django rest框架中的泛型与视图集,如何选择使用哪一个?
python Django Rest_Framework框架 视图集与路由Routers详解(图文并茂版)