我使用的是Python 2.7,DRF 3.1.3,Django 1.4.21(我知道它已经很久了,但它是一个很大的代码库,有一天我们会迁移)。现实世界的商业案例比这更复杂,这是简化版本。
我有一个模特:
class Person(models.Model):
foo = models.CharField(max_length=2, blank=True, null=True)
在REST API上我想公开两个字段,它们都来自foo。这两个字段都应该是可写的,当我写入时,这两个字段都会以某种方式设置foo字段。 尝试1:棒是不幸的只读
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
尝试2:试图以某种方式伪造一个字段
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
后者显然错误地抱怨Person
模型没有条形字段。这是真的。如何解决这个问题呢?我可以在序列化程序to_representation
和to_internal_value
中设置/获取foo和bar。我只想在DRF
中指定一个字段,该字段仅存在于REST API
侧,并且在模型端没有关联的字段。我可以照顾变换。那个字段应该是读写的,否则我可以用SerializerMethodField
来解决它。
答案 0 :(得分:2)
我不确定你的用例,看起来有点奇怪,但为什么不在你的模型上添加一个属性。例如,
@property
def bar(self):
"""
Used for DRF only.
"""
return None # or self.foo
然后将其添加到序列化程序中的字段中(无需使用PlaceholderCharField
)
fields = ('id', 'foo', 'bar')
其余的将会有效。
答案 1 :(得分:2)
稍微调整你的第一次尝试,你可以为该字段添加别名,没问题:
class PersonSerializer(serializers.ModelSerializer):
# vvvvvvvvv
bar = serializers.CharField(
source='foo', required=False
)# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class Meta:
model = Person
fields = ('id', 'foo', 'bar')
我仍然使用DRF 2.4.4来获得更好的嵌套,多对象嵌套序列化程序支持,但是我使用该方法来对URL及其关联对象进行别名处理,以处理Angular JS比较的方式一些控件中的对象。 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')