I have model that looks like this:
class Category(models.Model): parentCategory = models.ForeignKey('self', blank=True, null=True, related_name='subcategories') name = models.CharField(max_length=200) description = models.CharField(max_length=500)
I managed to get flat json representation of all categories with serializer:
class CategorySerializer(serializers.HyperlinkedModelSerializer): parentCategory = serializers.PrimaryKeyRelatedField() subcategories = serializers.ManyRelatedField() class Meta: model = Category fields = ('parentCategory', 'name', 'description', 'subcategories')
Now what I want to do is for subcategories list to have inline json representation of subcategories instead of their ids. How would I do that with django-rest-framework? I tried to find it in documentation, but it seems incomplete.
Instead of using ManyRelatedField, use a nested serializer as your field:
class SubCategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ('name', 'description') class CategorySerializer(serializers.ModelSerializer): parentCategory = serializers.PrimaryKeyRelatedField() subcategories = serializers.SubCategorySerializer() class Meta: model = Category fields = ('parentCategory', 'name', 'description', 'subcategories')
If you want to deal with arbitrarily nested fields you should take a look at the customising the default fields part of the docs. You can't currently directly declare a serializer as a field on itself, but you can use these methods to override what fields are used by default.
class CategorySerializer(serializers.ModelSerializer): parentCategory = serializers.PrimaryKeyRelatedField() class Meta: model = Category fields = ('parentCategory', 'name', 'description', 'subcategories') def get_related_field(self, model_field): # Handles initializing the `subcategories` field return CategorySerializer()
Actually, as you've noted the above isn't quite right. This is a bit of a hack, but you might try adding the field in after the serializer is already declared.
class CategorySerializer(serializers.ModelSerializer): parentCategory = serializers.PrimaryKeyRelatedField() class Meta: model = Category fields = ('parentCategory', 'name', 'description', 'subcategories') CategorySerializer.base_fields['subcategories'] = CategorySerializer()
A mechanism of declaring recursive relationships is something that needs to be added.
Edit: Note that there is now a third-party package available that specifically deals with this kind of use-case. See djangorestframework-recursive.
@wjin's solution was working great for me until I upgraded to Django REST framework 3.0.0, which deprecates to_native. Here's my DRF 3.0 solution, which is a slight modification.
Say you have a model with a self-referential field, for example threaded comments in a property called "replies". You have a tree representation of this comment thread, and you want to serialize the tree
First, define your reusable RecursiveField class
class RecursiveField(serializers.Serializer): def to_representation(self, value): serializer = self.parent.parent.__class__(value, context=self.context) return serializer.data
Then, for your serializer, use the the RecursiveField to serialize the value of "replies"
class CommentSerializer(serializers.Serializer): replies = RecursiveField(many=True) class Meta: model = Comment fields = ('replies, ....)
Easy peasy, and you only need 4 lines of code for a re-usable solution.
NOTE: If your data structure is more complicated than a tree, like say a directed acyclic graph (FANCY!) then you could try @wjin's package -- see his solution. But I haven't had any problems with this solution for MPTTModel based trees.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With