Problem
I have a model with the following standard generic foreign key fields:
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
event_object = generic.GenericForeignKey('content_type', 'object_id')
According to REST framework's docs, I can do the following to serialise this correctly:
class WhateverSerializer(serializers.ModelSerializer):
event_object = serializers.RelatedField(source='event_object')
This works fine, however in two other related situations, I can't get things working:
- I would like to use
HyperlinkedRelatedField
. This field requires the view_name argument, something I can't declare since the view name varies with the related model. I solved this by usingSerializerMethodField
, instantiating aHyperlinkedIdentityField
at runtime and returning itsfield_to_native
method (see snippet below). This does not feel very elegant. - I would like to nest the related object directly in the serialisation by saying
event_object = SoAndSoSerializer(source='event_object')
. The only solution I can see is to walk every*Serializer
I have defined and check which has the correct model, then use that. Again, this does not feel very elegant.
Questions
is HyperlinkRelatedField meant to work across a generic relationship? Am I just making a mistake? Is there an obvious solution to picking the right *Serializer
that I'm missing?
Code Snippet
The inelegant solution mentioned in bullet point 1 above:
class WhateverSerializer(DefaultSerializer):
event_object_url = serializers.SerializerMethodField('get_related_object_url')
# ...
def get_related_object_url(self, obj):
obj = obj.event_object
default_view_name = '%(model_name)s-detail'
format_kwargs = {
'app_label': obj._meta.app_label,
'model_name': obj._meta.object_name.lower()
}
view_name = default_view_name % format_kwargs
s = serializers.HyperlinkedIdentityField(source=obj, view_name=view_name)
s.initialize(self, None)
return s.field_to_native(obj, None)