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)
Your right, REST framework doesn't support those use cases, and its not obvious to me what the design would look like if it did. You'd probably need an implicit registry of model->view (for the hyperlinked case) and model-> serializer (for the nested case) which I don't think I'd be very keen on.
The simplest way to do what you need is probably to subclass
ManyRelatedField
and create a custom field type, overridingto_native(self, obj)
to serialize each object in the set exactly the way you want it.