I want to add 'isSuccess' at the pagination returns.
For example,
{
"count": 1234,
"next": "http://mydomain/?page=2",
"previous": null,
"isSuccess" : 'Success' # <---- this one
"results": [
{
'id':123,
'name':'abc'
},
{
'id':234,
'name':'efg'
},
...
]
}
I found this way but It didn't work. How can I add new values at Django pagination return?
this is my try:
class Testing(generics.GenericAPIView):
queryset = Problem.objects.all()
serializer_class = userSerializer
pagination_class = userPagination
def get(self, request):
queryset = self.get_queryset()
page = self.request.query_params.get('page')
if page is not None:
paginate_queryset = self.paginate_queryset(queryset)
serializer = self.serializer_class(paginate_queryset, many=True)
tmp = serializer.data
tmp['isSuccess'] = 'Success'
return self.get_paginated_response(tmp)
Give this a try, instead of adding isSuccess to the serializer.data, add it to get_paginated_response().data
def get(self, request):
queryset = self.get_queryset()
page = self.request.query_params.get('page')
if page is not None:
paginate_queryset = self.paginate_queryset(queryset)
serializer = self.serializer_class(paginate_queryset, many=True)
tmp = serializer.data
# tmp['isSuccess'] = 'Success'
response = self.get_paginated_response(tmp)
response.data['isSuccess'] = "Success"
return Response(data=response.data, status=status.HTTP_200_OK)
return Response(data="No Page parameter found", status=status.HTTP_200_OK)
The response will be something like
{
"count": 1234,
"next": null,
"previous": null,
"results": [
{
'id':123,
'name':'abc'
},
...
],
"isSuccess" : 'Success'
}
You can try overriding the get_paginated_response method in the PageNumberPagination
Example:
from rest_framework.pagination import PageNumberPagination
from collections import OrderedDict
class CustomPagination(PageNumberPagination):
def get_paginated_response(self, data):
return Response(OrderedDict([
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data),
('isSuccess', "Success") # extra
]))
Related
I have a very simple DRF ListApiView which is using filters.SearchFilter as filter_backend.
But the problem is it is returning an empty list if no data is found on the queryset.
My Code:
serializers.py
class PhoneSerializer(serializers.ModelSerializer):
brand_name = serializers.CharField(source='brand')
class Meta:
model = models.Phone
fields = '__all__'
views.py
class PhoneApiView(generics.ListAPIView):
filter_backends = [filters.SearchFilter]
serializer_class = serializers.PhoneSerializer
queryset = models.Phone.objects.all()
search_fields = ['model_name', 'jan_code']
Result for a successful search
[
{
"id": 6,
"brand_name": "Oppo",
"model_name": "Oppo Reno 5",
"image": "http://127.0.0.1:8000/media/phone/reno-5-black-2.jpg",
"colors": "Red, Blue",
"jan_code": "785621716768184",
"brand": 6
}
]
Expected Result if nothing found (Currently returning an empty list [])
{
"response": 'No Data Found'
}
Now, How do I do that?
Thanks
Try to start with the filter_queryset() method and work your way to the get() method.
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
def get_queryset(self):
return Phone.objects.all()
def get(self, request):
filtered_qs = self.filter_queryset(self.get_queryset())
serializer = PhoneSerializer(filtered_qs, data=request.data)
serializer.is_valid(raise_exception=True)
if not filtered_qs.exists():
return Response({'response': 'No Data Found'})
return Response(serializer.data)
Whenever i called my booking function with a post method in that it throws me an error of 'Invalid Data Type it expected dict but its an int'. So when i debug that i found a problem in my serializers so Please help me to resolve the error
model.py
class Booking(models.Model):
details = models.ForeignKey(PersonalDetails, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False)
total_amount = models.IntegerField()
show = models.ForeignKey(ShowTime, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.total_amount
views.py
class BookingTicketsQuery(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
booking_id = request.query_params.get('booking_no', None)
if booking_id is not None:
queryset = Booking.objects.get(id=booking_id)
else:
return Response("invalid", status=status.HTTP_409_CONFLICT)
seriliazer = BookingSerializer(queryset)
return Response(seriliazer.data)
def post(self, request, format=None):
recieve_data = JSONParser().parse(request)
showtime = ShowTime.objects.get(id=recieve_data['show'])
print(showtime)
if recieve_data['quantity'] > (showtime.total_seats - showtime.booked_seats):
return Response("Error: No seats available", status=status.HTTP_409_CONFLICT)
recieve_data['total_amount'] = showtime.total_price * \
recieve_data['quantity']
showtime.booked_seats += recieve_data['quantity']
showtime.save()
serializer = BookingSerializer(data=recieve_data)
if serializer.is_valid():
booking_obj = serializer.save()
return Response(booking_obj.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class ShowMovieSerializer(serializers.ModelSerializer):
cinema = CinemaSerializer()
movie = MovieSerializer()
class Meta:
model = ShowTime
fields = ('id', 'show_start_time', 'show_end_time',
'total_seats', 'booked_seats', 'cinema', 'movie')
class BookingSerializer(serializers.ModelSerializer):
show = ShowMovieSerializer()
details = PersonalDetailsSerializer()
class Meta:
model = Booking
fields = ('id', 'total_amount', 'quantity', 'details', 'show')
traceback
Bad Request: /api/v1/bookings/
[19/Jul/2021 12:07:20] "POST /api/v1/bookings/ HTTP/1.1" 400 168
{
"details": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
},
"show": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
}
}
my post data:
{
"details": 1,
"quantity":1,
"show":1
}
You added a ShowMovieSerializer() and PersonalDetailsSerializer(). Therefore drf expects data that represents both models (nested data). What you have to do instead of posting { "details": 1, "quantity":1, "show":1 }-data you have to adjusted your data that represents your model. You are posting data with a pk of your Movie and Show.
For instance:
{
"id":....,
"total_amount": ....,
....
"movie": {
"title": ...., # fields are only for explanation
"length": ....
},
"show": {
"title": ....,
"actor": ....
}
}
If you only want to establish a relationship between you ShowTime and Booking you have to remove your serializers.
dealing with nested data
Here I m making a POST request with the following data:
{
"ruleAssignmentDetails": {
"id": 1,
"ruleAssignment": {
"id": 1,
"empId": 1,
"roleId": 1,
"empName": "Emp01",
"roleName": "CEO"
},
"detailSrl": 12,
"rule": 4,
"validityType": "F",
"startDate": "2021-06-14",
"endDate": null,
"frequency": {
"id": 1,
"frequencyName": "Test",
"frequencyTpe": "Weekly"
}
},
"detailSrl": 12,
"parameterName": "Param1",
"valueType": "D",
"overwriteValue": null,
"targetDefination": {
"id": 1,
"targetName": "MIN SALES",
"displayName": "MIN SALES"
}
}
split the objects into respective models but when I m not getting the 'id' of targetDefination and ruleAssignmentDetails
serializer.py
class RuleAssignmentParamsSerializers(serializers.ModelSerializer):
ruleAssignmentDetails = RuleAssignmentDetailsSerializers()
targetDefination = TargetDefinationSerializers()
class Meta:
model = RuleAssignmentParams
fields = (
'id',
'ruleAssignmentDetails',
'detailSrl',
'parameterName',
'valueType',
'overwriteValue',
'targetDefination',
)
def create(self,validated_data):
ruleAssDetails = validated_data.pop('ruleAssignmentDetails')
targetdef = validated_data.pop('targetDefination')
serial = RuleAssignmentParams.objects.create(**validated_data)
return serial
views.py
def getSimpleRules(request):
simpleRules = RuleSimple.objects.all()
simpleRulesSer = OnlySimpleRules(simpleRules,many=True)
return JsonResponse(simpleRulesSer.data,safe=False)
#api_view(['GET'])
def getRuleAssignment(request,pk):
if request.method == 'GET':
print("get working")
q=get_object_or_404(RuleAssignmentParams,pk=pk)
f=RuleAssignmentParamsSerializers(q)
return JsonResponse(f.data)
#api_view(['POST'])
def ruleAssignment(request):
if request.method == 'POST':
data = JSONParser().parse(request)
validated_data = data
serializer=RuleAssignmentParamsSerializers(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status=status.HTTP_200_OK,safe=False)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
when I run this it shows me this error:
IntegrityError at /api/rules/ruleassign
(1048, "Column 'ruleAssignmentDetails_id' cannot be null")
How do I get the id of ruleAssignmentDetails and targetDefination ?
The create method in your serializer looks incorrect. Try this:
class RuleAssignmentParamsSerializers(serializers.ModelSerializer):
ruleAssignmentDetails = RuleAssignmentDetailsSerializers()
targetDefination = TargetDefinationSerializers()
class Meta:
model = RuleAssignmentParams
fields = (
'id',
'ruleAssignmentDetails',
'detailSrl',
'parameterName',
'valueType',
'overwriteValue',
'targetDefination',
)
def create(self,validated_data):
ruleAssDetails = validated_data.pop('ruleAssignmentDetails')
targetdef = validated_data.pop('targetDefination')
rule_serial = RuleAssignmentDetailsSerializers()
rule_instances = rule_serial.create(ruleAssDetails)
target_serial = RuleAssignmentDetailsSerializers()
target_instances = rule_serial.create(targetdef)
serial = RuleAssignmentParams.objects.create(**validated_data)
instance = super(RuleAssignmentParams, self).create(validated_data)
instance.ruleAssignmentDetails.add(*rule_instances)
instance.ruleAssignmentDetails.add(*target_instances)
instance.save()
return instance
Only works if the the ForeignKey in your model is not required. (blank=True, null=True). Otherwise you have to your rule_id and target_id to your validated_data.
I want to write unit tests for my project in django rest framwork but I can not compare my res.data with my serializer.data
This is my json for one object Brand :
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"url": "http://localhost:8000/shops/tags/1/",
"id": 1,
"name": "PS4",
"link": "https://www.playstation.com"
}
]
}
This is my unit test :
BRANDS_URL = reverse('brands-list')
def test_retrieve_brand_list(self):
"""Test retrieving a list of brands"""
Brand.objects.create(name='Bestbuy', link='https://bestbuy.ca')
Brand.objects.create(name='Amazon', link='https://amazon.ca')
res = self.client.get(BRANDS_URL)
brands = Brand.objects.all().order_by('-name')
context = {'request': RequestFactory().get('/')}
serializer = BrandsSerializer(brands, context=context, many=True)
self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.data, serializer.data)
My serializer :
class BrandsSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Brand
fields = ('url', 'id', 'name', 'link')
How I can add count, next, previous and results to my serializer.data ?
How I can have a serializer.data like res.data ?
I'm a little lost, I can not find a solution
You can try this:
*self.assertEqual(res.data['results'], serializer.data)*
Hope this helps.
So I have a fairly straightforward serializer in serializers.py
class ScheduleSerializer(serializers.ModelSerializer):
class Meta:
model = FrozenSchedule
fields = ['startDate', 'endDate', 'client', 'url']
startDate = serializers.DateField(source='start_date')
endDate = serializers.DateField(source='end_date')
client = serializers.StringRelatedField(many=False)
url = serializers.URLField(source='get_absolute_url')
get_absolute_url in my models.py
def get_absolute_url(self):
return reverse('reports:frozenschedule-detail', kwargs={
'slug': self.client.slug, 'pk': self.id
})
And it's related ViewSet in viewsets.py
class ScheduleViewSet(viewsets.ReadOnlyModelViewSet):
queryset = FrozenSchedule.objects.not_abandoned().future()\
.filter(signed=False).order_by('start_date')
serializer_class = serializers.ScheduleSerializer
It returns JSON which looks like this:
[
{
"startDate": "2016-10-01",
"endDate": null,
"client": "Abscissa.Com Limited",
"url": "/clients/abscissac/frozenschedule/1",
}
]
But I'd like it to return the complete URL, not just the relative path
[
{
"startDate": "2016-10-01",
"endDate": null,
"client": "Abscissa.Com Limited",
"url": "http://localhost:8000/clients/abscissac/frozenschedule/1",
}
]
Could I serialize URL's this way inside my Serializer?
The Restful documentation states that the rest_framework reverse function does exactly what I need. But it requires the request object to build the UR
http://www.django-rest-framework.org/api-guide/reverse/
Override HyperlinkedIdentityField. It has the following method,
get_url(self, obj, view_name, request, format)
which can be used to map the object instance to its URL representation. ie,
class UrlHyperlinkedIdentityField(HyperlinkedIdentityField):
def get_url(self, obj, view_name, request, format):
if obj.pk is None:
return None
return self.reverse(view_name,
kwargs={
'slug': obj.client.slug,
'pk': obj.id,
},
request=request,
format=format,
)
Then in serializers.py :
url = UrlHyperlinkedIdentityField(view_name='reports:frozenschedule-detail')