Assertion through Django restApi - django-rest-framework

I'm trying to insert records through APIView but it returns error like
Expected a Response, HttpResponse or HttpStreamingResponse to be returned from the view, but received a <class 'NoneType'>
this is views.py
class TrackList(APIView):
def post(self,request, *args, **kwargs):
employee = Employee.objects.filter(username=kwargs.get('username'), password=kwargs.get('password'))
if employee.exists():
serializer_class = TrackSerializer(data = request.data)
try:
if serializer_class.is_valid():
serializer_class.save(employee=employee[0])
return response.Response(serializer_class.data, status = status.HTTP_201_CREATED)
except Exception as e:
print(e)
return response.Response(serializer_class.errors, status = status.HTTP_404_NOT_FOUND)
please help me how could it be fixed?

When employee.exists() == False or serializer_class.is_valid() == False, then the execution moves to the end of the method, where it implicitly returns None.
Fix it with the following. When the employee doens't exist, it will return a Not Found response with a 404 status. When the serializer data is not valid, it will return an empty response with a 400 Bad Request status.
class TrackList(APIView):
def post(self,request, *args, **kwargs):
employee = Employee.objects.filter(username=kwargs.get('username'), password=kwargs.get('password'))
if employee.exists():
serializer_class = TrackSerializer(data = request.data)
try:
if serializer_class.is_valid():
serializer_class.save(employee=employee[0])
return response.Response(serializer_class.data, status = status.HTTP_201_CREATED)
except Exception as e:
print(e)
return response.Response(serializer_class.errors, status = status.HTTP_404_NOT_FOUND)
return response.Response(None, status=status.HTTP_400_BAD_REQUEST)
return response.Response(None, status=status.HTTP_404_NOT_FOUND)

Related

Getting an AttributeError using RetrieveUpdateDestroyAPIView

I am new to django and am using mongoengine. I am trying to create an employee database using DRF. All of the APIs are working well but whenever I am trying to fetch a single document which has been deleted its giving me an AttributeError at employee/<int:pk>.
This is my models.py file:-
from mongoengine import Document, SequenceField, StringField, IntField, EmailField from enum import Enum from rest_framework.exceptions import ValidationError
class GenderEnums(str, Enum):
MALE = "Male"
FEMALE = "Female"
OTHER = "Other"
#classmethod
def choices(cls):
return [item.value for item in cls]
models.py:-
class Employee(Document):
employee_id = SequenceField(required=False, primary_key=True)
name = StringField(required=True, max_length=50)
age = IntField(required=True, min_value=18, max_value=50)
company = StringField(required=True, max_length=50)
gender = StringField(choices=GenderEnums.choices(), default=GenderEnums.OTHER)
email = EmailField(required=True, unique=True)
password = StringField(required=True)
def clean(self):
if self.gender == GenderEnums.MALE.value and self.age > 30:
raise ValidationError("For male employees, age should be under 31")
elif self.gender == GenderEnums.FEMALE.value and self.age < 20:
raise ValidationError("For female employees, age should be above 20")
serializers.py:-
from rest_framework_mongoengine import serializers
from .models import Employee
class EmployeeSerializer(serializers.DocumentSerializer):
class Meta:
model = Employee
fields = "__all__"
views.py:-
from .serializers import EmployeeSerializer
from .models import Employee
from rest_framework.response import Response
from rest_framework_mongoengine import generics
import logging
from rest_framework.exceptions import ValidationError
from mongoengine import DoesNotExist
import time
logging.basicConfig(filename="logs.txt", filemode="a", level=logging.INFO)
# GeneralSerializer.Meta.model = Employee
# serializer_used = GeneralSerializer
class EmployeeAdd(generics.CreateAPIView):
try:
serializer_class = EmployeeSerializer
logging.info(f"Document created successfully at {time.ctime()}")
except ValidationError as e:
Response(f"Validation error: {e}")
except Exception as e:
logging.error(f"Error occurred: {e}")
Response(f"An error occurred while creating the document")
class EmployeeAll(generics.ListAPIView):
serializer_class = EmployeeSerializer
queryset = Employee.objects.all()
def get_queryset(self):
queryset = self.queryset
params = self.request.query_params
if "name" in params:
queryset = queryset.filter(name=params["name"])
if "age" in params:
queryset = queryset.filter(age=params["age"])
return queryset
class EmployeeOne(generics.RetrieveUpdateDestroyAPIView):
serializer_class = EmployeeSerializer
lookup_field = "pk"
queryset = Employee.objects.all()
def get_object(self):
try:
queryset = self.get_queryset()
obj = queryset.get(pk=self.kwargs[self.lookup_field])
return obj
except Exception as e:
logging.error(
f"Failed to retrieve document with the ID {self.kwargs[self.lookup_field]}"
)
return Response(
{"detail": "An error occurred while processing your request."}, status=500
)
def update(self, request, *args, **kwargs):
try:
response = super().update(request, *args, **kwargs)
logging.info(
f"Successfully updated document with ID {kwargs[self.lookup_field]}"
)
return response
except ValidationError as e:
logging.error(
f"Failed to update document with ID {kwargs[self.lookup_field]} due to validation error: {e}"
)
return Response({"detail": e.detail}, status=e.status_code)
except DoesNotExist:
return Response({"detail": "Document not found."}, status=404)
except Exception as e:
logging.error(
f"Failed to update document with ID {kwargs[self.lookup_field]} due to an error: {e}"
)
return Response(
{"detail": "An error occurred while processing your request."}, status=500
)
def destroy(self, request, *args, **kwargs):
try:
response = super().destroy(request, *args, **kwargs)
logging.info(
f"Successfully deleted document with ID {kwargs[self.lookup_field]}"
)
return Response(
f"Successfully deleted document with ID {kwargs[self.lookup_field]}"
)
except DoesNotExist:
return Response({"detail": "Document not found."}, status=404)
except Exception as e:
logging.error(
f"Failed to delete document with ID {kwargs[self.lookup_field]} due to an error: {e}"
)
return Response(
{"detail": "An error occurred while processing your request."}, status=500
)
from django.urls import path from .views import EmployeeAdd, EmployeeAll, EmployeeOne
urlpatterns = [ path("register", EmployeeAdd.as_view()), path("employees", EmployeeAll.as_view()), path("employee/<int:pk>", EmployeeOne.as_view()), ]
Any help would be very much appreciated. Thank you.
I tried using serializer, serializer_class changed the methods but still getting the AttributeError:
AttributeError: "Got AttributeError when attempting to get a value for field nameon serializerEmployeeSerializer. The serializer field might be named incorrectly and not match any attribute or key on the Response instance. Original exception text was: 'Response' object has no attribute 'name'."

Is there a way to call pagination methods get_next_link and get_previous_link in DRF viewset?

I want to add additional values ​​to the pagination response in my viewset and keep the fields what already there. I was able to add count, but i can`t add next and previous urls to response, is where a way to call pagination_class methods in viewset.
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(queryset, many=True)
return self.get_paginated_response(serializer.data)
else:
status_count = Vps.objects.all().aggregate(
started=Count("status", filter=Q(status="started")),
blocked=Count("status", filter=Q(status="blocked")),
stopped=Count("status", filter=Q(status="stopped"))
)
serializer = self.get_serializer(queryset, many=True)
status_count["results"] = serializer.data
return Response(status_count)
def get_paginated_response(self, data):
status_count = Vps.objects.all().aggregate(
started=Count("status", filter=Q(status="started")),
blocked=Count("status", filter=Q(status="blocked")),
stopped=Count("status", filter=Q(status="stopped"))
)
pagination = self.pagination_class()
page = self.paginate_queryset(data)
return Response(OrderedDict([
('count', pagination.get_count(data)),
('next', self.pagination_class.get_next_link),
('previous', self.pagination_class.get_previous_link),
('started', status_count["started"]),
('blocked', status_count["blocked"]),
('stopped', status_count["stopped"]),
('results', page)
]))
I was able to solve this by creating custom pagination class
class VpsLimitOffsetPagination(LimitOffsetPagination):
def get_paginated_response(self, data):
status_count = Vps.objects.all().aggregate(
started=Count("status", filter=Q(status="started")),
blocked=Count("status", filter=Q(status="blocked")),
stopped=Count("status", filter=Q(status="stopped"))
)
return Response(OrderedDict([
('count', self.count),
('started', status_count["started"]),
('blocked', status_count["blocked"]),
('stopped', status_count["stopped"]),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))

SerializerMethodField doesn't work on DRF

Here is the simplified verison of the Serializer what I have:
class CommentSerializer(serializers.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
init = super().__init__(*args, **kwargs)
return init
username = serializers.ReadOnlyField(source='user.username')
user_id = serializers.ReadOnlyField(source='user.id')
user = UserSerializer(read_only=True)
url_field_name = 'url_api'
# and more definitions
content_type_id = serializers.IntegerField()
site_id = serializers.SerializerMethodField('_siteId')
def _siteId(self, threadedcomment):
site_id = settings.SITE_ID
return site_id
class Meta:
model = ThreadedComment
fields = ('url_api','url','id','title','tree_path','comment','submit_date','submit_date_unix','submit_date_humanized','root_id','is_removed',
'parent_id','last_child_id','newest_activity','depth','username','user_id','object_pk','content_type_id','user',
'site_id',
)
read_only_fields = ('id','title','tree_path','submit_date','root_id','is_removed',
'parent_id','last_child_id','newest_activity','depth','username','user_id',
# 'site_id',
)
class CommentViewSet(viewsets.ModelViewSet):
queryset = ThreadedComment.objects.all().annotate().all()
serializer_class = CommentSerializer
permission_classes = []
filter_backends = [filters.OrderingFilter]
def filter_queryset(self, queryset):
return queryset
def list(self, request):
return super().list(request)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
# site_id = settings.SITE_ID
# serializer.save(user=self.request.user, site_id=site_id, )
return super().perform_create(serializer)
Now I make an http post request on the api as i.e.:
axios.post('/api/comments/', {
"comment":"test.",
"object_pk":34,
"content_type_id":12,
},
It shows me an error:
500 (Internal Server Error)
IntegrityError: NOT NULL constraint failed: django_comments.site_id
The problem (a pure question) is, why the SerializerMethodField doesn't work? I put a breakpoint on the site_id = settings.SITE_ID line, but it doesn't hit, which means the line hasn't even executed.
I also tried putting a set of lines (the commented lines) on perform_create, reading a SO post, but the result is the same, the same error, NOT NULL constraint failed.
I'm certainly passing a value, but it shows it's a null value, saying nothing is passed, what this means? What am I donig wrong here? Thanks.

how could I POST the data in DJANGO rest_frame?

I want to insert Track record through a condition but it does not happen. Please help me how could I do fix it?
this is views.py
class Track(APIView):
http_method_names = ['post',]
def post(self,request, *args, **kwargs):
employee = Employee.objects.filter(username=kwargs.get('username'), password=kwargs.get('password'))
if employee.exists():
serializer_class = TrackSerializer
try:
if serializer_class.is_valid():
serializer_class.save()
return Response(serializer_class.data, status = status.HTTP_201_CREATED)
except Exception as e:
print(e)
return Response(serializer_class.errors, status = status.HTTP_404_NOT_FOUND)
urls.py
path('track/<username>/<password>/',views.TrackList.as_view(),name = 'track'),
You have to pass data to your serializer
class Track(APIView):
http_method_names = ['post',]
def post(self,request, *args, **kwargs):
employee = Employee.objects.filter(username=kwargs.get('username'), password=kwargs.get('password'))
if employee.exists():
serializer_class = TrackSerializer(data=request.data)
try:
if serializer_class.is_valid():
serializer_class.save()
return Response(serializer_class.data, status = status.HTTP_201_CREATED)
except Exception as e:
print(e)
return Response(serializer_class.errors, status = status.HTTP_404_NOT_FOUND)

Django Rest Framework Testing Exceptions In Views

I have a test class that inherits from APITestCase. This test class has a test case that attempts to mock a function called to raise an exception by another object in one the views being tested. However, my exception is never getting raised by the mock. If I don't inherit from APITestCase the test cases works as expected essentially.
Does APITestCase hide or prevent exceptions from being propagated up?
Here is my view file:
views.py
class Foo(object):
def bar(self):
pass
class Foo2(object):
def bar2(self, f):
f = Foo()
f.bar()
class JobListRest(generics.ListAPIView, generics.CreateAPIView):
queryset = Job.objects.all()
serializer_class = JobSerializer
"""
List all jobs, or create a new job.
"""
#csrf_exempt
def get(self, request, format=None):
jobs = Job.objects.all()
serializer = JobSerializer(jobs, many=True)
return Response(serializer.data)
#csrf_exempt
def post(self, request, format=None):
foo = Foo()
foo.bar()
serializer = JobSerializer(data=request.data)
if serializer.is_valid():
job = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
test.py
Exception does NOT get raised
class JobPostTest(APITestCase):
def setUp(self):
self.valid_job = """{
'name': 'foo',
'tasks':
[
{
'name':'test_task'
}
]
}"""
#patch('app.views.Foo')
def test_create_job_fails(self, mock):
error = ValidationError
mock.bar.side_effect = error
with self.assertRaises(error):
self.client.post('/api/jobs/', self.valid_job, format='json')
Exception does get raised
class FooTest(TestCase):
#patch('app.views.Foo')
def test_bar(self, mock):
mock.bar.side_effect=ValidationError
foo2 = Foo2()
self.assertRaises(ValidationError, foo2.bar2(1))

Resources