Django-RestFramework Custom Seriliazation - django

I have problem in custom serialization and I look in documentation for hours, but I couldn't figure out what I will do. I have nested serializers object like below but I want to have non-nested object, can anyone help me with this?
Nested Object:
{
"id": 1,
"adDate": "20-08-2016",
"price": "30.50",
"city": "Istanbul",
"latitude": "28.987509",
"longitude": "41.040353",
"isPublished": true,
"book": {
"id": 1,
"bookName": "GameOfThrones",
"category": "Adventure",
"photo": "http://localhost:8000/media/advert_images/game_of_thrones.jpg",
"description": "Adventure Book",
"author": "Emre Yavuz",
"language": "Sangridce",
"publicationDate": "2023",
"publisher": "Deu_Yapim",
"edition": "22",
"page_number": 900
}
}
Non-Nested Object:
{
"id": 1,
"adDate": "20-08-2016",
"price": "30.50",
"city": "Istanbul",
"latitude": "28.987509",
"longitude": "41.040353",
"isPublished": true,
"bookName": "GameOfThrones",
"category": "Adventure",
"photo": "http://localhost:8000/media/advert_images/game_of_thrones.jpg",
"description": "Adventure Book",
"author": "Emre Yavuz",
"language": "Sangridce",
"publicationDate": "2023",
"publisher": "Deu_Yapim",
"edition": "22",
"page_number": 900
}
My Serializer Class:
class AdvertSerializer(serializers.ModelSerializer):
book = BookSerializer()
class Meta(object):
model = Advert
fields = ('id', 'adDate', 'price',"city","latitude","longitude","isPublished",'book','seller')
depth = 2
.
class BookSerializer(serializers.ModelSerializer):
photo = serializers.ImageField(max_length=None,use_url=True)
class Meta(object):
model = Book

I don't know why you would prefer a non-nested representation but in order to archive that, you need to specify book fields, one by one on your serializer using the source field attribute.
class AdvertSerializer(serializers.ModelSerializer):
book_name = serializer.CharField(source='book.bookName')
description = serializer.CharField(source='book.description')
# add the rest of the book fields in that way
class Meta(object):
model = Advert
fields = ('id', 'adDate', 'price',"city","latitude","longitude","isPublished",'book','seller')

Related

Fields of Nested serializers

In my nested serializer i want to show only movie name and exclude the other fields
[
{
"id": 2,
"watchlist": [
{
"id": 3,
"platform": "Netflix",
"title": "Martian",
"storyline": "A lost astronaut of Mars survived",
"average_rating": 4.1,
"total_rating": 2,
"active": true,
"created": "2022-04-05T05:37:35.902464Z"
},
{
"id": 4,
"platform": "Netflix",
"title": "Intersteller",
"storyline": "Finding new home",
"average_rating": 0.0,
"total_rating": 0,
"active": true,
"created": "2022-04-06T04:52:04.665202Z"
},
{
"id": 5,
"platform": "Netflix",
"title": "Shutter Island",
"storyline": "Psycopath",
"average_rating": 0.0,
"total_rating": 0,
"active": true,
"created": "2022-04-06T04:52:51.626397Z"
}
],
"platform": "Netflix",
"about": "streaming, series and many more",
"website": "https://www.netflix.com"
},
]
In the above data,
"watchlist" is the nested serializer data
i want to show only "title"
and exclude all other data
I have included WatchListSerializer class as "nested" serializer in the StreamPlatformSerializer class.
I want that on "title should be shown, rest other fields should be excluded from nested serializer part"
below is the code...
class WatchListSerializer(serializers.ModelSerializer):
# reviews = ReviewSerializer(many=True, read_only=True)
platform = serializers.CharField(source='platform.platform')
class Meta:
model = WatchList
fields = '__all__'
# def to_representation(self, value):
# return value.title
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = WatchListSerializer(many=True, read_only=True)
# watchlist = serializers.CharField(source='watchlist.title')
class Meta:
model = StreamPlatform
fields = '__all__'
after removing other fields it should look like this as below..
[
{
"id": 2,
"watchlist": [
{
"title": "Martian"
},
{
"title": "Intersteller",
},
{
"title": "Shutter Island",
],
"platform": "Netflix",
"about": "streaming, series and many more",
"website": "https://www.netflix.com"
},
]
There may be two approaches for this thing
First Approach:
class WatchListSerializer(serializers.ModelSerializer):
# reviews = ReviewSerializer(many=True, read_only=True)
class Meta:
model = WatchList
fields = ("title",)
# def to_representation(self, value):
# return value.title
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = WatchListSerializer(many=True, read_only=True)
# watchlist = serializers.CharField(source='watchlist.title')
class Meta:
model = StreamPlatform
fields = '__all__'
With this approach the downside will be that WatchListSerializer can only be used in this serializer not as a standalone serializer.
For second approach I need to see your models. It would be like
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = serializers.SerializerMethodField("get_watchlist")
class Meta:
model = StreamPlatform
fields = '__all__' # include watchlist as well
def get_watchlist(self, obj):
return obj.watchlist.all().values('title')
I like this approach personally.

How to change DRF API SlugRelatedField Response template

I have managed to create a working model with 2 different serializers, depending on what we are doing. Right now, ReadTitleSerializer returns the below JSON object:
[
{
"id": 1,
"category": {
"id": 1,
"name": "Movies",
"slug": "movie"
},
"genres": [
{
"id": 1,
"name": "Drama",
"slug": "drama"
}
],
"name": "Drama Llama",
"year": "1998-02-02",
"description": null,
"rating": null
}
]
And this is the response from WriteTitleSerializer:
{
"id": 1,
"category": "movie",
"genres": [
"drama"
],
"name": "Drama Llama",
"year": "1998-02-02",
"description": null,
"rating": null
}
How can I make WriteTitleSerializer respond similarly to ReadTitleSerializer? I am using SlugRelatedField in WriteTitleSerializer because the JSON input should be a list of slugs.
Input JSON
{
"name": "Drama Llama",
"year": "1998-02-02",
"category": "movie",
"genres": [
"drama"
]
}
serializers.py
class ReadTitleSerializer(serializers.ModelSerializer):
category = CategorySerializer()
genres = GenreSerializer(many=True)
class Meta:
model = Title
fields = '__all__'
read_only_fields = ('category', 'genres')
class WriteTitleSerializer(serializers.ModelSerializer):
category = SlugRelatedField(
slug_field='slug',
queryset=Category.objects.all(),
required=True
)
genres = SlugRelatedField(
slug_field='slug',
queryset=Genre.objects.all(),
many=True,
required=True
)
class Meta:
model = Title
fields = '__all__'

How to serialize ForeignKey in Django rest?

I'm using the latest version of django rest framework.
I have this model:
class Subscriptions(models.Model):
subs_list = models.ForeignKey(SubsList, verbose_name='Subscription list', on_delete=models.CASCADE, related_name='subs_list') # идентификатор подписного листа
subscriber = models.ForeignKey(Subscribers, verbose_name='Subscriber', on_delete=models.CASCADE) # идентификатор подписчика
created_date = models.DateTimeField(verbose_name='Created date', auto_now=True) # дата добавления подписчика в подписной лист
deleted = models.NullBooleanField(verbose_name='Deleted') # True-удален из подписного листа, False/null-в подписном листе
How do I serialize it? The main question is how to serialize ForeignKey, that would be associated with the query related data, i.e. NOT:
"id": 29,
"created_date": "2018-03-01T14:28:41.237742Z",
"deleted": false,
"subs_list": 1,
"subscriber": 1
but like this
"id": 29,
"subs_list": {
"id": 1,
"uuid": "d183bab7-af26-48f8-9ef5-ea48e09a95a9",
"name": "TEST",
"description": "TEST",
"created_date": "2018-03-01T13:15:18.808709Z",
"deleted": null,
"user": 6
},
"subscriber": {
"id": 1,
"bot_id": "1",
"name_messenger": "11",
"username": "1",
"first_name": "1",
"last_name": "1",
"created_date": "9999-03-01T16:47:51.440000Z",
"subscribed": true,
"chat_bot": "1",
"phone": "1",
"user": 1
},
"created_date": "2018-03-01T14:28:41.237742Z",
"deleted": false
I have such a serializer:
...
class SubscriptionsSerializer(serializers.ModelSerializer):
subs_list = SubsListSerializer(read_only=True)
subscriber = SubscribersSerializer(read_only=True)
class Meta:
model = Subscriptions
fields = '__all__'
When get requests everything is ok, but how to update and add data is not clear, error:
IntegrityError at /subscriptions/subscriptions/
null value in column "subs_list_id" violates not-null constraint
DETAIL: Failing row contains (41, 2018-03-01 16:10:02.383625+00, f, null, null).
I struggle with this problem for a very long time, read all the related answers, but there is no clarity.
remove read_only=True and change your serializer.py as below
class SubscriptionsSerializer(serializers.ModelSerializer):
subs_list = SubsListSerializer()
subscriber = SubscribersSerializer()
class Meta:
model = Subscriptions
fields = '__all__'
def create(self, validated_data):
sub_lst = SubsList.objects.create(**validated_data['subs_list'])
subscriber = Subscribers.objects.create(**validated_data['subscriber'])
return Subscriptions.objects.create(subs_list=sub_lst, subscriber=subscriber, deleted=validated_data['deleted'])
And your creation payload will be like this,
{
"subs_list": {
"uuid": "d183bab7-af26-48f8-9ef5-ea48e09a95a9",
"name": "TEST",
"description": "TEST",
# etc etc
},
"subscriber": {
"bot_id": "1",
"name_messenger": "11",
"username": "1",
# etc etc
},
"deleted": null
}
I think you have several ForeignKey relationships are there, so you have to map those things carefully in create()
Similar way, you can override update() and which can be used while API updation too.
See this official doc for more info

Django REST Meta data for M2M missing

On my json output I don't seem to get key value pairs on my m2m field attribute_answers. see the code below. How to I add in the attribute_answers fields?
json
{
"id": 20,
"name": "Jake",
"active": true,
"type": {
"id": 1,
"name": "Human",
"active": true,
"created": "2013-02-12T13:31:06Z",
"modified": null
},
"user": "jason",
"attribute_answers": [
1,
2
]
}
Serializer
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field='username')
attribute_answers = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Profile
depth = 2
fields = ('id', 'name', 'active', 'type', 'user', 'attribute_answers')
def restore_object(self, attrs, instance=None):
"""
Create or update a new snippet instance.
"""
if instance:
# Update existing instance
instance.name = attrs.get('name', instance.name)
instance.active = attrs.get('active', instance.active)
instance.type = attrs.get('type', instance.type)
instance.attribute_answers = attrs.get('attribute_answers', instance.attribute_answers)
return instance
# Create new instance
return Profile(**attrs)
If I understand your question correctly, you want a Nested Relationship. In your ProfileSerializer, you'll want:
attribute_answers = AttributeAnswerSerializer(many=True)
This will display all the attributes of each associated attribute_answer model and give you something like:
{
"id": 20,
"name": "Jake",
"active": true,
"type": {
"id": 1,
"name": "Human",
"active": true,
"created": "2013-02-12T13:31:06Z",
"modified": null
},
"user": "jason",
"attribute_answers": [
{"id": 1, "foo": "bar"},
{"id": 2, "foo": "bar2"}
]
}

Django Tastypie - How to get related Resources with a single request

Suppose following Resources are given:
class RecipeResource(ModelResource):
ingredients = fields.ToManyField(IngredientResource, 'ingredients')
class Meta:
queryset = Recipe.objects.all()
resource_name = "recipe"
fields = ['id', 'title', 'description',]
class IngredientResource(ModelResource):
recipe = fields.ToOneField(RecipeResource, 'recipe')
class Meta:
queryset = Ingredient.objects.all()
resource_name = "ingredient"
fields = ['id', 'ingredient',]
A HTTP Request to myhost.com/api/v1/recipe/?format=json gives following response:
{
"meta":
{
...
},
"objects":
[
{
"description": "Some Description",
"id": "1",
"ingredients":
[
"/api/v1/ingredient/1/"
],
"resource_uri": "/api/v1/recipe/11/",
"title": "MyRecipe",
}
]
}
So far so good.
But now, I would like to exchange the ingredients resource_uri ("/api/v1/ingredient/1/") with something like that:
{
"id": "1",
"ingredient": "Garlic",
"recipe": "/api/v1/recipe/1/",
"resource_uri": "/api/v1/ingredient/1/",
}
To get following response:
{
"meta":
{
...
},
"objects":
[
{
"description": "Some Description",
"id": "1",
"ingredients":
[
{
"id": "1",
"ingredient": "Garlic",
"recipe": "/api/v1/recipe/1/",
"resource_uri": "/api/v1/ingredient/1/",
}
],
"resource_uri": "/api/v1/recipe/11/",
"title": "MyRecipe",
}
]
}
The answer is the attribute full=True:
ingredients = fields.ToManyField('mezzanine_recipes.api.IngredientResource', 'ingredients', full=True)