Reputation: 9077
I've got a relationship between User's and Image's where every user can have multiple images. I need to define an endpoint that retrieves all images for a specific user:
GET /users/:id/images
I've done it like this:
urls.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),
...
)
image/views.py
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()
It works but I'm not happy with it. Imagine a few additional endpoints that are analogous to /users/:user_id/images/
, i.e. something along the lines of /categories/:category_id/images/
, etc. Having get_queryset
as an entry-point for both of those, letting it distinguish between them based on kwargs
, doesn't seem very appealing. Is there a better way to do it?
Upvotes: 2
Views: 830
Reputation: 8981
You really should use super()
in get_queryset()
to get the unfiltered query set and just filter it down based on the kwargs
.
if user_id:
super(ImageViewSet, self).get_queryset().filter(user_id=user_id)
You'll notice that this becomes very generic and can be included into each view as a 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
Upvotes: 2
Reputation: 7386
In the basic case you end up specifying a model and a serializer class. There's no reason why you couldn't put both of these in some kind of table and use kwargs
to do a lookup.
LOOK_UP_TABLE = {
'users' : {
'model': ...,
'serializer_class': ...,
},
'categories' : {
...
},
}
If you did this, as well as overriding get_queryset
, you could override get_serializer_class
too. You'd then have something pretty generic.
I'm not how much typing you'd really be saving (especially if you use your editor's code snippets features). Or how flexible the resultant system would be. But it's an interesting idea.
Upvotes: 2