Django REST serializer and extra attributes from custom model fields
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Puzzle Game 5 Looping
--
Chapters
00:00 Django Rest Serializer And Extra Attributes From Custom Model Fields
01:17 Accepted Answer Score 1
02:10 Answer 2 Score 0
03:47 Thank you
--
Full question
https://stackoverflow.com/questions/3021...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #django #rest #djangorestframework
#avk47
ACCEPTED ANSWER
Score 1
Question 1:
I want to be able to access the test1-info attribute just like i would be able to access the name1-max_length attribute.
Yes, you can access your info attribute by ModelField.model_field.info.
you can see the example below.
Question 2 for your final goal:
I think you can customize your own metadata class.
from rest_framework.metadata import SimpleMetadata
from rest_framework.serializers import ModelField
from pbweb.models import RsTestField
class MyMetadata(SimpleMetadata):
def get_field_info(self, field):
field_info = super(MyMetadata, self).get_field_info(field)
# I will add the info field only for RsTestField-ModelField
if isinstance(field, ModelField) and isinstance(field.model_field, RsTestField):
# access your info attribute HERE
field_info['info'] = field.model_field.info
return field_info
and, don't forget to config your DEFAULT_METADATA_CLASS settings
settings.py
REST_FRAMEWORK = {
'DEFAULT_METADATA_CLASS': 'my.customize.MyMetadata'
}
ANSWER 2
Score 0
Ok got it, for everyone trying the same, adding extra kwargs to django-models, passing them to the rest_framework serializer, and delivering them to the Metadata scheme to get them in the OPTIONS method in a API request:
In this example i add a kwarg 'serial' to a CharField. First extend django.db.models.CharField and use it in a model:
models.py
class RsCharField(models.CharField, metaclass=models.SubfieldBase):
def __init__(self, serial=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.serial = serial
class MyModel(models.Model):
fied_name1 = RsCharField(max_length=100, serial=123456, default="")
Then create a new serializer for your new field type, eg: RsCharField below, and extend the ModelSerializer to create a mapping from the Django-model-RsCharField, to the serializer-RsCharField.
Extend the build_standard_field method of the ModelSerializer to add the extra kwargs from the django-model-RsCharField to the serializers-RsCharField
serializers.py
from rest_framework import serializers
class RsCharField(serializers.CharField):
def __init__(self, serial=None, **kwargs):
self.serial = serial
super().__init__(**kwargs)
class RsModelSerializer(serializers.ModelSerializer):
serializer_field_mapping = serializers.ModelSerializer.serializer_field_mapping
serializer_field_mapping[myapp.models.RsCharField] = RsCharField
def build_standard_field(self, field_name, model_field):
field_class, kwargs = super().build_standard_field(field_name, model_field)
if isinstance(model_field, kernel.fields.RsCharField):
kwargs['serial'] = model_field.serial
return field_class, kwargs
Finally extend SimpleMetadata to pass the new kwargs to the OPTIONS method of your api, and show it in the scheme:
class RsMetaData(SimpleMetadata):
def get_field_info(self, field):
field_info = super(RsMetaData, self).get_field_info(field)
if(isinstance(field, RsCharField)):
field_info['serial'] = field.serial
return field_info
And adjust settings.py
REST_FRAMEWORK = {
'DEFAULT_METADATA_CLASS': 'my.customize.RsMetaData'
}
Probably not neat yet, but this is the idea. Tnx soooooot!