Django REST API: How to create user-specific endpoints?

Hey everyone, I’m stuck trying to make my Django REST API user-specific. I want to access data by adding the username at the end of the URL, like /api/notes/johndoe.

Here’s what I’ve got so far:

class PersonalInfo(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birthday = models.DateField()
    bio = models.TextField(max_length=500)

class Memo(models.Model):
    content = models.TextField(max_length=1000)
    owner = models.ForeignKey(PersonalInfo, on_delete=models.CASCADE)

class MemoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Memo
        fields = ['id', 'content', 'owner']

class MemoViewSet(viewsets.ModelViewSet):
    serializer_class = MemoSerializer
    queryset = Memo.objects.all()

    def get_queryset(self):
        return self.request.owner.Memo.all()

I’ve set up the models, serializer, and view, but I can’t figure out how to make it work with usernames in the URL. Any ideas on what I’m missing or doing wrong? Thanks!

yo, i’ve been there too. try this:

in ur views.py, add:

from django.shortcuts import get_object_or_404

class MemoViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        username = self.kwargs.get('username')
        user = get_object_or_404(User, username=username)
        return Memo.objects.filter(owner__user=user)

then in urls.py:

path('api/notes/<str:username>/', MemoViewSet.as_view({'get': 'list'})),

shud work now. good luck!

I’ve dealt with this exact problem in a recent project. Here’s what I found works well:

Instead of modifying the ViewSet, I created a custom URL router. This approach gives you more flexibility and keeps your ViewSet clean.

First, define a custom router:

class UserRouter(SimpleRouter):
    def get_lookup_regex(self, viewset, lookup_prefix=''):
        return r'(?P<username>[^/.]+)'

Then, use it in your urls.py:

router = UserRouter()
router.register(r'api/notes', MemoViewSet)
urlpatterns = router.urls

In your MemoViewSet, override get_queryset:

def get_queryset(self):
    username = self.kwargs.get('username')
    return Memo.objects.filter(owner__user__username=username)

This setup allows for URLs like /api/notes/johndoe/ without cluttering your ViewSet. Just ensure you’re handling permissions correctly to prevent unauthorized access.

I’ve encountered a similar issue before, and here’s what worked for me:

Modify your MemoViewSet to include a lookup_field and lookup_url_kwarg:

class MemoViewSet(viewsets.ModelViewSet):
    serializer_class = MemoSerializer
    lookup_field = 'owner__user__username'
    lookup_url_kwarg = 'username'

    def get_queryset(self):
        username = self.kwargs.get('username')
        return Memo.objects.filter(owner__user__username=username)

Then, update your URLs:

urlpatterns = [
    path('api/notes/<str:username>/', MemoViewSet.as_view({'get': 'list', 'post': 'create'})),
    path('api/notes/<str:username>/<int:pk>/', MemoViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]

This approach should allow you to access memos via URLs like /api/notes/johndoe/. Remember to handle permissions appropriately to ensure users can only access their own data.