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 different views. I would like to use 'id' field in my 1st view, and in 2nd view - 'id' and 'name' fields.
Here is my model.py
class Processing(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField()
description = models.CharField()
And here is my serializer.py
class ProcessingSerializer(serializers.ModelSerializer):
id = serializers.ModelField(model_field=Processing()._meta.get_field('id'))
class Meta:
model = Processing
fields = ('id', 'name')
Any help will be welcome.
In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.
DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.
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.
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.
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'))
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With