0
votes

My ember app expects the JSON response to contain a primary key result for the model ID. Rather than use integer IDs, I want to use slugs. I know that in the standard django framework you can do something like this:

from rest_framework import serializers
from .models import Page

class PageSerializer(serializers.ModelSerializer):
   id = serializers.CharField(source='slug')

   class Meta:
      model = Page
      fields = ('name','id',...etc )

However, this doesn't work when using the json api - in my response I still have something like

"data": [{
        "type": "pages",
        "id": "2",
        "attributes": {
            "name": "Some page name",                 
        }]

When I want the "id" field to be something like "some-page-name" (the slug)

Is this not possible with the json api. For clarity the equivalent json api import above would be

 from rest_framework_json_api import serializers

Many thanks

**** addition ****

To help clarify the problem I am facing, here is a serializer using the standard REST framework. All attributes shown below are included in the Page model.

from rest_framework import serializers
from .models import Page

class PageSerializer(serializers.ModelSerializer):
    id = serializers.CharField(source='slug')
    class Meta:
        model = Page
        fields = ('name','id')

The JSON response I get at http://localhost:8000/api/pages is as follows

 [
    {
      "name": "Page 1",
      "id": "page-1"
   },
   {
    "name": "Page 2",
    "id": "page-2"
   },
   {
     etc
   }
 ]

When I use the json api, doing the exactly the same, but obviously importing

from rest_framework_json_api import serializers 

I am not able to change the id value in the same way, I have something like this when viewing http://localhost:8000/api/pages

{
   "links": {
      omitted for brevity ...
   },
  "data": [
      {
        "type": "pages",
        "id": "1",
        "attributes": {
            "name": "Page 1"
        }
     },
     {
        "type": "pages",
        "id": "2",
        "attributes": {
            "name": "Page 2"
       }
    },
]
2
don't include 'id' in fields.dirkgroten
do you have the field slug in your model?indexOutOfBounds
If your model has a slug field, why not just pass that as field (and give it the label "id")?dirkgroten
Hi - thanks for getting back. If I remove 'id' in fields it makes no difference, and sorry, yes I do have slug in the model .. I didnt show it in the fields list for brevityNewfoundland
@dirkgroten sorry can you clarify?Newfoundland

2 Answers

2
votes

This is the solution which allows me to view responses at eg http://localhost:8000/api/pages and make a request to http://localhost:8000/api/pages/some-slug in a format that Emberjs (expecting the response to conform with the JSON API spec) won't complain about.

In my serializer (PageSerializer.py):

from rest_framework_json_api import serializers
from .models import Page

class PageSerializer(serializers.ModelSerializer):

    class Meta:
        model = Page
        fields = ('name','id','url','slug')
        lookup_field = 'slug'

        // if you want to show the links field in the response
        extra_kwargs = {'url': {'lookup_field':'slug'}}

In the view (PageViewSet)

from rest_framework import viewsets
from .models import Page
from .serializers import PageSerializer

class PageViewSet(viewsets.ModelViewSet):

    queryset = Page.objects.all().order_by('name')
    serializer_class = PageSerializer
    lookup_field = 'slug'

The router stays unchanged:

from django.urls import path, include
from rest_framework import routers
from page import views

router = routers.DefaultRouter(trailing_slash=False)
router.register('pages',views.PageViewSet)

urlpatterns = [
   path('api/',include(router.urls)),
]
0
votes

I think what you want is to use your slug field instead of id as your primary key so that you can pass that parameter in your url to get the desired result. You can do something like this in your url

url(r'^something-here/(?P<slug>[\w-]+)/$', "your_view_name_here", name='name_you_want')

In your views then you can do something like the following:

class YourListAPIView(ListAPIView):
    serializer_class = YourSerializer
    def get_queryset(self):
        slug = self.kwargs['slug']
        return ModelName.objects.filter(slug=slug)