I'm building a django application, with a rest api, where users can subscribe to feeds.
My model looks like this:
class Profile(models.Model):
user = models.OneToOneField(
User, # standard django user
on_delete=models.CASCADE,
primary_key=True
)
subscriptions = models.ManyToManyField(Feed, related_name="subscribers")
class Feed(models.Model):
# These feeds are read-only for the subscribers
pass
Explained in English:
Each user has a profile. These profile can subscribe to feeds. The feeds can only be subscribed to, they can't be created or updated by the users.
I want to expose a rest endpoint to create, read, update and delete subscriptions for the current user. Of course, I'd love to use the generic views, a ListCreateAPIView
and a RetrieveUpdateDeleteAPIView
, but I can't figure out how to make the correct serializers and querysets to make this easy to use.
I ended up with /me/subscriptions/
returning a list of Feeds directly, but then the POST
is weird because it would create a feed instead of creating a subscription.
I'm confused... Any hint is appreciated!
You could use a ModelViewSet
and override create
method:
views.py:
from rest_framework import status
from rest_framework import viewsets
class FeedViewSet(serializers.ModelViewSet):
serializer_class = FeedSerializer
def get_queryset(self):
# show an only related Feed objects to a request.user
profile = request.user.profile
return Feed.objects.filter(subscribers=profile)
def create(self, request, *args, **kwargs):
pk = request.data.get('pk')
profile = request.user.profile
feed = Feed.objects.get(pk=pk)
profile.subscriptions.add(feed)
return Response('subscription feed updated!', status=status.HTTP_201_CREATED)
# list will work by default
# other methods like update, delete, retrieve
# you could set with NOT_IMPLEMENTED status
def update(self, request, *args, **kwargs):
return Response(status=status.HTTP_501_NOT_IMPLEMENTED)
urls.py:
from rest_framework import routers
router = routers.SimpleRouter()
router.register('subscriptions', FeedViewSet, base_name='subscription')
Now you'll have an endpoint for updating subscriptions of Profile
based on a request.user
. GET
to /subscriptions/
will show all Feed
objects filtered by request.user
and POST
with data {'pk': <Feed_pk>}
to /subscriptions/
will create a link between Feed
and Profile
.