Django Rest Framework - Get full related objects in list - python

I'm rather new to Django Rest Framework and I'm trying to use DRF to to serialize a list of (related) objects.
I have the following models:
class Answer(models.Model):
value = models.CharField(max_length=128)
class User(models.Model):
name = models.CharField(max_length=128)
age = models.PositiveIntegerField()
class UserAnswer(models.Model):
user = models.ForeignKey(User)
answer = models.ForeignKey(Answer)
And the result I'm trying to get is in this form:
[
{
"name": "myName1",
"answers": [
{
"value": "myFirstAnswer"
},
{
"value": "mySecondAnswer"
},
{
"value": "myThirdAnswer"
},
]
},
{
"name": "myName2",
"answers": [
{
"value": "myFirstAnswer"
},
{
"value": "mySecondAnswer"
},
{
"value": "myThirdAnswer"
},
]
}
]
I'm trying to do it this way now:
class UserAnswerSerializer(serializers.ModelSerializer):
answers = AllUserAnswersSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ('name', 'answers')
But then I get the following result:
[
{
"name": "myName1"
},
{
"name": "myName2"
}
]
And when I try to do it this way:
class UserAnswerSerializer(serializers.ModelSerializer):
answers = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = User
fields = ('name', 'answers')
Then i get the following result (an example again):
[
{
"name": "myName1",
"answers": [
1,
2,
3
]
},
{
"name": "myName2",
"answers": [
4,
5,
6
]
}
]
I'm having a hard time making this work, hope someone can show me how to convert the Primary Key's to actual objects!
Thanks!

Remove the explicit definition of the answers field in your serializer and add depth=1. It should look like this:
class UserAnswerSerializer(serializers.ModelSerializer):
class Meta:
depth = 1
model = User
fields = ('name', 'answers')
Info about depth: http://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization

Related

ManyToManyField value in Django REST Framework

So when I am routing to api/ to view my models I am not seeing what I expected to see.
I wanted to see the names of the strats that I grouped in Strat_Basket model in the variable basket but instead I see their ids which is generated by DJANGO automatically.
I want to see the names rather than numbers in the strat_basket view. It is more informative that's why.
models.py
class Strats(models.Model):
name = models.CharField(max_length=64)
class Strats_Basket(models.Model):
name = models.CharField(max_length=64)
basket = models.ManyToManyField(Strats, blank=True, related_name='list')
serializers.py:
class StratsSerializer(serializers.ModelSerializer):
class Meta:
model = Strats
fields = ('id', 'name')
class Strats_BasketSerializer(serializers.ModelSerializer):
class Meta:
model = Strats_Basket
fields = ('id', 'name', 'basket')
views.py:
class StratsView(viewsets.ModelViewSet):
serializer_class = StratsSerializer
queryset = Strats.objects.all()
class Strats_BasketView(viewsets.ModelViewSet):
serializer_class = Strats_BasketSerializer
queryset = Strats_Basket.objects.all()
urls.py:
router = routers.DefaultRouter()
router.register(r'strats', views.StratsView, 'strats')
router.register(r'strats_basket', views.Strats_BasketView, 'strats_basket')
API OUTPUT:
strats:
[
{
"id": 1,
"name": "strat1"
},
{
"id": 2,
"name": "strat2"
},
{
"id": 3,
"name": "strat3"
},
{
"id": 4,
"name": "strat4"
},
{
"id": 5,
"name": "strat5"
},
{
"id": 6,
"name": "strat6"
}
]
strats_basket:
Instead of 1,2,4 I want to see strat1, strat2, strat4.
[
{
"id": 1,
"name": "Basket 1",
"basket": [
1,
2,
4
]
},
{
"id": 2,
"name": "Basket 2",
"basket": [
3,
5,
6
]
}
]
You can use SerializerMethodField and inside the method return names list using values_list with flat=True
class Strats_BasketSerializer(serializers.ModelSerializer):
basket = serializers.SerializerMethodField()
def get_basket(self, obj):
return obj.basket.all().values_list('name', flat=True)
class Meta:
model = Strats_Basket
fields = ('id', 'name', 'basket')

RelatedObjectDoesNotExist when nesting data in DRF

I'm trying to serialize a model with nested data for its relationships. The data is returned properly in a GET request but when trying to POST data the following error is returned: api.models.Narration.narrative.RelatedObjectDoesNotExist: Narration has no narrative. I have no interest in POSTing nested data, it only needs to be returned in the GET requests and PKs can be used everywhere else. I have tried to using Meta.depth as well as defining the fields manually, both of which return the same exception. Code is below, any help is appreciated.
# serializers.py
class NarrationSerializer(ModelSerializer):
narrative = NarrativeSerializer(read_only=True)
settings = MapSettingsSerializer(read_only=True)
attached_events = CachedDataSerializer(many=True, read_only=True)
class Meta:
model = Narration
fields = "__all__"
# depth = 1 [also doesn't work]
# models.py
class Narration(OrderedModel):
narrative = models.ForeignKey(Narrative, on_delete=models.CASCADE)
title = models.TextField()
description = models.TextField()
date_label = models.CharField(max_length=100)
map_datetime = models.DateTimeField()
attached_events = models.ManyToManyField(CachedData)
img = models.URLField(blank=True, null=True)
video = models.URLField(blank=True, null=True)
settings = models.ForeignKey(MapSettings, on_delete=models.CASCADE)
order_with_respect_to = "narrative"
# views.py
class NarrationViewSet(viewsets.ModelViewSet):
queryset = Narration.objects.all()
serializer_class = NarrationSerializer
POSTed nested data (using PKs results in same exception):
{
"title": "cvxcv",
"description": "cxvxcv",
"date_label": "test",
"map_datetime": "0002-01-01T00:00:00Z",
"img": "",
"video": "",
"narrative": {
"author": "Test Author",
"title": "Test Narrative",
"description": "This is a test narrative.",
"tags": [
"test",
"tags"
]
},
"settings": {
"bbox": {
"type": "MultiPoint",
"coordinates": [
[
0,
0
],
[
1,
1
]
]
},
"zoom_min": 1,
"zoom_max": 12
},
"attached_events": [
{
"event_type": 178561,
"wikidata_id": 1,
"location": {
"type": "Point",
"coordinates": [
0,
0
]
},
"date": "0001-01-01",
"rank": 830700
}
]
}

How to convert to a full JSON

How to convert to JSON type format.
Instead of the object ID you need to get full information about it.
From such
[
{
"title": "scenario factory - sump",
"scenario_pipeline": [
{
"pipeline": 11
}
],
"scenario_exist": [
{
"factory": 43
},
{
"factory": 44
}
]
}
]
To such a
[
{
"title": "scenario factory - sump",
"scenario_pipeline": [
{
"title": "factory - sump",
"percent": 11,
"start_point": [
57.332892983304895,
36.40013349999995
],
"end_point": [
51.829824506973154,
43.43138349999996
],
"point": []
}
],
"scenario_exist": [
{
"id": 43,
"title": "factory",
"choice": "Factory",
"address": [
57.332892983304895,
36.40013349999995
]
},
{
"id": 44,
"title": "sump",
"choice": "Sump",
"address": [
51.829824506973154,
43.43138349999996
]
}
]
}
]
My models.py
The basic model of Scenario, the two remaining inline
class Scenario(models.Model):
title = models.CharField(max_length=200)
class ScenarioExist(models.Model):
scenario = models.ForeignKey('Scenario', related_name='scenario_exist', on_delete=models.CASCADE)
factory = models.ForeignKey('factory.Factory', related_name='factory', on_delete=models.CASCADE)
class PipelineTwo(models.Model):
scenario = models.ForeignKey('Scenario', related_name='scenario_pipeline', on_delete=models.CASCADE)
pipeline = models.ForeignKey('pipeline.Pipeline', null = True, on_delete=models.CASCADE, related_name = 'point_two')
If you want to show the models to which the fields are accessed, I will show.
My serializes.py
class PipelineTwoSerializer(serializers.ModelSerializer):
class Meta:
model = PipelineTwo
fields = ['pipeline']
class ScenarioExistSerializer(serializers.ModelSerializer):
class Meta:
model = ScenarioExist
fields = ['factory']
class ScenarioSerializer(serializers.ModelSerializer):
scenario_pipeline = PipelineTwoSerializer(many=True)
scenario_exist = ScenarioExistSerializer(many=True)
class Meta:
model = Scenario
fields = ['title', 'scenario_pipeline', 'scenario_exist']
You are using nested serializers in your ScenarioSerializer; you need to do the same in your PipelineTwoSerializer to get the values from pipeline.Pipeline and in ScenarioExistSerializer for factory.Factory.

Django Rest Framework: Get related specific model field in serializer from another model

I'm trying to return a Response including data from 2 linked models, where I can get a specific field value from another model. The models are:
class Author(models.Model):
author = models.CharField(max_length=200)
author_created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('author_created',)
class Book(models.Model):
book_name = models.CharField(max_length=200)
author_name = models.ForeignKey(Author, on_delete=models.CASCADE)
book_created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('book_created',)
Serializers are:
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('id', 'author')
class BookSerializer(serializers.ModelSerializer):
name = AuthorSerializer(source='author_name')
class Meta:
model = Book
fields = ('id', 'book_name','name')
My response shows like this:
[
{
"id": 1,
"book_name": "Himu",
"name": {
"id": 1,
"author": "Humayun Ahmed"
}
},
{
"id": 2,
"book_name": "Shanta's family",
"name": {
"id": 2,
"author": "Jafar Iqbal"
}
}
]
But i want to show it like this:
[
{
"id": 1,
"book_name": "Himu",
"name": {
"author": "Humayun Ahmed"
}
},
{
"id": 2,
"book_name": "Shanta's family",
"name": {
"author": "Jafar Iqbal"
}
}
]
How can i get this output?
Try something like this name = AuthorSerializer(source='author_name.author')
Reference : http://www.django-rest-framework.org/api-guide/fields/#source

Django REST - How to create a non-model serializer?

Firstly I want to say I'm a newbie to Django.
I was wondering if is it possible to create a non-ModelSerializer which serialize existant model based serializers ?
In serializers.py, I already have this :
class MapSerializer(serializers.ModelSerializer):
class Meta:
model = Map
fields = ('id', 'name')
class GrenadeSerializer(serializers.ModelSerializer):
class Meta:
model = Grenade
fields = ('id', 'name')
I want here a new serializer which allows to display a JSON like that :
{
"maps": {
"map": [
{
"id": "1",
"name": "dust2"
},
{
"id": "2",
"name": "inferno"
}
]
},
"grenades": {
"grenade": [
{
"id": "1",
"name": "flashbang"
},
{
"id": "2",
"name": "smoke"
}
]
}}
I need something like this, even if I know the following structure isn't correct :
class MyNewSerializer(serializers.ModelSerializer):
maps = MapSerializer(many=True)
grenades = GrenadeSerializer(many=True)
class Meta:
field = ('maps', 'grenades')
Thanks in advance !

Categories