Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework: Two different ModelSerializers for the same model

I have one model for which I've defined two different HyperlinkedModelSerializers:

class Foo(models.Model):
    ...

class FooSerializer1(serializers.HyperlinkedModelSerializer):
    ...

    class Meta:
        model = Foo
        fields = ('url', 'id', ...)
        lookup_field= 'pk'

# A second view of the same model for another API use-case
class FooSerializer2(serializers.HyperlinkedModelSerializer):
    ...

    class Meta:
        model = Foo
        fields = ('url', 'id', ...)
        lookup_field= 'pk'

FooSerializer1 is being used by a couple GenericViews in one Django app (i.e. its own urls.py), and FooSerializer2 by a ModelViewSet in another Django app. I have the ModelViewSet registered in a DefaultRouter along with a few other viewsets:

urlpatterns = patterns('',
    url(r'^$', 'myapp.views.api_root'),
    url(r'^foo1/$', views.FooList1.as_view(), name='foo1-list'),
    ...
)

urlpatterns = format_suffix_patterns(urlpatterns)

...

class FooViewSet2(viewsets.ReadOnlyModelViewSet):
    queryset = Foo.objects.all()
    serializer_class = FooSerializer2
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def get_queryset(self):
        ...

router = routers.DefaultRouter()
...
router.register(r'foo2', views.FooViewSet2)
...
urlpatterns = router.urls

That router's auto-generated api root displays the endpoint for the GenericView of FooSerializer1 (foo1-list), instead of foo2/. If I manually GET foo2/, the results show Foo serialized according to FooSerializer2 (which is correct), however the URL for each result again displays the foo1 detail view.

I tried setting get_serializer in FooViewSet2, but that didn't work. How do I get the api-root and FooSerializer2 results to display the URLs corresponding to FooViewset2?

like image 997
Neil Avatar asked Jun 22 '14 12:06

Neil


People also ask

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

Is Django REST framework synchronous?

Django REST framework is built on Django, which is a synchronous framework for web applications.

Why serializers are used in Django?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.


1 Answers

DRF fortunately allows the flexibility to support this scenario through setting a few parameters.

First, I set the basename parameter on the router entry:

router.register(r'foo2', views.Foo2ViewSet, 'foo2')

Next, I set the view_name in the HyperlinkedModelSerializers in order to not default to foo-detail as mentioned in the docs:

class FooSerializer1(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='foo1-detail',
    )
    ...

urlpatterns = patterns('',
    url(r'^$', 'myapp.views.api_root'),
    url(r'^foo1/$', views.Foo1List.as_view(), name='foo1-list'),
    url(r'^foo1/(?P<pk>[0-9]+)/$', views.FooDetail1.as_view(), name='foo1-detail'),

    ...

class FooSerializer2(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='foo2-detail',
    )
    ...
like image 69
Neil Avatar answered Sep 18 '22 22:09

Neil