How to get the detailed page by slug and not id in Django Rest Framework class based views

Question:

I am building an API using Django Rest Framework. I have the /api/localities endpoint where all of the objects on my database are displayed.

Now I want to create the endpoint for a single page of a particular locality, and I want to make it by slug and not id for example /api/localities/munich.

I am using Class based views and right now I can get the single page by id, for example /api/localities/2, but I want to change that to the slug.

How can I do this?

Here is my code:

models.py

class Localities(models.Model):
        id_from_api = models.IntegerField()
        city = models.CharField(max_length=255, null=True, blank=True)
        slug = models.CharField(max_length=255, null=True, blank=True)
        postal_code = models.CharField(max_length=20, null=True, blank=True)
        country_code = models.CharField(max_length=10, null=True, blank=True)
        lat = models.CharField(max_length=255, null=True, blank=True)
        lng = models.CharField(max_length=255, null=True, blank=True)
        google_places_id = models.CharField(max_length=255, null=True, blank=True)
        search_description = models.CharField(max_length=500, null=True, blank=True)
        seo_title = models.CharField(max_length=255, null=True, blank=True)

        def __str__(self):
             return self.city

serializers.py

from rest_framework import serializers
from .models import Localities

class LocalitiesSerializers(serializers.ModelSerializer):
    class Meta:
        model = Localities
        fields = (
            "id",
            "id_from_api",
            "city",
            "slug",
            "postal_code",
            "country_code",
            "lat",
            "lng",
            "google_places_id",
            "search_description",
            "seo_title",
        )

views.py

from django.shortcuts import render
from django.http import HttpResponse
from wagtail.core.models import Page
from .models import LocalityPage, Localities
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import generics

import json
import requests

from .models import Localities
from .serializers import LocalitiesSerializers


class LocalitiesAll(generics.ListCreateAPIView):
    queryset = Localities.objects.all()
    serializer_class = LocalitiesSerializers


class LocalitiesDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Localities.objects.all()
    serializer_class = LocalitiesSerializers

urls.py

from django.urls import path
from . import views

urlpatterns = [  
    path('reload', views.convert_json),  # app homepage
    path("localities/", views.LocalitiesAll.as_view()),
    path("localities/<int:pk>/", views.LocalitiesDetail.as_view()),
] 

Asked By: Blerdijan

||

Answers:

If you want to use slug instead of id then first you need to update your URLs from int:pk to str:slug:

path("localities/<str:slug>/", views.LocalitiesDetail.as_view())

Now update your views.py file class to:

class LocalitiesDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Localities.objects.all()
    serializer_class = LocalitiesSerializers
    lookup_field = 'slug'

This will help you to reach the goal that you wanted to achieve.

Answered By: dostogircse171