Can someone advise me on how to deal with how to retrieve data such as this example
JSON:
[
{
"deviceid": 4,
"devicename": "###",
"device_measurment": {
"deviceid": 4,
"measurement": "31.8",
}
},
]
How is it right now:
[
{
"deviceid": 4,
"devicename": "###",
},
{
"deviceid": 4,
"measurement": "31.8",
},
]
I understand the problem and why I am getting such a response, but I cannot handle this problem via the serializer. at the moment, I have the following
Views
from itertools import chain
class RetrieveSpecificDevicesView(APIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = SpecificDeviceSerializer
def post(self, request):
if self.request.method == 'POST':
serializer = SpecificDeviceSerializer(data=request.data)
if serializer.is_valid():
obj1= Devices.objects.using('###').filter(deviceid=serializer.data.get("deviceid"))
obj2= Measurements.objects.using('###').filter(deviceid=serializer.data.get("deviceid"))
dats= chain(obj1, obj2)
data = serializers.serialize('json', dats)
return HttpResponse(data, content_type="application/json")
return JsonResponse(serializer.erorr, status=status.HTTP_201_CREATED)
Serializer
class SpecificDeviceSerializer(serializers.Serializer):
deviceid = serializers.CharField(required=True)
class MeasurmentsSerializer(serializers.ModelSerializer):
class Meta:
model = Measurements
fields = ('measurementid','measurement')
Models
enter image description here
Update:
I am trying to implement via serializer but something is going wrong:
Note: By wrong I mean => *Got AttributeError when attempting to get a value for field devicesname on serializer SpecificDeviceSerializer*.
Views
class RetrieveSpecificDevicesView(APIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = SpecificcDeviceSerializer
def post(self, request):
if self.request.method == 'POST':
data = self.serializer_class.get_device(self, obj=request.data)
user = SpecificDeviceSerializer(data)
return HttpResponse(user)
Serializers
class SpecificDeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Devices
fields = ( 'deviceid', 'devicename')
class SpecificcDeviceSerializer(serializers.ModelSerializer):
def get_device(self, obj):
device = Devices.objects.using('###').filter(deviceid=obj.get("deviceid"))
return device
class Meta:
model = Devices
fields = ( 'deviceid', 'devicename')
Solution:
Serializer
class SpecificDeviceSerializer(serializers.ModelSerializer):
measurments = serializers.SerializerMethodField()
def get_measurments(self, obj):
device_measurements = obj.measurment_details.last()
serializer = MeasurmentsSerializer(device_measurements)
return serializer.data
class Meta:
model = Devices
fields = ('devicename','measurments')
Views
class RetrieveSpecificDevicesView(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated]
serializer_class = SpecificDeviceSerializer
def get_queryset(self):
return Devices.objects.using('###').filter(deviceid=self.request.data.get("deviceid"))
JSON:
[
{
"devicename": "RTMU 3068",
"measurments": {
"measurementid": 2980465,
"measurement": "25.6"
}
}
]
Documentation: Best for this case
Related
I am new to django rest framework. I am getting the response data for not in the format I need. Any help will be appreciated. Below is my code.
model.py
class Price(models.Model):
ticker = models.CharField(max_length=15, null=False, blank=False)
price_date=models.DateField(null=False, blank=False)
daily_pe = models.FloatField(blank=True, null=True)
class Meta:
db_table= 'price'
unique_together = ('ticker', 'price_date')
def __str__(self):
return "%s %s %s " % (self.ticker, self.price_date, daily_pe)
serializers.py
class ChartSerilizer(serializers.ModelSerializer):
class Meta:
model = Price
fields = ['ticker', 'daily_pe']
view.py
class peChartViewSet(APIView):
def get(self, request):
queryset = Price.objects.all()
serializer = ChartSerilizer(queryset, many=True)
return JsonResponse(serializer.data, safe=False)
This is how am getting the response:
[
{
"ticker": "AAPL",
"daily_pe": 25.144920802584345
},
{
"ticker": "AAPL",
"daily_pe": 25.043920960028977
},
{
"ticker": "WMT",
"daily_pe": 24.930801136366966
},
{
"ticker": "WMT",
"daily_pe": 25.504480242081453
},
]
But I need the response like this :
[
{
"Ticker": "AAPL",
"daily_pe": [25.144920802584345, 25.043920960028977]
},
{
"Ticker": "WMT",
"daily_pe": [24.930801136366966,25.504480242081453]
}
]
you can do the thing you wanted by using ArrayAgg aggregation function
views.py
from django.contrib.postgres.aggregates import ArrayAgg
class peChartViewSet(APIView):
def get(self, request):
queryset = Price.objects.values('ticker').annotate(
daily_pe_list=ArrayAgg('daily_pe')
)
serializer = ChartSerilizer(queryset, many=True)
return JsonResponse(serializer.data, safe=False)
and also change daily_pe's type to ListField
serializers.py
class ChartSerilizer(serializers.ModelSerializer):
Ticker = serializers.CharField(source='ticker')
daily_pe = serializers.ListField(source='daily_pe_list')
class Meta:
model = Price
fields = ['Ticker', 'daily_pe']
based on your answer, you want result list in order of price_date, so for this purpose, you can add ordering argument to ArrayAgg like this:
queryset = Price.objects.values('ticker').annotate(
daily_pe_list=ArrayAgg('daily_pe', ordering='price_date')
)
* sorry I answered late, i wasn't around my pc.
There must me a better way, but I got desired result (almost).
Here is my updated view.py
class peChartViewSet(APIView):
def get(self, request):
tickers = ['AAPL', 'WMT']
data=[]
for tick in tickers:
print(tick)
# tick = request.query_params["ticker"]
queryset = Price.objects.all().filter(ticker=tick).order_by('price_date')
serializer = ChartSerilizer(queryset, many=True)
data.append({tick : serializer.data})
return Response(data)
Parent id or foreign key is not returning from child. I am trying drf-nested-routers example.
models.py
class Client(models.Model):
name = models.CharField(max_length=255)
class MailDrop(models.Model):
title = models.CharField(max_length=255)
client_id = models.ForeignKey(Client, on_delete=models.CASCADE)
serializers.py
class ClientSerializer(HyperlinkedModelSerializer):
class Meta:
model = Client
fields = ['id', 'name']
class MailDropSerializer(NestedHyperlinkedModelSerializer):
parent_lookup_kwargs = {
'client_pk': 'client_id',
}
class Meta:
model = MailDrop
fields = ['id', 'title']
views.py
class ClientViewSet(viewsets.ViewSet):
serializer_class = ClientSerializer
def list(self, request):
queryset = Client.objects.filter()
serializer = ClientSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Client.objects.filter()
client = get_object_or_404(queryset, pk=pk)
serializer = ClientSerializer(client)
return Response(serializer.data)
class MailDropViewSet(viewsets.ViewSet):
serializer_class = MailDropSerializer
def list(self, request, client_pk=None):
queryset = MailDrop.objects.filter(client_id=client_pk)
serializer = MailDropSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None, client_pk=None):
queryset = MailDrop.objects.filter(pk=pk, client_id=client_pk)
maildrop = get_object_or_404(queryset, pk=pk)
serializer = MailDropSerializer(maildrop)
return Response(serializer.data)
If I add fields = ['id', 'title', 'client_id'] in the MailDropSerializer, it throws the following error:
AssertionError: `NestedHyperlinkedRelatedField` requires the request in the serializer context. Add `con
text={'request': request}` when instantiating the serializer.
If I add the request in the serializer context, the output is as follows:
url: http://127.0.0.1:8000/clients/4/maildrops/
[
{
"id": 3,
"title": "Madison Mosley",
"client_id": "http://127.0.0.1:8000/clients/4/"
},
{
"id": 4,
"title": "Louis Chen",
"client_id": "http://127.0.0.1:8000/clients/4/"
}
]
I added the serializer context as follows:
def list(self, request, client_pk=None):
queryset = MailDrop.objects.filter(client_id=client_pk)
serializer_context = {
'request': request
}
serializer = MailDropSerializer(
queryset, many=True, context=serializer_context)
return Response(serializer.data)
I am trying to get something as follows:
[
{
"id": 3,
"title": "Madison Mosley",
"client_id": 4
},
{
"id": 4,
"title": "Louis Chen",
"client_id": 4
}
]
Just solved:
class MailDropSerializer(NestedHyperlinkedModelSerializer):
parent_lookup_kwargs = {
'client_pk': 'client_id',
}
client_id = IntegerField(source='client_id.id')
class Meta:
model = MailDrop
fields = ['id', 'title', 'client_id']
I have 3 different models. I need to build a custom serializer with these 3 models. I tried using some code, but it didn't reach what I expected.
There is structure, but I was not able to get the data I was expecting
# Serializer
This my Serializer and ModelOne, ModelTwo, ModelThree these are my models.
class ModelOneSerializer(serializers.ModelSerializer):
class Meta:
model = ModelOne
fields = ['id', 'obj_1', 'obj_2']
class ModelTwoSerializer(serializers.ModelSerializer):
class Meta:
model = ModelTwo
fields = ['id', 'obj_1', 'obj_2']
class ModelThreeSerializer(WritableNestedModelSerializer):
class Meta:
model = ModelThree
fields = ['id', 'obj_1', 'obj_2']
class CustomSerializer(serializers.Serializer):
model_1 = ModelOneSerializer(many=True)
model_2 = ModelTwoSerializer(many=True)
model_3 = ModelThreeSerializer(many=True)
# View
class CustomView(APIView):
def get(self, request, *args, **kwargs):
serializer = CustomSerializer(context={'request': request})
return Response({'response': 'ok', 'result': serializer.data})
# Expected Output
{
"response": "ok",
"result": {
"model_1": [
{
"id":"1",
"obj_1":"test",
"obj_2":"test",
"obj_3":"test"
},
{
"id":"1",
"obj_1":"test",
"obj_2":"test",
"obj_3":"test"
}
],
"model_2": [
{
"id":"1",
"obj_1":"test",
"obj_2":"test",
"obj_3":"test"
}
],
"model_3": [
{
"id":"1",
"obj_1":"test",
"obj_2":"test",
"obj_3":"test"
}
]
}
}
The results may have multiple data in the model_2 and model_3 as in the model_1 structure
You didn't pass what to serialize for all the model serializers, so CustomSerializer doesn't have anything to serialize against.
You can pass the querysets of the models to CustomSerializer:
class CustomView(APIView):
def get(self, request, *args, **kwargs):
model_one_qset = ModelOne.objects.all()
model_two_qset = ModelTwo.objects.all()
model_three_qset = ModelThree.objects.all()
qsets_map = {
'model_1': model_one_qset,
'model_2': model_two_qset,
'model_3': model_three_qset,
}
serializer = CustomSerializer(qsets_map, context={'request': request})
return Response({'response': 'ok', 'result': serializer.data})
I'm Trying to add the sum of multiple objects to a DRF response. For example, right now the response works with just listing the objects:
[
{
"id": "47d0deaa5c8c",
"amount": "25.00"
},
{
"id": "29787731",
"amount": "25.00"
}
]
But what I want is to be able to sum the amount attribute of those objects together and then include that in the response, so that it would look like this:
{
"sum":"50.00",
"objects":[
{
"id":"47d0deaa5c8c",
"amount":"25.00"
},
{
"id":"29787731",
"amount":"25.00"
}
]
}
Here's my current APIView:
class TransactionsList(GenericAPIView):
"""
Retrieve list of transactions
"""
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request):
"""List Transactions"""
transaction = Transaction.objects.all()
serializer = TransactionSerializer(transaction, many=True)
return Response(serializer.data)
And Serializer:
class TransactionSerializer(serializers.ModelSerializer):
class Meta:
model = Transaction
fields = ('id', 'amount')
How could I efficiently go about adding the sum field into the response?
change
return Response(serializer.data)
to
from django.db.models import Sum
all_sum = transaction.aggregate(Sum('amount'))['amount__sum']
return Response({'sum': all_sum if all_sum else 0 , 'objects': serializer.data})
Since the amount field seems string type. So, we've to convert to int before summing them.
class TransactionsList(GenericAPIView):
"""
Retrieve list of transactions
"""
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request):
"""List Transactions"""
transaction = Transaction.objects.all()
serializer = TransactionSerializer(transaction, many=True)
return_data = {"sum": str(sum([lambda items: int(items['amount'])])), "objects": serializer.data}
return Response(return_data)
If the amount field is int type, then you don't want to add do the type casting. If so, use this,
return_data = {"sum": sum([lambda items: items['amount']]), "objects": serializer.data}
I have the next view on my API
class CapsuleViewSet(viewsets.ModelViewSet):
queryset = Capsule.objects.all()
serializer_class = CapsuleSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
#action(detail=True)
def modules(self, request, pk=None):
capsule = self.get_object()
capsule_modules = Module.objects.filter(capsule=capsule)
serializer = ModuleSerializer(capsule_modules, many=True)
return Response(serializer.data)
When i try to get all the modules related to a capsule, the URL of the imageField of a module is incomplete.
When i call http://0.0.0.0:8000/api/capsules/1/ it returns:
{
"capsuleID": 1,
"capsuleName": "sdfads",
"capusuleDetails": "asdf",
"capsuleImageURL": "http://0.0.0.0:8000/media/capsulas/logocitbm.png",
"userStars": 0,
"pallete": {
"palleteID": 1,
"palleteName": "Default smartraining",
"colors": [
{
"colorID": 1,
"colorName": "A1",
"colorCode": "#sdfs"
},
{
"colorID": 2,
"colorName": "A2",
"colorCode": "#dsfksdoif"
},
{
"colorID": 3,
"colorName": "A3",
"colorCode": "#sdjfjgioj"
}
]
}
}
but when i call http://0.0.0.0:8000/api/capsules/1/modules/ i get:
[
{
"moduleID": 1,
"moduleName": "sdfa",
"moduleDetails": "asÃ",
"moduleImageURL": "/media/modulos/9_-_4._Detalle_C%C3%A1psula.png",
"userScore": 0
}
]
the moduleImageURL is incomplete, why?
these are my serializers:
class CapsuleSerializer(serializers.ModelSerializer):
pallete = PalleteSerializer(read_only=True)
class Meta:
model = Capsule
fields = ('capsuleID', 'capsuleName', 'capusuleDetails', 'capsuleImageURL', 'userStars', 'pallete')
class ModuleSerializer(serializers.ModelSerializer):
class Meta:
model = Module
fields = ('moduleID', 'moduleName', 'moduleDetails', 'moduleImageURL', 'userScore')
After some research i find that i need pass the context to the ModelSerializer like this:
serializer = ModuleSerializer(capsule_modules, many=True, context={'request': request})