Hello Everyone!
I have latest django-rest-framework and I'm trying to make serializer show possible choices for each field on OPTIONS request.
Here's part of my model
# models.py
class Task(models.Model):
parent = models.ForeignKey('self',
blank=True, null=True, related_name='child_tasks')
title = models.CharField(max_length=128)
status = models.CharField(max_length=16, choices=STATUS_CHOISES, default='new')
priority = models.CharField(max_length=16, choices=PRIORITY_CHOISES, default='1')
chief = models.ForeignKey('users.SystemUser', related_name='tasks',
blank=True, null=True)
And here's serializer
# serializers.py
class ParentRelatedField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
obj = self.context['view'].get_object()
return Task.objects.exclude(pk=obj.pk)
def get_user_choices():
return tuple([(i.id, i.system_name) for i in SystemUser.objects.all()])
class TaskDetailSerializer(serializers.Serializer):
title = serializers.CharField()
parent = ParentRelatedField(
required=False, allow_null=True
)
status = serializers.ChoiceField(choices=STATUS_CHOISES)
priority = serializers.ChoiceField(choices=PRIORITY_CHOISES)
chief = serializers.ChoiceField(choices=get_user_choices(), required=False)
I achieved that for chief field using get_user_choices function, so i get:
"chief": {
"type": "choice",
"required": false,
"read_only": false,
"label": "Chief",
"choices": [
{
"value": 1,
"display_name": "First User Name"
}
]
}
ParentRelatedField works great for validation, but not for metadata:
"parent": {
"type": "field",
"required": false,
"read_only": false,
"label": "Parent"
}
I can't use ChoiceField with function (like in chief) for that because parent choice must exclude current Task object.
Solved the problem.
Solution was found at drf 3.4 announcement and drf issue comments.
I changed my field to make it more universal
class SelfExcludingRelatedField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
obj = self.context['view'].get_object()
return self.queryset.exclude(pk=obj.pk)
Then wrote custom metadata class (copied from github).
class CustomMetadata(SimpleMetadata):
def get_field_info(self, field):
field_info = super().get_field_info(field)
if (not field_info.get('read_only') and
isinstance(field, SelfExcludingRelatedField) and
hasattr(field, 'choices')):
field_info['choices'] = [
{
'value': choice_value,
'display_name': choice_name
}
for choice_value, choice_name in field.choices.items()
]
return field_info
And added it to settings:
REST_FRAMEWORK = {
'DEFAULT_METADATA_CLASS': 'api_v0.metadata.CustomMetadata',
}
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