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

fly*_*ure 46 python django django-rest-framework

我正在使用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"
}
Run Code Online (Sandbox Code Playgroud)

我也希望在我的路由器上注册这个视图,因此当加载API根时,它会显示在我的其他端点上.

router.register(r'updatetime', views.UpdateTimeView)
Run Code Online (Sandbox Code Playgroud)

以下是我尝试使用的四种型号

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)
Run Code Online (Sandbox Code Playgroud)

是否有可能做到这一点?它将如何完成?

Kev*_*own 59

路由器使用aViewSet而不是为普通视图设计,但这并不意味着您不能在普通视图中使用它们.通常它们与模型(和a ModelViewSet)一起使用,但它们可以在没有它们的情况下使用GenericViewSet(如果你通常使用的话GenericAPIView)和ViewSet(如果你只是使用它APIView).

对于列表视图,请求方法映射到这样的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,
        })
Run Code Online (Sandbox Code Playgroud)

可比较的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,
        })
Run Code Online (Sandbox Code Playgroud)

请注意两个必需的更改:APIView- > ViewSetget- > list.我还更新了名称,表明它不仅仅是一个普通的视图(因为ViewSet不能以相同的方式初始化),但这不是必需的.

因此,使用这个新视图,您可以像在任何其他方式一样在路由器中注册它.你需要一个base_name这里,所以可以生成url名称(通常这将从查询集中提取).

router.register(r'updatetime', views.UpdateTimeViewSet, base_name='updatetime')
Run Code Online (Sandbox Code Playgroud)

因此,现在updatetime端点将在API根目录中可用,您可以通过调用端点(简单的GET请求)来获取最新时间.

  • 我的情况是,我想公开几个不能用于具体资源的API(定义为Django模型),我还想将它们放到一个ViewSet中并在特定的url前缀下公开它们,例如` scheduler/get_job`,`scheduler/report_result`等.您的解决方案如何适用于此案例? (4认同)
  • 所以不可能在`router`中注册`APIView`? (2认同)
  • 只是想注意,您应该使用“fromrest_framework importviewsets.ViewSet”才能使用它。 (2认同)