Django Rest Framework - Marking extra actions for routing - django

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})

Related

POST id objects and retriving nested tables related to it

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

Django NestedHyperlinkedModelSerializer not returning Foreign Key Field

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']

How to iterate ManyToMany filed in serializer class

I have this Event model:
# models.py
class Event(models.Model):
name = models.CharField(max_length=200))
user = models.ManyToManyField(User))
This is my ListCreateAPIView class:
class EventListView(LoginRequiredMixin, generic.ListView):
model = Event
This is my ListCreateAPIView class:
class Events(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated,)
queryset = Event.objects.all()
serializer_class = EventSerializer
This is my serialiser class:
#serializers,py
class EventSerializer(serializers.ModelSerializer):
class Meta:
fields = (
‘id',
'name',
'user',
)
model = Event
And this is my REST request response:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "My event1",
"user": [
1,
4
],
"registered": true // <—- I NEED THIS
},
{
"id": 2,
"name": "Other event",
"user": [
2,
4,
6
],
"registered": false // <—- I NEED THIS
}
]
}
What I am gonna need in REST response is property “registered”, which will contain true or false if current user is registered on particular event or not.
My approach was to control if current user is in list of users of event. I tried to get this information in serialiser class this way:
#serializers,py
class EventSerializer(serializers.ModelSerializer):
registered = serializers.SerializerMethodField(‘_user’)
def _user(self, obj):
request = getattr(self.context, 'request', None)
if request.user in self.user:
return True
else:
return False
class Meta:
fields = (
‘id',
'name',
'user',
)
model = Event
But I get AttributeError: 'NoneType' object has no attribute 'user'
How can I solve this problem?
You can try like this using exists() with filter method:
class EventSerializer(serializers.ModelSerializer):
registered = serializers.SerializerMethodField(‘_user’)
def _user(self, obj):
request = self.context.get('request', None)
if request and obj.user.filter(pk=request.user.pk).exists():
return True
else:
return False
In view.py add
For This "registered": true // <—- I NEED THIS
model_name.object.filter(column='required value')

How to make Custom Serializer from different models?

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})

Django REST Framework: Show only latest of nested object, return as un-nested JSON

What I'm trying to do in Django REST Framework: Return only latest nested object in list for an object and return it as JSON, with the sub-object un-nested.
My models:
class BaseObject(models.Model):
name = models.TextField()
object_type = models.ForeignKey(ObjectType)
class ObjectStatus(models.Model):
baseobject_id = models.ForeignKey('objects.BaseObject', related_name='status')
object_status = models.IntegerField()
object_status_timestamp = models.DateTimeField()
My serializers:
class ObjectStatusSimplifiedSerializer(serializers.ModelSerializer): #helper serializer to simplify status objects
class Meta:
model = ObjectStatus
fields = ['object_status', 'object_status_timestamp']
class ObjectStatusListSerializer(serializers.ModelSerializer): #request for last status of several objects
status = ObjectStatusSimplifiedSerializer(many=True)
class Meta:
model = BaseObject
fields = ['id', 'name', 'object_type', 'status']
My current view:
class ObjectStatusListView(generics.ListCreateAPIView):
serializer_class = ObjectStatusListSerializer
def get_queryset(self):
queryset = BaseObject.objects.all()
id = self.request.query_params.getlist('id')
if id:
queryset = queryset.filter(id__in=id)
return queryset
Current URL:
url(r'^objectstatus/status/list$', views.ObjectStatusListView.as_view()),
So now, when going to, for example, [...]/objectstatus/status/list?id=9, the result I get looks like this:
[
{
"id": 9,
"name": "r5",
"object_type": "router",
"status": [
{
"object_status": 1,
"object_status_timestamp": "2019-10-24T09:40:15.605391Z"
},
{
"object_status": 2,
"object_status_timestamp": "2019-10-24T09:40:28.133296Z"
},
{
"object_status": 3,
"object_status_timestamp": "2019-10-24T09:40:40.829486Z"
},
{
"object_status": 1,
"object_status_timestamp": "2019-10-24T09:40:53.333332Z"
}
]
}
]
What I want is to display only the object status with the most recent timestamp.
Also, I can't figure out how to flatten the JSON object, like this:
[
{
"id": 9,
"name": "r5",
"object_type": "router",
"object_status": 1,
"object_status_timestamp": "2019-10-24T09:40:53.333332Z"
}
]
With the following serializer, you should get the desired output. We filter the status list and get only the latest one and then we flatten the structure as you need.
class ObjectStatusListSerializer(serializers.ModelSerializer): #request for last status of several objects
status = serializers.SerializerMethodField(read_only=True)
class Meta:
model = BaseObject
fields = ['id', 'name', 'object_type', 'status']
def get_status(self, obj):
return ObjectStatusSimplifiedSerializer(instance=obj.status.order_by('object_status_timestamp').first()).data
def to_representation(self, obj):
"""Move fields from status to main object representation."""
representation = super().to_representation(obj)
status_representation = representation.pop('status')
for key in status_representation:
representation[key] = status_representation[key]
return representation
you can try change serializer to like this. I assum your ObjectType have field is name for line code object_type.name
class ObjectStatusSimplifiedSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
object_type = serializers.SerializerMethodField()
#staticmethod
def get_name(instance):
return instance.status.name
#staticmethod
def get_object_type(instance):
return instance.status.object_type.name
class Meta:
model = ObjectStatus
fields = ['id', 'name', 'object_type', 'object_status', 'object_status_timestamp']
class ObjectStatusListSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField()
#staticmethod
def get_status(instance):
queryset = ObjectStatus.objects.filter(baseobject_id=instance).order_by('-object_status_timestamp')[:1]
if queryset.count():
return ObjectStatusSimplifiedSerializer(queryset, many=True).data
return []
class Meta:
model = BaseObject
fields = ['id', 'name', 'object_type', 'status']