I'm creating a django rest framework application with this structure (assuming imports are correct, so I omit them from the code below.
models.py:
class Door(models.Model):
type = models.CharField(max_length=40)
color = models.CharField(max_length=40)
serializers.py:
class DoorSerializer(serializers.ModelSerializer):
class Meta:
model = Door
fields = ['type', 'color']
views.py:
class DoorViewSet(viewsets.ModelViewSet):
serializer_class = DoorSerializer
queryset = Door.objects.all()
def get_queryset(self, *args, **kwargs):
queryset = Door.objects.all()
parameter = self.request.query_params.get('type', '')
if parameter:
return queryset.filter(type=parameter)
else:
return queryset
So far this behaves as intended, when I make an api call to localhost/Doors
it lists all the doors. And when I make an api call to localhost/Doors/?type=big
it lists all the doors that have the value "big" in their "type" field.
The addition I would like to make is another parameter check which would return a list of all the unique door types that exist in the database. This can be achieved in the manage.py shell by using: Door.objects.all().values('type').distinct()
My attempt was the following modifications to views.py:
...
parameter = self.request.query.params.get('type', '')
unique = self.request.query.params.get('unique', '')
if parameter:
...
elif unique:
return Door.objects.all().values('type').distinct()
...
My assumption was that this would return the same as Door.objects.all().values('type').distinct()
when I make a call to localhost/Doors/?unique=whatever
However I am getting the error: "Got KeyError when attempting to get a value for field color
on serializer DoorSerializer
.\nThe serializer field might be named incorrectly and not match any attribute or key on the dict
instance.\nOriginal exception text was: 'color'."
I assume this means that the serializer expects an object or a list of objects that contains all the fields of the corresponding model.
Is there some way I could circumvent this by fixing the view or should I create a different serializer? In either case, since I've gotten pretty confused with DRF / django differences and it is possible I won't be able to follow abstract instructions, could you provide a code solution that addresses the issue? Also, in the very likely case that my assumption is completely off, could you also explain what is causing the problem? Thank you for your time!
Edit for clarifying the desired result:
Assuming my database has 4 doors which are:
{
"id": 1,
"type": "big",
"color": "blue"
},
{
"id": 2,
"type": "big",
"color": "yellow"
},
{
"id": 3,
"type": "small",
"color": "green"
},
{
"id": 4,
"type": "big",
"color": "red"
},
I would like to make a get
request to some url, for instance localhost/Doors/?unique=Yes
and have the api return to me the list {"big", "small}
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view()
def Unique_door_types(request):
types = Door.objects.values_list('type', flat=True).distinct()
return Response({"types": list(types)})
No need for additional view or serializer. Override the list
method. Note that this is closer to a trick than to a good way of programming.
from rest_framework.response import Response
class DoorViewSet(viewsets.ModelViewSet):
serializer_class = DoorSerializer
def get_queryset(self, *args, **kwargs):
queryset = Door.objects.all()
parameter = self.request.query_params.get('type', '')
if parameter:
return queryset.filter(type=parameter)
else:
return queryset
def list(self, request):
unique = self.request.query_params.get('unique', '')
if unique:
types = Door.objects.values_list('type', flat=True).distinct()
return Response({"types": list(types)})
return super().list()
My suggestion would be to create a separate route like /doors/types/
. You do this by adding a method to your DoorViewSet
class with a @action
decorator. See https://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing for more details about how to do this.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.