如何在路由器上注册单个视图(不是视图集)?

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 -> ViewSetget -> 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_jobscheduler/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 路由

drf-视图集路由系统action装饰器

django rest框架中的泛型与视图集,如何选择使用哪一个?

python Django Rest_Framework框架 视图集与路由Routers详解(图文并茂版)

python Django Rest_Framework框架 视图集与路由Routers详解(图文并茂版)

python Django Rest_Framework框架 视图集与路由Routers详解(图文并茂版)