Reputation: 10699
I'm using Python 2.7, DRF 3.1.3, Django 1.4.21 (I know it's old but it's a large codebase, one day we'll migrate). The real-world business case is more complicated than this, here is the simplified version.
I have a model:
class Person(models.Model):
foo = models.CharField(max_length=2, blank=True, null=True)
On the REST API I want to expose two fields, both of them is derived from foo. Both fields should be writable, and both fields would set the foo field in a way when I write into it. Try 1: bar is unfortunately read-only
class PersonSerializer(serializers.ModelSerializer):
bar = serializers.SerializerMethodField()
class Meta:
model = Person
fields = ('id', 'foo', 'bar')
def get_bar(self, obj):
return get_bar(obj.foo) # not relevant now what get_bar does
Try 2: trying to fake a field somehow
class PlaceholderCharField(serializers.CharField):
def to_representation(self, obj):
pass
def to_internal_value(self, data):
pass
class PersonSerializer(serializers.ModelSerializer):
bar = PlaceholderCharField()
class Meta:
model = Person
fields = ('id', 'foo', 'bar')
def to_representation(self, instance):
data = super(PersonSerializer, self).to_representation(instance)
data['bar'] = get_bar(instance.foo)
return data
def to_internal_value(self, data):
instance = super(PersonSerializer, self).to_internal_value(data)
if data.has_key('bar') and not data.has_key('foo'):
instance.foo = get_foo(data['bar']) if data['bar'] else None
return instance
This latter one errors out obviously complaining that the Person
model doesn't have a bar field. Which is true. How to solve this problem? I can handle setting/getting the foo and bar in the serializer's to_representation
and to_internal_value
. I just want a way in DRF
to specify a field, which only exists on the REST API
side, and doesn't have a field associated on the model end. I can take care of the transformations. And that field should be read-write, otherwise I could just solve it with a SerializerMethodField
.
Upvotes: 2
Views: 1838
Reputation: 8354
I'm unsure of your usecase, it seems a little odd, but why don't you just add a property on your model. For example,
@property
def bar(self):
"""
Used for DRF only.
"""
return None # or self.foo
Then add it to your fields in the serializer (no need to use PlaceholderCharField
)
fields = ('id', 'foo', 'bar')
The rest will work as you have it.
Upvotes: 2
Reputation: 24230
Tweak your first attempt a little and you can alias that field, no problem:
class PersonSerializer(serializers.ModelSerializer):
# vvvvvvvvv
bar = serializers.CharField(
source='foo', required=False
)# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class Meta:
model = Person
fields = ('id', 'foo', 'bar')
I'm still using DRF 2.4.4 for the better nested, multi-object nested serializer support, but I use that method for aliasing a URL and its associate object all the time to deal with the way Angular JS compares objects in some of its controls. e.g.
class SensorSerializer(serializers.HyperlinkedModelSerializer):
location_obj = SensorLocationSerializer(source='location',read_only=True,required=False)
class Meta:
model = Sensor
fields = ('url', 'id', 'name', 'serial_number', 'location',
'location_obj', 'active')
Upvotes: 3