Reputation: 1972
I have model with generic foreign key and I want to serialize that model.
model.py
:
class AddressType(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type','object_id')
def __unicode__(self):
return u'%s' % str(self.content_type)
class AddressBook(TimeStampedModel):
class Meta:
db_table = 'address_book'
uuid = UUIDField(auto=True)
address_tag = models.CharField(null=True, blank=True, max_length=20)
# should be a generic foreign key
address_object_type = GenericRelation(AddressType)
address1 = models.CharField(
verbose_name='Address1',
max_length=200,
)
address2 = models.CharField(
verbose_name='Address2',
max_length=200,
)
serializer.py
:
class AddressBookSerializer(serializers.ModelSerializer):
class Meta:
model = AddressBook
fields = ('id','uuid','address_tag','address_object_type','address1','address2')
How can I serialize JSON on above model?
Upvotes: 12
Views: 10988
Reputation: 699
If your code is more structured, i.e. each app has its serializers.py, and serializer naming follows a convention (i.e. [ModelName]Serializer) you could use dynamic importing to avoid if ... elif ... else ...
logic with a benefit of loose coupling:
from django.utils.module_loading import import_string
class ContentObjectRelatedField(serializers.RelatedField):
"""
A custom field to serialize generic relations
"""
def to_representation(self, object):
object_app = object._meta.app_label
object_name = object._meta.object_name
serializer_module_path = f'{object_app}.serializers.{object_name}Serializer'
serializer_class = import_string(serializer_module_path)
return serializer_class(object).data
Upvotes: 2
Reputation: 535
I'd prefer use this third party (rest-framework-generic-relations) as also described in documentation.
from generic_relations.relations import GenericRelatedField
class TagSerializer(serializers.ModelSerializer):
"""
A `TaggedItem` serializer with a `GenericRelatedField` mapping all possible
models to their respective serializers.
"""
tagged_object = GenericRelatedField({
Bookmark: BookmarkSerializer(),
Note: NoteSerializer()
})
class Meta:
model = TaggedItem
fields = ('tag_name', 'tagged_object')
Upvotes: 10
Reputation: 558
This case is perfectly described in the documentation.
So if you want to serialize AddressType
you will need to implement something like this:
class ContentObjectRelatedField(serializers.RelatedField):
"""
A custom field to use for the `content_object` generic relationship.
"""
def to_representation(self, value):
"""
Serialize tagged objects to a simple textual representation.
"""
if isinstance(value, Bookmark):
return 'Bookmark: ' + value.url
elif isinstance(value, Note):
return 'Note: ' + value.text
raise Exception('Unexpected type of tagged object')
Where Bookmark
and Note
are objects which may be have associated contents.
If you want to serialize AddressBook
you can try doing something like this:
class AddressBookSerializer(serializers.ModelSerializer):
address_object_type = ContentObjectRelatedField()
class Meta:
model = AddressBook
fields = ('id','uuid','address_tag','address_object_type','address1','address2')
Upvotes: 16