Django Rest Framework ModelViewSets with natural key lookup

DRF ModelViewSet can easily support detail views by slug via the lookup_value attribute. But what if you had compound keys (aka natural keys)? For example a url structure like

/api/computers/<organization-slug>/<computer-slug>/

A computer slug may only be unique per organization. That means different organizations may have computers with the same slug. But no computer may have the same slug in one organization. By using both slugs, we can look up a specific computer. We can use the lookup_value_regex attribute for this.

class ComputerViewSet(viewsets.ModelViewSet):
    queryset = Computer.objects.all()
    serializer_class = ComputerSerializer
    lookup_value_regex = r"(?P<org_slug>[^/.]+)/(?P<slug>[-\w]+)"

    def get_object(self):
        queryset = self.filter_queryset(self.get_queryset())
        obj = get_object_or_404(
            queryset,
            slug=self.kwargs["slug"],
            organization__slug=self.kwargs["org_slug"],
        )

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj

This works with drf-nested-routers. For example, we could add a nested /hard_drives viewset. The url values are in self.kwargs.

class HardDriveViewSet(viewsets.ModelViewSet):
    queryset = HardDrive.objects.all()
    serializer_class = HardDriveSerializer

    def get_queryset(self):
        return (
            super()
            .get_queryset()
            .filter(
                computer__slug=self.kwargs["slug"],
                computer__organization__slug=self.kwargs["org_slug"],
            )
        )

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s