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',
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.