I ran into this problem now too. I think I solved this with the following code, freely modeled from Django REST docs - Generic Relationships .
(Hope this helps. I am new to Django. I will update this if I can make it more elegant).
My models:
from django.contrib.auth.models import User
from django.db import models
from django_extensions.db.models import TimeStampedModel
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
class TaggedItem(models.Model):
"""
Tags arbitrary model instances using a generic relation.
"""
tag_name = models.SlugField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
tagged_object = GenericForeignKey('content_type', 'object_id')
user_created = models.BooleanField(default=True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
def __str__(self):
return self.tag_name
class Bookmark(TimeStampedModel):
"""
A bookmark consists of a URL, and 0 or more descriptive tags.
"""
user = models.ForeignKey(User, verbose_name='user', related_name='bookmarks')
url = models.URLField()
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
tags = GenericRelation(TaggedItem)
class Meta:
unique_together = ("url", "user")
verbose_name = 'bookmark'
verbose_name_plural = 'bookmarks'
def __str__(self):
return '%s (%s)' % (self.title, self.user)
My serializers:
from rest_framework import serializers
from rest_framework.pagination import PageNumberPagination
from market_builder.serializers import HATEOASMixin
from . import models
class BookmarkPagination(PageNumberPagination):
"""Bookmark pagination serialization."""
page_size = 10
page_size_query_param = 'page_size'
class TaggedObjectRelatedField(serializers.RelatedField):
"""
Serialize bookmark instances using a bookmark serializer.
"""
def to_representation(self, value):
if isinstance(value, models.Bookmark):
serializer = BookmarkSerializer(value)
else:
raise Exception('Unexcepted type of tagged object')
return serializer.data
class TaggedItemSerializer(serializers.ModelSerializer):
"""Tagged Item serialization."""
class Meta:
model = models.TaggedItem
fields = [
'tag_name',
'user_created',
'object_id',
]
class BookmarkSerializer(HATEOASMixin, serializers.ModelSerializer):
"""Bookmark serialization."""
links = serializers.SerializerMethodField()
tags = TaggedItemSerializer(many=True)
class Meta:
model = models.Bookmark
fields = [
'id',
'url',
'title',
'description',
'created',
'modified',
'tags',
'links',
]
def get_links(self, bookmark):
links = super().get_links(bookmark)
return links
:
from django.contrib import admin
from django.contrib.contenttypes import admin as cadmin
from .models import Bookmark, TaggedItem
class TaggedItemInline(cadmin.GenericTabularInline):
model = TaggedItem
class BookmarkAdmin(admin.ModelAdmin):
list_display = ('title', 'url', 'user', )
list_filter = ('user', )
search_fields = ['url', 'title']
inlines = [
TaggedItemInline,
]
class TaggedItemAdmin(admin.ModelAdmin):
list_display = ('tag_name', )
admin.site.register(Bookmark, BookmarkAdmin)
admin.site.register(TaggedItem, TaggedItemAdmin)