Django Rest Framework Testing Exceptions In Views - django-rest-framework

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

Related

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.

'InMemoryUploadedFile' object is not callable

While uploading the csv file showing "'InMemoryUploadedFile' object is not callable " this error, i want to import the csv file data into database using APIview.
Here My Apiview
class UploadViewSet(APIView):
parser_classes = (MultiPartParser, FormParser)
permission_classes = (AllowAny,)
serializer_class= UploadSerializer
def post(self, request, *args, **kwargs):
serializer = UploadSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
file = serializer.validated_data['File']
reader = csv.reader(file('file','r'))
for row in reader():
new_company = Company(
name=row['name'],
hr_name=row['hr_name'],
hr_email=row['hr_email'],
hr_verified=row['hr_verified'],
user_id=row['user_id'],
primary_phone=row['primary_phone'],
comments=row['comments'],
)
new_company.save()
return Response({"status": "success"},status.HTTP_201_CREATED)

Assertion through Django restApi

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)

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)

How can create Serializer with custom logic?

Only two parameters come to the input:
param1 = Int, optional
param2 = Char, require
On output - json with 4 elements
key1 = Char
key2 = Int
key3 = Int
key4 = Int
Everything can be null
Now I have it implemented in the view in the get method, but I want to create a Serializer for this and put all the logic there, but I don’t really understand where to transfer the logic - validate, to_representation?
Now it looks something like this
views.py
class ExampleRetrieveApiView(APIView):
def get(self, request, *args, **kwargs):
# A lot of logic related with input parameters.
return Response({
'key1': value1,
'key2': value2,
'key3': value3,
'key4': value4
})
Need to do something like this
views.py
class ExampleRetrieveApiView(APIView):
serializer_class = ExampleSerializer
def get(self, request):
serializer = ExampleSerializer(???)
return Response(serializer.data)
serializers.py
class ExampleSerializer(serializers.Serializer):
???
Pass the input params as a dict. Then, you should use SerializerMethodField() for this:
from rest_framework import serializers
class ExampleSerializer(serializers.Serializer):
key1 = serializers.SerializerMethodField()
key2 = serializers.SerializerMethodField()
key3 = serializers.SerializerMethodField()
key4 = serializers.SerializerMethodField()
def get_key1(self, obj):
# do some calculations, let's say we want to return input1 multiplied by 2
# I'm accessing obj data and if it's empty assigning 0, you can add your own check instead
return obj.get('input1', 0)*2
def get_key2(self, obj):
# same deal, do whatever calculations you want with the input data
return obj.get('input2')
def get_key3(self, obj):
# your logic
return
def get_key4(self, obj):
return
For every field declared as SerializerMethodField, you should have a corresponding get_field method.
It's up to you how to get the input params, you can do it either through query params or body data.
Call the serializer like this in your view, for example with body params:
class ExampleRetrieveApiView(APIView):
def get(self, request):
input_data = {'input1':request.data.get('input1'),
'input2':request.data.get('input2')}
serializer = ExampleSerializer(input_data)
return Response(serializer.data)
views
class ExampleAPIView(APIView):
serializer_class = ExampleSerializer
def get(self, request):
serializer = ExampleSerializer(data=request.query_params)
if serializer.is_valid(raise_exception=True):
return(Response(serializer.data))
serializers
class ExampleSerializer(serializers.Serializer):
param1 = serializers.IntegerField()
param2 = serializers.CharField()
def validate(self, data):
#custom logic
data['param3'] = 'text'
#another params
return data
def to_representation(self, data):
return {
'key1': data['param3']
'key2': data['param4']
#another key for representation
}

Resources