【问题标题】:django rest API route showing same api link for all end pointdjango rest API 路由显示所有端点的相同 api 链接
【发布时间】:2016-03-07 15:54:07
【问题描述】:

我创建了一个小型任务应用程序并定义了一些终点,例如所有任务、到期任务、已完成任务。

这是我的 url.py

#Define API Routes
router = routers.DefaultRouter()
#router = routers.SimpleRouter()
router.register(r'task', views.TaskViewSet)
router.register(r'due_task', views.DueTaskViewSet)
router.register(r'completed_task', views.CompletedTaskViewSet)

urlpatterns = [
    # Examples:
    # url(r'^$', 'TaskAPI.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),
    url(r'^',include(router.urls)),
    url(r'^admin/', include(admin.site.urls)),
]

序列化器.py

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model =  Task
        fields = ('id','task_name','task_desc','completed','date_created')

查看.py

class TaskViewSet(viewsets.ModelViewSet):

    queryset = Task.objects.all().order_by('-date_created')
    serializer_class = TaskSerializer

class DueTaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all().order_by('-date_created').filter(completed=False)
    serializer_class = TaskSerializer

class CompletedTaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all().order_by('-date_created').filter(completed=True)
    serializer_class = TaskSerializer

模型.py

class Task(models.Model):
    task_name = models.CharField(max_length=20)
    task_desc = models.TextField(max_length=200)
    completed = models.BooleanField(default=False)
    date_created = models.DateTimeField(auto_now=True)

当我运行服务器并点击 127.0.0.1:8080 API 路由窗口将打开,所有端点都指向同一个链接。

请提出这里出了什么问题。 谢谢

【问题讨论】:

  • 查看您的序列化程序代码会很有帮助。我将假设您的taskdue_taskcompleted_task 是关系。如果是这种情况,DRF 默认使用HyperlinkedRelatedField
  • @themanatuf:我已经更新了我的代码。请调查一下。谢谢
  • 嗯...我不能 100% 确定 DRF 在幕后是如何工作的,但我的猜测是,由于您使用相同的序列化程序定义了三个视图,因此 DRF 正在使用最后一个。也许尝试过滤一个视图集而不是三个:django-rest-framework.org/api-guide/filtering
  • @themanatuf:谢谢,但是在 DRF 中不可能使用具有不同视图的相同序列化程序吗?

标签: django django-rest-framework


【解决方案1】:

您可能需要在register() 方法中指定可选的base_name 参数。它通常是自动生成的。但是,相同的序列化程序和相对相似的查询集可能是您获得相同端点的原因。我想你想要这样的东西。

router.register(r'task', views.TaskViewSet, 'task')
router.register(r'due_task', views.DueTaskViewSet, 'due_task')
router.register(r'completed_task', views.CompletedTaskViewSet, 'completed_task')

根据docs

如果未设置,基本名称将根据视图集的queryset 属性自动生成(如果有的话)。请注意,如果视图集不包含queryset 属性,则您必须在注册视图集时设置base_name

【讨论】:

    【解决方案2】:

    您确实在混淆 DRF。也许它应该能够处理你的情况,但它不能。

    我会将所有三个 viewsets 合并为一个 viewset 并使用可选过滤器:

    from rest_framework import filters
    
    class TaskViewSet(viewsets.ModelViewSet):
    
        queryset = Task.objects.all()
        serializer_class = TaskSerializer
        filter_fields = ('completed',)
        ordering = ('-date_created',)
    
        filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter,)
    

    然后,使用completed 参数进行条件查询:

    /completed_task/
    /completed_task/?completed=True
    /completed_task/?completed=False
    

    【讨论】:

    • - 感谢您的解决方案,我同意您的看法。但是是否可以对不同的视图集使用相同的序列化程序。如果我想在没有查询参数的情况下创建不同的端点,那么该怎么做。
    • 我不知道该怎么做。我曾经尝试过这样做。我设置了一个断点并开始沿着兔子洞走下去。无论如何,我放弃了,所以我不知道如何做到这一点。您可能需要进入router.register 代码库,以了解如何让 DRF 完成完全您所要求的操作。同时:过滤器! :-)
    • 这似乎归结为 DRF 中的路由器实现。目前,简单路由器和默认路由器都使用小写型号名称作为注册路由queryset.model._meta.object_name.lower() 的唯一标识符。如果你真的想避免过滤器并按照你想要的方式去做,你可能想要继承默认路由器并覆盖 get_default_base_name()。详细看SimpleRouter和BaseRouter的实现代码,比较容易阅读。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 2022-07-11
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多