首页 > 解决方案 > ViewSet 和额外的检索 URL

问题描述

我有一个Donation作为 ViewSet 公开的 django 模型。现在我想向第二个模型添加一个额外的 URL,在该模型中,可以通过参数检索Shop相关实例,并且可以执行自定义操作。Donationorder_id

# models.py
class Donation(models.Model):
  id = models.AutoField(primary_key=True)
  order_id = models.StringField(help_text='Only unique in combination with field `origin`')
  origin = models.ForeignKey('Shop', on_delete=models.PROTECT)

class Shop(models.Model):
  id = models.AutoField(primary_key=True)
  

# views.py
class DonationViewSet(mixins.CreateModelMixin,
                     mixins.RetrieveModelMixin,
                     mixins.ListModelMixin,
                     viewsets.GenericViewSet):

  def retrieve(self, request, *args, **kwargs):  
    if kwargs['pk'].isdigit():
      return super(DonationViewSet, self).retrieve(request, *args, **kwargs)
    else:
      shop_id = self.request.query_params.get('shop_id', None)
      order_id = self.request.query_params.get('order_id', None)
      
      if shop_id is not None and order_id is not None:
        instance = Donations.objects.filter(origin=shop_id, order_id=order_id).first()
        if instance is None:
          return Response(status=status.HTTP_404_NOT_FOUND)
        
        return Response(self.get_serializer(instance).data)

      return Response(status=status.HTTP_404_NOT_FOUND)

  @action(methods=['post'], detail=True)
  def custom_action(self, request, *args, **kwargs):
      pass

class ShopViewSet(viewsets.ModelViewSet):
  pass

# urls.py
router = routers.DefaultRouter()

router.register(r'donations', DonationViewSet)
router.register(r'shops', ShopViewSet)
router.register(r'shops/(?P<shop_id>[0-9]+)/donations/(?P<order_id>[0-9]+)', DonationViewSet)

我的目标是让 http://localhost:8000/donations 指向整个 DonationViewSet。我还想查找个人捐赠,通过它的组合shop_idorder_id类似 http://localhost:8000/shops/123/donations/1337/ 并执行自定义操作,如 http://localhost:8000/shops /123/donations/1337/custom_action/。我遇到的问题是第二个 url 返回整个查询集,而不仅仅是模型的单个实例。

标签: pythondjangorestdjango-rest-framework

解决方案


您还可以使用drf-nested-routers,它将具有以下内容:

from rest_framework_nested import routers

from django.conf.urls import url

# urls.py
router = routers.SimpleRouter()
router.register(r'donations', DonationViewSet, basename='donations')
router.register(r'shops', ShopViewSet, basename='shops')

shop_donations_router = routers.NestedSimpleRouter(router, r'', lookup='shops')
shop_donations_router.register(
    r'donations', ShopViewSet, basename='shop-donations'
)

# views.py
class ShopViewSet(viewsets.ModelViewSet):
    def retrieve(self, request, pk=None, donations_pk=None):
        # pk for shops, donations_pk for donations

    @action(detail=True, methods=['PUT'])
    def custom_action(self, request, pk=None, donations_pk=None):
        # pk for shops, donations_pk for donations

这个没有测试!但除了你已经拥有的,这将支持:

donations/
donations/1337/
shops/123/donations/1337/
shops/123/donations/1337/custom_action

推荐阅读