Подтвердить что ты не робот

Django Rest Framework: доступ к деталям элемента с помощью slug вместо ID

Можно ли использовать объектную пробку (или любое другое поле) для доступа к деталям элемента вместо использования идентификатора?

Например, если у меня есть элемент с slug "lorem" и ID 1. По умолчанию URL-адрес http://localhost:9999/items/1/. Я хочу получить доступ к нему через http://localhost:9999/items/lorem/.

Добавление lookup_field в сериализаторе. Класс Meta не изменил автоматически сгенерированный URL-адрес и не разрешил мне получить доступ к элементу, вручную введя пул вместо идентификатора в URL-адресе.

models.py

class Item(models.Model):
    slug = models.CharField(max_length=100, unique=True)
    title = models.CharField(max_length=100, blank=True, default='')
    # An arbitrary, user provided, URL
    item_url = models.URLField(unique=True)

serializers.py

class ClassItemSerializer(serializers.HyperlinkedModelSerializer):
     class Meta:
        model = Item
        fields = ('url', 'slug', 'title', 'item_url')

views.py

class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer

urls.py

router = DefaultRouter()
router.register(r'items', views.ItemViewSet)

urlpatterns = [
    url(r'^', include(router.urls)),
]

Сгенерированный JSON:

[
    {
        "url": "http://localhost:9999/items/1/",
        "slug": "lorem",
        "title": "Lorem",
        "item_url": "http://example.com"
    }
]
4b9b3361

Ответ 1

Вы должны установить lookup_field в свой сериализатор:

class ItemSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Item
        fields = ('url', 'slug', 'title', 'item_url')
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

и на ваш взгляд:

class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    lookup_field = 'slug'

Я получил этот результат:

~ curl http://127.0.0.1:8000/items/testslug/ | python -mjson.tool
{
    "item_url": "https://example.com/", 
    "slug": "testslug", 
    "title": "Test Title", 
    "url": "http://127.0.0.1:8000/items/testslug/"
}

Ответ 2

В некоторых сценариях вы можете иметь как значение "низкий уровень" pk, так и более семантический slug. Мне нравится иметь оба варианта лично и сделать это, установив lookup_field позже в методе viewet as_view() в моем urls.py.

Примечание. Следующие значения по умолчанию: pk с необязательным поиском slug. Чтобы объединить это с предыдущим ответом, вы изменили бы lookup_field ниже на "pk" вместо "slug".

from django.conf.urls import *
from rest_framework.urlpatterns import format_suffix_patterns

from myobjects import views as myviews


# simplify the view definitions by splitting out the options
REQDICT = {
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
}


# define the pk detail view
myobject_detail = myviews.MyObjectViewset.as_view(REQDICT)
# define the slug detail view
myobject_slug_detail = myviews.MyObjectViewset.as_view(REQDICT, lookup_field='slug')


urlpatterns = [
    url(r"^myobjects/(?P<pk>\d*)/$",
           myobject_detail,
           name = 'myobject-detail'),
    url(r"^myobjects/(?P<slug>[-\w]+)/$",
           myobject_slug_detail,
           name = 'myobject-slug-detail'),
]

urlpatterns = format_suffix_patterns(urlpatterns)

Это также может быть в вашем views.py - я предпочитаю видеть его рядом с списком urlpatterns.