Python 使用Django REST框架定义过滤端点的更好方法

Python 使用Django REST框架定义过滤端点的更好方法,python,django,django-rest-framework,Python,Django,Django Rest Framework,我在用户和图像之间建立了一种关系,每个用户都可以有多个图像。我需要定义一个端点来检索特定用户的所有图像: GET/users/:id/images 我是这样做的: url.py router = routers.DefaultRouter() router.register(r'images', ImageViewSet) image_list = ImageViewSet.as_view({ 'get': 'list' }) urlpatterns = patterns('',

我在用户和图像之间建立了一种关系,每个用户都可以有多个图像。我需要定义一个端点来检索特定用户的所有图像:

GET/users/:id/images

我是这样做的:

url.py

router = routers.DefaultRouter()
router.register(r'images', ImageViewSet)

image_list = ImageViewSet.as_view({
    'get': 'list'
})

urlpatterns = patterns('',
    ...
    url(r'^', include(router.urls)),
    url(r'^users/(?P<user_id>[^/]+)/images/$', image_list),
    ...
)
class ImageViewSet(viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer

    def get_queryset(self):
        user_id = self.kwargs.get('user_id', None)
        if user_id:
            return Image.objects.filter(user_id=user_id)
        return super(ImageViewSet, self).get_queryset()

它很管用,但我不满意。想象一些类似于
/users/:user\u id/images/
的附加端点,即类似于
/categories/:categories\u id/images/
等的端点。将
获取查询集作为这两个端点的入口点,让它基于
夸尔格来区分它们,似乎不是很吸引人。有更好的方法吗

在基本情况下,您最终指定了一个模型和一个序列化程序类。没有理由不将这两种方法都放在某种表中,并使用
kwargs
进行查找

LOOK_UP_TABLE = {
    'users' : {
        'model': ...,
        'serializer_class': ...,
    },
    'categories' : {
        ...
    }, 
}
如果您这样做了,并且覆盖了
get\u queryset
,那么您也可以覆盖
get\u serializer\u class
。然后你会有一些非常普通的东西


我不知道你到底能节省多少打字(特别是如果你使用编辑器的代码片段功能)。或者由此产生的系统会有多灵活。但这是一个有趣的想法。

在基本情况下,您最终指定了一个模型和一个序列化器类。没有理由不将这两种方法都放在某种表中,并使用
kwargs
进行查找

LOOK_UP_TABLE = {
    'users' : {
        'model': ...,
        'serializer_class': ...,
    },
    'categories' : {
        ...
    }, 
}
如果您这样做了,并且覆盖了
get\u queryset
,那么您也可以覆盖
get\u serializer\u class
。然后你会有一些非常普通的东西


我不知道你到底能节省多少打字(特别是如果你使用编辑器的代码片段功能)。或者由此产生的系统会有多灵活。但是这是一个有趣的想法。

你真的应该在
get\u queryset()
中使用
super()
来获取未过滤的查询集,然后根据
kwargs
对其进行过滤

if user_id:
    super(ImageViewSet, self).get_queryset().filter(user_id=user_id)
您会注意到,这变得非常通用,可以作为mixin包含在每个视图中:

class FilterByUserMixin(object):
    def get_queryset(self):
        user_id = self.kwargs.get('user_id', None)
        queryset = super(FilterByUserMixin, self).get_queryset()
        if user_id:
            queryset = queryset.filter(user_id=user_id)
        return querset


class ImageViewSet(FilterByUserMixin, viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer


class CategoryViewSet(FilterbyUserMixin, viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

您确实应该在
get\u queryset()
中使用
super()
来获取未筛选的查询集,并根据
kwargs
对其进行筛选

if user_id:
    super(ImageViewSet, self).get_queryset().filter(user_id=user_id)
您会注意到,这变得非常通用,可以作为mixin包含在每个视图中:

class FilterByUserMixin(object):
    def get_queryset(self):
        user_id = self.kwargs.get('user_id', None)
        queryset = super(FilterByUserMixin, self).get_queryset()
        if user_id:
            queryset = queryset.filter(user_id=user_id)
        return querset


class ImageViewSet(FilterByUserMixin, viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer


class CategoryViewSet(FilterbyUserMixin, viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

你的意思是你必须定义url的方式?应用程序怎么知道在哪里提供服务呢?我的一个想法是在UserViewSet中添加一个images操作,用@link装饰它,然后在ImageViewSet中重用get操作。自从提出这个问题以来,我尝试过这样做,但这似乎不是一件很容易的事情。而且,考虑了更多,手动定义url对我来说一点也不麻烦,就像必须以这种方式弄脏get_queryset方法一样。想象一下,有一些类似于
/users/:id/images
的附加端点,类似于
/category/:category\u id/images
等,将get\u queryset作为所有这些端点的入口点似乎是个坏主意。你是说一种必须定义url的方式吗?应用程序怎么知道在哪里提供服务呢?我的一个想法是在UserViewSet中添加一个images操作,用@link装饰它,然后在ImageViewSet中重用get操作。自从提出这个问题以来,我尝试过这样做,但这似乎不是一件很容易的事情。而且,考虑了更多,手动定义url对我来说一点也不麻烦,就像必须以这种方式弄脏get_queryset方法一样。想象一下,有一些类似于
/users/:id/images
的附加端点,类似于
/category/:category\u id/images
等,将get\u queryset作为所有这些端点的入口点似乎是个坏主意。