user12177026
user12177026

Reputation:

Format url by user name

I have a small messaging API built with DRF which sends messages between users in the system. My messages view contains several extra actions:

class MessagesViewSet(ModelViewSet):
    """
    A simple ViewSet for viewing and editing the messages
    associated with the user.
    """
    authentication_classes = [TokenAuthentication, ]
    permission_classes = [IsAuthenticated]
    serializer_class = MessageSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = [MessageFields.MARK_READ]

    def get_user(self):
        user = self.request.user
        return user

    def get_queryset(self):
        return Message.objects.filter(sent_to=self.get_user())

    @action(detail=True)
    def sent_messages(self, request, pk):
        """
        Return all messages sent by the user.
        """
        queryset = Message.objects.filter(sender=self.get_user())
        serialized_data = MessageSerializer(queryset, many=True)
        return Response(serialized_data.data, status=HTTP_200_OK)

    @action(detail=True)
    def last_50_messages(self, request, pk):
        """
        Return the user's 50 last messages
        """
        queryset = Message.objects.filter(sent_to=self.get_user())
        serialized_data = MessageSerializer(queryset, many=True)
        return Response(serialized_data.data, status=HTTP_200_OK)

Urls file:

from .views import MessagesViewSet

messages_router = DefaultRouter()
messages_router.register(r'messages', MessagesViewSet, basename='messages')

urlpatterns = [
    url('', include(messages_router.urls))
]

Right now the only way to access the two custom methods is opening one of the message instances and then add it to the URL line and it'll work.

How can format the url for each method so it will be via the username? right now:

http://127.0.0.1:8000/api/messages/1/sent_messages/

I looking for something like:

http://127.0.0.1:8000/api/messages/#request.user.username/sent_messages/

Upvotes: 0

Views: 77

Answers (1)

ncopiy
ncopiy

Reputation: 1604

You have to change lookup_field value in ModelViewSet like this:

class MessagesViewSet(ModelViewSet):
    ...
    lookup_field = "username"
    ...

But be careful, API like retrieve will be work with username lookup too, not pk.
To use both (username, lookup) check hook here:

class MultipleFieldLookupORMixin(object):
    """
    Actual code http://www.django-rest-framework.org/api-guide/generic-views/#creating-custom-mixins
    Apply this mixin to any view or viewset to get multiple field filtering
    based on a `lookup_fields` attribute, instead of the default single field filtering.
    """
    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        for field in self.lookup_fields:
            try:                                  # Get the result with one or more fields.
                filter[field] = self.kwargs[field]
            except Exception:
                pass
        return get_object_or_404(queryset, **filter)  # Lookup the object

class RetrieveUserView(MultipleFieldLookupORMixin, generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_fields = ('account', 'username')

Upvotes: 2

Related Questions