Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework: Access item detail by slug instead of ID

Is it possible to use a object's slug (or any other field) to access the details of an item, instead of using the ID?

For example, if I have an item with the slug "lorem" and ID 1. By default the URL is http://localhost:9999/items/1/. I want to access it via http://localhost:9999/items/lorem/ instead.

Adding lookup_field in the serializer's Meta class did nothing to change the automatically generated URL nor did it allow me to access the item by manually writing the slug instead of the ID in the 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)), ] 

Generated JSON:

[     {         "url": "http://localhost:9999/items/1/",         "slug": "lorem",         "title": "Lorem",         "item_url": "http://example.com"     } ] 
like image 395
Virgiliu Avatar asked Aug 25 '15 10:08

Virgiliu


People also ask

How do you get a foreign key field name instead of ID in Django REST framework?

If you want to show any field of foreign key instead of id then you can use StringRelatedField.

How do I get Slugs in Django?

Now in the post_detail() function in the views.py file, we can accept the captured slug from the URL using post_detail(request, slug). From there, we then use the Django ORM to query the database using that slug with the Post. objects. get(slug=slug) code.

What is SlugRelatedField?

SlugRelatedField. SlugRelatedField may be used to represent the target of the relationship using a field on the target. For example, the following serializer: class AlbumSerializer(serializers. ModelSerializer): tracks = serializers.

What is QuerySet in Django REST framework?

The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.


2 Answers

You should set lookup_field in your serializer:

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

and in your view:

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

I got this result:

~ 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/" } 
like image 181
Ilya Tikhonov Avatar answered Sep 18 '22 13:09

Ilya Tikhonov


In some scenarios you may want to have both the "low level" pk value and the more semantic slug. I like to have both options personally and do this by setting the lookup_field later in the viewset as_view() method in my urls.py.

Note: the following defaults to pk with an optional slug lookup. To combine this with previous answer you would change the lookup_field below to be "pk" instead of "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) 

This could also be in your views.py - my preference is to see it beside the urlpatterns list.

like image 22
rjmoggach Avatar answered Sep 17 '22 13:09

rjmoggach