I want to hide specific fields of a model on the list display at
persons/
and show all the fields on the detail displaypersons/jane
I am relatively new to the rest framework and the documentation feels like so hard to grasp.
Here's what I am trying to accomplish.
I have a simple Person
model,
# model
class Person(models.Model):
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
nickname = models.CharField(max_length=20)
slug = models.SlugField()
address = models.TextField(max_length=300, blank=True)
and the serializer class
# serializers
class PersonListSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = ('nickname', 'slug')
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = ('first_name', 'last_name', 'nickname', 'slug', 'address')
and the viewsets.
# view sets (api.py)
class PersonListViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = PersonListSerializer
class PersonViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all()
serializer_class = PersonSerializer
at the url persons
I want to dispaly list of persons, just with fields nickname
and slug
and at the url persons/[slug]
I want to display all the fields of the model.
my router configurations,
router = routers.DefaultRouter()
router.register(r'persons', api.PersonListViewSet)
router.register(r'persons/{slug}', api.PersonViewSet)
I guess the second configuration is wrong, How can I achieve what I am trying to do?
update:
the output to persons/slug
is {"detail":"Not found."}
but it works for person/pk
Thank you
I wrote an extension called
drf-action-serializer
(pypi) that adds a serializer calledModelActionSerializer
that allows you to define fields/exclude/extra_kwargs on a per-action basis (while still having the normal fields/exclude/extra_kwargs to fall back on).The implementation is nice because you don't have to override your ViewSet
get_serializer
method because you're only using a single serializer. The relevant change is that in theget_fields
andget_extra_kwargs
methods of the serializer, it inspects the view action and if that action is present in theMeta.action_fields
dictionary, then it uses that configuration rather than theMeta.fields
property.In your example, you would do this:
Your ViewSet would look something like:
And your router would look normal, too:
Implementation
If you're curious how I implemented this:
get_action_config
which gets the current view action and returns that entry in theaction_fields
dict:get_field_names
ofModelSerializer
:From:
To:
get_extra_kwargs
method:From:
To:
I think it should be like this:
and you should include a line like this:
in your serializer class. Like this:
You can override the 'get_fields' method your serializer class and to add something like that:
In this case when you get detail-view there is 'kwargs': {'pk': 404} and when you get list-view there is 'kwargs': {}
If you want to change what fields are displayed in the List vs Detail view, the only thing you can do is change the Serializer used. There's no field that I know of that lets you specify which fields of the Serializer gets used.
For anyone else stumbling across this, I found overriding get_serializer_class on the viewset and defining a serializer per action was the DRY-est option (keeping a single viewset but allowing for dynamic serializer choice):
Hope this helps someone else.
The field selection on you serializers should be working, but I don't know what might be happening exactly. I have two solutions you can try:
1 Try to change the way you declare you serializer object
2 The second way around would change your serializers
This is not the most normal way, since the field selector should be working but you can try:
I hope it helps. Try to see the APIview class for building your view too.