Change structure of JSON data for API POST request with Django - json

I have a Django REST API endpoint with this structure, that I need to post to an external API:
{
"body": [
"...",
"...",
"...",
],
"title": [
"...",
"...",
"...",
],
"id": [
"...",
"...",
"...",
]
}
The first item under 'body' goes with the first under 'title' and 'id', and so forth.
The problem I'm having is that the API in question expects JSON data with the following structure:
{
"texts": [
{
"body": "...",
"title": "...",
"id": "..."
},
{
"body": "...",
"title": "...",
"id": "..."
},
{
"body": "...",
"title": "...",
"id": "..."
},
],
"language": "EN",
}
And I can't figure out how have my endpoint mirror that structure, with the bodies, titles, and ids grouped together, those groupings nested under texts, and with the language parameter appended at the end.
The serializer I'm using in my views.py looks as follows:
class MyReasonsSerializer(serializers.Serializer):
body = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
id = serializers.SerializerMethodField()
def get_body(self, obj):
return obj.reasons.order_by('transaction_date').values_list('body', flat=True)
def get_title(self, obj):
return obj.reasons.order_by('transaction_date').values_list('title', flat=True)
def get_id(self, obj):
return obj.reasons.order_by('transaction_date').values_list('transaction_date', flat=True)
class ReasonsData(RetrieveAPIView):
queryset = Market.objects.all().prefetch_related('reasons')
authentication_classes = []
permission_classes = []
serializer_class = MyReasonsSerializer
Thanks in advance for any advice!
EDIT:
Here are the models:
class Market(models.Model):
title = models.CharField(max_length=50, default="")
current_price = models.DecimalField(max_digits=5, decimal_places=2, default=0.50)
description = models.TextField(default="")
...
language = models.CharField(max_length=2, default="EN")
def __str__(self):
return self.title[:50]
class Reason(models.Model):
user_id = models.ForeignKey('users.CustomUser',
on_delete=models.CASCADE,
related_name='user_reasons',
default=None)
market = models.ForeignKey(
Market,
on_delete=models.CASCADE,
related_name='reasons',
default=None)
...
valence = models.CharField(max_length=11, default="")
title = models.TextField(default="")
body = models.TextField(default="")
def __str__(self):
return str(self.title)

I would structure it like this... (its hard to know exactly without seeing the models and trying it out)
class ReasonSerializer(serializers.ModelSerializer):
class Meta:
model = Reason
fields = ("id", "body", "title")
class MarketSerializer(serializers.Serializer):
texts = ReasonSerializer(many=True, source="reasons")
language = serializers.CharField()
class Meta:
model = Market
class ReasonsData(RetrieveAPIView):
queryset = Market.objects.all()
authentication_classes = []
permission_classes = []
serializer_class = MarketSerializer
def get_queryset(self):
qs = super().get_queryset()
# filter queryset by valence if passed as a query param
# ?valence=something
valence = self.request.query_params.get("valence", None)
if valence is not None:
qs = qs.filter(reasons__valence=valence)
return qs

Related

Custom Response to display the data in list of JSON using django

models.py
class Project(models.Model):
project_id = models.CharField(max_length=50,default=uuid.uuid4, editable=False, unique=True, primary_key=True)
org = models.ForeignKey(Organisation, on_delete=models.CASCADE, related_name='org_project',null=True)
product = models.ManyToManyField(Product,related_name='product_project')
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='client_project')
project_name = models.CharField(unique=True,max_length=100)
project_code = models.CharField(max_length=20)
project_cost = models.IntegerField(null=True)
currency_type = models.CharField(max_length=100, choices=CURRENCY_CHOICES, default='Indian Rupee')
project_head = models.ForeignKey(User_Master, on_delete=models.CASCADE, related_name='project_head',null=True)
project_manager = models.ForeignKey(User_Master, on_delete=models.CASCADE, related_name='project_manager',null=True)
project_user = models.ManyToManyField(User_Master,related_name='project_user')
description = models.TextField(max_length=500)
start_date = models.DateField()
end_date = models.DateField()
techstack = models.ManyToManyField(Techstack,related_name='techstack_project')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.IntegerField(default=0, choices=STATUS_CHOICES)
views.py
from djmoney.settings import CURRENCY_CHOICES
class CurrencyList(APIView):
renderer_classes = (CustomRenderer,)
def get(self, request, *args, **kwargs):
return Response(CURRENCY_CHOICES, status=status.HTTP_200_OK)
I was Trying to get the Currency code list in a response so that the data can be sent to the frontend as a dropdown list.
When I Used the above django money package I am getting an response as
{
"status": "success",
"code": 200,
"data": [
[
"XUA",
"ADB Unit of Account"
],
[
"AFN",
"Afghan Afghani"
],
[
"AFA",
"Afghan Afghani (1927–2002)"
],
....
],
"message": null
}
But I need to Get the response as list of json inside the data not as the list of arrays,
{
"status": "success",
"code": 200,
"data": [
{
"shortname": "XUA",
"fullname": "ADB Unit of Account"
},
{
"shortname":"AFN",
"fullname":"Afghan Afghani"
},
{
"shortname":"AFA",
"fullname":"Afghan Afghani (1927–2002)"
},
....
],
"message": null
}
Is it possible to modify the response for this package? or is there any other way to achieve the end goal response by any other method?
You just need to adjust your response in the following way:
from djmoney.settings import CURRENCY_CHOICES
class CurrencyList(APIView):
renderer_classes = (CustomRenderer,)
def get(self, request, *args, **kwargs):
return Response(
[{'shortname': short, 'fullname': full} for short, full in CURRENCY_CHOICES],
status=status.HTTP_200_OK,
)
try this
from djmoney.settings import CURRENCY_CHOICES
class CurrencyList(APIView):
renderer_classes = (CustomRenderer,)
def get(self, request, *args, **kwargs):
return Response([dict(zip(['shortname', 'fullname'], c)) for c in CURRENCY_CHOICES], status=status.HTTP_200_OK)
python console
>>> data = [
... [
... "XUA",
... "ADB Unit of Account"
... ],
... [
... "AFN",
... "Afghan Afghani"
... ],
... [
... "AFA",
... "Afghan Afghani (1927–2002)"
... ]
]
>>>
>>> [dict(zip(['shortname', 'fullname'], c)) for c in data ]
[{'shortname': 'XUA', 'fullname': 'ADB Unit of Account'}, {'shortname': 'AFN', 'fullname': 'Afghan Afghani'}, {'shortname': 'AFA', 'fullname': 'Afghan Afghani (1927–2002)'}]

Django Rest Framework - How to get the json response in a way, so that it is easier to access in frontend?

Hey guys I have this serializer to get the list of pending users,
class UserInfo(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'username',]
class PendingRequestSerializer(serializers.ModelSerializer):
other_user = UserInfo(read_only=True)
class Meta:
model = PendingRequest
fields = ['other_user', ]
views.py
class PendingRequestListApiView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, *args, **kwargs):
user = PendingRequest.objects.filter(user=self.request.user)
serializer = PendingRequestSerializer(user, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
I am getting the json response like this.
[
{
"other_user": {
"id": 8,
"username": "testuser5"
}
},
{
"other_user": {
"id": 4,
"username": "testuser2"
}
}
]
I want the json response to look like this instead.
"results": [
{
"id": 4,
"username": "testuser2",
},
{
"id": 8,
"username": "testuser5",
}
]
That is instead of having the user information in separate other_user, is it possible to combine it like it is in the second response?
Thanks
You can override to_representation() method of PendingRequestSerializer to return the other_user value
class PendingRequestSerializer(serializers.ModelSerializer):
class Meta:
model = PendingRequest
def to_representation(self, instance):
return UserInfo(instance.other_user).data

Parsing static json file and save values to Django Database/model

I have json file in my static folder in my django project. And I want to save the data from json file to my Django Database.
This is my model.py
from django.db import models
class Coming_Soon(models.Model):
movie_id = models.CharField(primary_key=True, max_length=11)
movie_title = models.TextField(blank=True, max_length=100)
image_url = models.TextField(blank=True)
synopsis = models.TextField(blank=True)
rating = models.TextField(default="MTRCB rating not yet available")
cast = models.TextField(blank=True)
release_date = models.TextField()
this is sample of my json file
{
"results": [
{
"rating": "PG",
"cast": [
"Jeremy Ray Taylor",
"Gerard Butler",
"Abbie Cornish"
],
"synopsis": "some synopsis",
"movie_title": "(3D/4DX) GEOSTORM",
"image_url": "some url",
"id": "8595"
},
{
"rating": "PG",
"cast": [
"Jeremy Ray Taylor",
"Gerard Butler",
"Abbie Cornish"
],
"synopsis": "some synopsis",
"movie_title": "(ATMOS) GEOSTORM",
"image_url": "some url",
"id": "8604"
}
]
}
what should I write on my view so that I can save those data into my django database? This is my views.py:
def polls(request):
ROOT_FILE = STATIC_ROOT + '/polls/coming_soon.json'
json_data = open(ROOT_FILE)
json_load = json.load(json_data)
with open(ROOT_FILE, 'r') as data:
parsed_json = json.load(data)
for result in parsed_json['results']:
# HOW CAN I SAVE DATA INTO DATABASE??
I really don't have any idea about getting those file into my database. Thank you.
You can create obj like this
from .models import Coming_Soon
def polls(request):
ROOT_FILE = STATIC_ROOT + '/polls/coming_soon.json'
json_data = open(ROOT_FILE)
json_load = json.load(json_data)
with open(ROOT_FILE, 'r') as data:
parsed_json = json.load(data)
for result in parsed_json['results']:
Coming_Soon.objects.create(
movie_id = result['id'],
movie_title = result['movie_title'],
image_url=result['image_url'],
synopsis = result['synopsis'],
)

Formatting JSON in Serializer - Django REST

I am new to Django and Django-REST and I was tasked to create a serializer.
The output of my serializer looks like this:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "a",
"description": "a",
"price": "1.00",
"images": [
{
"image_addr": "http://127.0.0.1:8000/media/products/Screenshot_from_2018-05-16_15-07-34.png",
"product": 1
},
{
"image_addr": "http://127.0.0.1:8000/media/products/Screenshot_from_2018-05-16_16-42-55.png",
"product": 1
}
]
}
]
}
How can i tweak my serializer in a way that my output would look like this:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "a",
"description": "a",
"price": "1.00",
"images": [
"http://127.0.0.1:8000/media/products/Screenshot_from_2018-05-16_15-07-34.png",
"http://127.0.0.1:8000/media/products/Screenshot_from_2018-05-16_16-42-55.png"
]
}
]
}
The serializers that I am using are:
class ProductImageSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = ('image_addr', 'product')
and
class ProductSerializer(serializers.ModelSerializer):
images = ProductImageSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = ('id', 'name', 'description', 'price','images')
My models used are:
class ProductImage(models.Model):
image_addr = models.FileField(upload_to='products/',null=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
and
class Product(models.Model):
name = models.CharField(max_length=150)
price = models.DecimalField(max_digits=9, decimal_places=2)
product_count = models.IntegerField(blank=True, default=0, validators=[MinValueValidator(0)])
description = models.TextField()
category = models.ManyToManyField(Category)
objects = ProductManager()
My view used is:
class CategoryProductList(generics.ListAPIView):
serializer_class = ProductSerializer
def get_queryset(self):
queryset = Product.objects.filter(category__id=self.kwargs['pk'])
return queryset
You can use SerializerMethodField for your purpose. Change your ProductSerializer as below
class ProductSerializer(serializers.ModelSerializer):
images = serializers.SerializerMethodField(read_only=True, source='images')
def get_images(self, model):
return model.images.values_list('image_addr', flat=True)
class Meta:
model = Product
fields = ('id', 'name', 'description', 'price', 'images')

How to move a serializer.data into custom Instance (field) with Django Rest Framework

I am able to get the JSON result below using django-rest-framework.
{
"id": 1,
"fieldA": 1,
"fieldB": 100
},
{
"id": 2,
"fieldA": 2,
"fieldB": 101
},
{
"id": 3,
"fieldA": 1,
"fieldB": 101
}
I just want to change the structure to this.
{
"typeA":
{
"id": 1,
"fieldA": 1,
"fieldB": 100
}
},
{
"typeB":
{
"id": 2,
"fieldA": 2,
"fieldB": 100,
},
{
"id": 3,
"fieldA": 1,
"fieldB": 101,
}
}
typeA includes objects where fieldB == 100 and typeB includes objects where fieldB == 101.
I can handle the results using like Objects.filter() at get_query_set() in views.py. So you don't need to care about it.
The key of my question is how I can insert my customized field name and move the results to its child level. Currently, I guess the solution would be related to create() and update() functions from building a serializer. Please give any tips or hints.
Here's my model.py for more information.
class Results(models.Model):
fieldA = models.ForeignKey(Model)
fieldB = models.ForeignKey(EplTeams, null=True)
views.py
class ResultsView(generics.ListAPIView):
serializer_class = ResultSerializer
def get_queryset(self):
typeA = Results.objects.filter( fieldB=100 )
typeB = Results.objects.filter( fieldB=101 )
queryset = list( itertools.chain(typeA, typeB) )
return queryset
serializers.py
class ResultSerializer(serializers.ModelSerializer):
class Meta:
model = Results
You can do this by using ListSerializer
In your serializers.py:
class CustomListSerializer(serializers.ListSerializer):
def to_representation(self, data):
resdata = []
data1 = data.filter(fieldB=100)
data2 = data.filter(fieldB=101)
resdata.append({'typeA': super(CustomListSerializer, self).to_representation(data1)})
resdata.append({'typeB': super(CustomListSerializer, self).to_representation(data2)})
return resdata
class ResultSerializer(serializers.ModelSerializer):
class Meta:
model = Results
list_serializer_class = CustomListSerializer
Learn more about ListSerializer here