22👍
Just to expand on Wim’s answer, this is a way to select a different serialiser based on the incoming request method:
class RequestViewSet(viewsets.ModelViewSet):
serializer_class = RequestModelSerializer
model = Request
def get_serializer_class(self):
serializer_class = self.serializer_class
if self.request.method == 'POST':
serializer_class = SerializerWithoutCertainFields
return serializer_class
2👍
The answer of @fabio.sussetto put me on the right track. I think my answer is slightly prettier; I don’t specify the serializer on the class directly but only in get_serializer_class()
. Also, I do not switch it based on the HTTP type (i.e. POST
) but rather on the action, update
, which I think is more declarative.
class RequestViewSet(viewsets.ModelViewSet):
model = Request
def get_serializer_class(self):
if self.action == 'update':
return serializer_class = SerializerWithoutCertainFields
return RequestModelSerializer
- How do I update an object's members using a dict?
- Returning a value with psycopg2
- No matching distribution found for django
- How do I redefine functions in python?
- Django + mod_wsgi. Set OS environment variable from Apache's SetEnv
1👍
This can be achieved with one serializer by using to_internal_value
method
class TaskSerializer(serializers.ModelSerializer):
# Field settings here
def to_internal_value(self, data):
data = super().to_internal_value(data)
# Remove target_object if serializer is updating object
if self.instance:
data.pop('target_object', None)
return data
class Meta:
model = Task
fields = ('owner', 'task_id', 'target_object')
- What is the correct way to deal with DB migration while using South, Django and Git?
- Language Localization of Khan Academy
- Django, difference between _base_manager and objects
- Django MakeMessages missing xgettext in Windows
- Django REST Framework – POSTing foreign key field containing natural key?
0👍
could also be done with a combination of required=False
and dropping the field value when updating like in this example:
class SectionSerializer(serializers.ModelSerializer):
# do not require field lesson when updating
lesson = serializers.PrimaryKeyRelatedField(queryset=Lesson.objects.all(), required=False)
# do not allow changing the lesson field
def update(self, instance, validated_data):
validated_data.pop("lesson", None)
return super().update(instance, validated_data)
0👍
The most simple and reusable solution I could find for it was to create a validator that allows creating but not updating:
class CreateOnlyValidator:
"""
Prevent a field from being updated.
"""
requires_context = True
def __call__(self, value, serializer_field):
instance = serializer_field.parent.instance
if instance is not None:
if value != getattr(instance, serializer_field.source):
msg = "This field cannot be updated."
raise exceptions.ValidationError(msg, code="create-only")
# if the value is the same, no need to update it
raise fields.SkipField()
return value
class TaskSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
task_id = serializers.ReadOnlyField()
target_object = serializers.PrimaryKeyRelatedField(
queryset=Request.objects.all()
validators=[CreateOnlyValidator()],
)
Adding the validation logic to a validator allows using it in any field type.