I am new at Django and couldn\'t find solution for my problem.
The problem is to force specific serializer for include different amount of fields in case of utilizing di
When someone just starts using DRF, a common mistake is to try to make the same Serializer do everything under the sun. Certainly I went down that path myself.
but life becomes a lot simpler when you use mutiple serializers for different tasks. You can easily switch serializers using the get_serializer_class method. Here is an example right from the manual that shows how to use one for admins and another for ordinary users
def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
Sometimes you want to use a single serializer for lists and another one for when providing details. Try something like this:
def get_serializer_class(self):
if self.action == 'retrieve':
return serializers.PlayerDetailSerializer
else :
return serializers.PlayerSerializer
Life is much simpler this way.
You can also use the next approach:
class SelectSerializerMixin(object):
serializer_class = None
list_serializer_class = None
retrieve_serializer_class = None
update_serializer_class = None
partial_update_serializer_class = None
create_serializer_class = None
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return getattr(self, f"{self.action}_serializer_class") or self.serializer_class
Then add this mixin to your ViewSet:
class MyModelViewSet(SelectSerializerMixin, ModelViewSet):
queryset = models.MyModel.objects.all()
serializer_class = serializers.SomeSerializer
retrieve_serializer_class = serializers.AnotherSerializer
list_serializer_class = serializers.OneMoreSerializer
But if you need a Serializer with a dynamic set of fields (ex. you have a handler but you need to return only specific fields in the response), you can use the approach from Ykh's answer.
https://stackoverflow.com/a/44064046/2818865
class DynamicFieldsModelSerializer(ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` and 'exclude' argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
exclude = kwargs.pop('exclude', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields.keys())
for field_name in existing - allowed:
self.fields.pop(field_name)
if exclude is not None:
not_allowed = set(exclude)
for exclude_name in not_allowed:
self.fields.pop(exclude_name)
class UserCreateSerializer(DynamicFieldsModelSerializer):
class Meta:
model = User
fields = ('username', 'tel', 'email', 'password')
use:
serializer = UserCreateSerializer(data=request.data, fields=('username', 'password', 'tel'))
or
serializer = UserCreateSerializer(data=request.data, fields=('username', 'password', 'email'))