sourceを使用する
sourceを使用することで、Metaに指定したモデルに関連する値を抜き出すことが出来ます。
使い方としては以下のような感じです。
models.py
class Pref(models.Model):
name = models.CharField(...)
point = models.PointField(geography=True...)
def get_lat(self):
return self.point.y
def get_long(self):
return self.point.x
...
class City(models.Model):
city = models.ForeignKey(Pref, related_name='cities')
name = models.CharField(...)
...
serializers.py
class PrefSerializer(serializers.ModelSerializer):
city_count = serializers.IntegerField(source='cities.count', read_only=True)
class Meta:
model = Pref
fields = ('id', 'name', 'city_count')
このようにrelated_nameを付けた名称からcountを取ったり、上記のモデルからであればget_latやget_longを指定することも出来ます。
SerializerMethodFieldを使用する
SerializerMethodFieldを使用すると、serializerの中でfield名に沿った独自の関数を作成することが出来ます。
使い方としては以下のような感じです。get_ + field名で関数を作るところが特徴的です。
serializers.py
class PrefSerializer(serializers.ModelSerializer):
is_pickup = serializers. SerializerMethodField(read_only=True)
class Meta:
model = Pref
fields = ('id', 'name', 'is_pickup')
def get_is_pickup(self, instance):
return instance.pickup_start <= timezone.now() < instance.pickup_end
上記のもの程度であれば、モデル内に関数を用意してsourceを使ってしまっても良いですが、ちょっとした判定などを行うのに使うと便利です。
ただし、自由度が非常に高いあまりに、この中で複雑な処理を書くことはパフォーマンスの観点から避けた方が良いと思います。
to_representationを使用する
to_representation関数をoverrideすることで、view側のquerysetでannotateなどで生成した変数名を使いたい時や、データの階層を変えたい時などに使うことが出来ます。
views.py
class PrefList(mixins.ListModelMixin, generics.GenericAPIView):
permission_classes = (AllowAny,)
serializer_class = PrefSerializer
queryset = Pref.objects.annotate(
rank=Window(
expression=Rank(),
order_by=F('population').desc()
)
)
serializers.py
class PrefSerializer(serializers.ModelSerializer):
class Meta:
model = Pref
fields = ('id', 'name')
def to_representation(self, instance):
ret = super(PrefSerializer, self).to_representation(instance)
ret['rank'] = instance.rank
return ret
上記の例では、views側で生成したrankをto_representationで入れています。fieldsに入れようとすると、そのようなfieldは無いとエラーが出てしまいます。










モデル内に存在しないfieldを返す方法をいくつか上げてみました。
ただし、どの方法も注意しないといけないのは、querysetでrelationなどを良く考えながらselect_relatedやprefetch_relatedなどを加えてパフォーマンスを保つことには気を付けましょう。