I am new to Django and a small detail has been bothering me.I have an api endpoint that returns the details of one patient. I have made a successful get request and tested on postman. It returns data for a particular patient with id = 996(I have hard coded the id). But I need to set it so it can pick the id from params in postman instead of the hard coded one here. How can I set params and append them on the url so that I use the id fed in postman instead of hard coding? Kindly assist
views.py
class PatientDetailsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
try:
result = {}
auth = cc_authenticate()
res = getPatientDetails(auth["key"], id)
result = res
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
error = getattr(e, "message", repr(e))
result["errors"] = error
result["status"] = "error"
return Response(result, status=status.HTTP_400_BAD_REQUEST)
api_service.py
def getPatientDetails(auth, id):
print("getting patientdetails from Callcenter")
try:
print(auth)
# print(url)
id= 996
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/patients/v1/details/?id={id}'
print(url)
res = requests.get(url, headers=headers)
print("returning patientdetails response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path("details/", views.PatientDetailsView.as_view(), name="patient_info"),
This is the code I needed
id = request.GET.get('<id>')
Related
I have a post method under View Set. I need to write a unit test case for the method. when I pass param its give None. How should I pass both param and data(payload).
views.py
#action(detail=True, methods=['post'])
def complete_task(self, request, *args, **kwargs):
"""
Method for complete the task
input post request : task_id : str, variable_return:boolean, request data: dict
output Response : gives whether task is completed or not
"""
try:
get_task_id = self.request.query_params.get("task_id")
get_process_variables = request.data
print(get_task_id)
print(get_process_variables)
complete_task = CamundaWriteMixins.complete_task(url=CAMUNDA_URL, task_id=get_task_id,
process_variable_data=get_process_variables)
print("compl", complete_task)
return Response({"task_status": str(complete_task)})
except Exception as error:
return Response(error)
test.py
def test_completed_task(self):
self.client = Client()
url = reverse('complete-task')
data = {"variables": {
"dept_status": {"value": "approved", "type": "String"}}
}
response = self.client.post(url, data=data, params={"task_id": "000c29840512"},
headers={'Content-Type': 'application/json'})
print(response.data)
self.assertTrue(response.data)
I have tried above test case method which is getting request data but I got param None.
Thanks in Advance,.
if you just modify your request a bit and add query param as part of your url then i guess you are good to go.
Example:
response = self.client.post(f'{url}?task_id=000c29840512', data=data,
headers={'Content-Type': 'application/json'})
you can refer the official documentation for the example: https://docs.djangoproject.com/en/4.0/topics/testing/tools/
I'm currently struggling to make this current unit-test pass:
def test_markNotifications(self):
request_url = f'Notifications/mark_notifications/'
view = NotificationsViewSet.as_view(actions={'post': 'mark_notifications'})
request = self.factory.post(request_url)
request.POST = {'id_notifs': "1"}
force_authenticate(request, user=self.user)
response = view(request)
self.assertEqual(response.status_code, 200)
Here's the associated view:
#action(detail=False, methods=['POST'])
def mark_notifications(self, request, pk=None):
"""
Put Notifications as already read.
"""
id_notifs = request.POST.get("id_notifs")
if not id_notifs:
return Response("Missing parameters.", status=400)
id_notifs = str(id_notifs).split(",")
print(id_notifs)
for id in id_notifs:
notif = Notification.objects.filter(pk=id).first()
if not notif:
return Response("No existant notification with the given id.", status=400)
notif.isRead = True
notif.save()
return Response("Notifications have been marked as read.", status=200)
The problem is that even though I'm passing "id_notifs" through the request in test, I'm getting None when I do id_notifs = request.POST.get("id_notifs").
It seems that the id_notifs I'm passing in the POST request are neither in the body and the form-data. In this context, I have no idea on how to access them.
Looking forward some help, thanks.
I want to send post request from testing. Its working for postman but it didnot work for my test case. How can I give the data by post request.
Views.py,
class PersonalInfoAPI(viewsets.ViewSet):
permission_classes = [IsOwnerPermission]
def get_object(self, pk):
obj = get_object_or_404(Employee.objects.all(), pk=pk)
self.check_object_permissions(self.request, obj)
return obj
def create(self, request):
personal_info = JSONParser().parse(request)
.....
return ...
test.py
url = reverse('employee1-list')
self.client = Client(HTTP_AUTHORIZATION='Token ' + token.key)
resp1 = self.client.post(url, {"data": {
"appraisal_master_id": 1,
"personal_info": {
"employee_id": 1,
"experience": "abcd",
"education": "Nonoooo"
}
}
}, format='json')
print(resp1)
self.assertEqual(resp1.status_code, 200)
I have got 400 error. Please, tell anyone how can I pass data im properway,..
I got solution. When I gave request which passes dictionary data. then, I coverted into json its working fine.
url = reverse('employee1-list')
self.client = Client(HTTP_AUTHORIZATION='Token ' + token.key)
resp1 = self.client.post(url, data=data, content_type="application/json")
print(resp1)
self.assertEqual(resp1.status_code, 201)
I have defined the following custome action for my ViewSet Agenda:
class AgendaViewSet(viewsets.ModelViewSet):
"""
A simple viewset to retrieve all the Agendas
"""
queryset = Agenda.objects.all()
serializer_class = AgendaSerializer
#action(detail=False, methods=['GET'])
def get_user_agenda(self, request, pk=None):
print('here1')
id = request.GET.get("id_user")
if not id:
return Response("No id in the request.", status=400)
id = int(id)
user = User.objects.filter(pk=id)
if not user:
return Response("No existant user with the given id.", status=400)
response = self.queryset.filter(UserRef__in=user)
if not response:
return Response("No existant Agenda.", status=400)
serializer = AgendaSerializer(response, many=True)
return Response(serializer.data)
Here, I'd like to unit-test my custom action named "get_user_agenda".
However, when I'm testing, the debug output("here1") doesn't show up, and it always returns 200 as a status_code.
Here's my test:
def test_GetUserAgenda(self):
request_url = f'Agenda/get_user_agenda/'
view = AgendaViewSet.as_view(actions={'get': 'retrieve'})
request = self.factory.get(request_url, {'id_user': 15})
response = view(request)
self.assertEqual(response.status_code, 400)
Note that:
self.factory = APIRequestFactory()
Am I missing something?
Sincerely,
You will have to use the method name of the custom action and not retrieve so:
view = AgendaViewSet.as_view(actions={'get': 'get_user_agenda'})
You have to specify request url
#action(detail=False, methods=['GET'], url_path='get_user_agenda')
def get_user_agenda(self, request, pk=None):
And in my opinion it would be better to use detail=True, and get pk from url.
For example: 'Agenda/pk_here/get_user_agenda/'
The scenario is quite straight-forward:
Say i have a user model where email should be unique. I did a custom validation for this like.
def validate_email(self, value):
if value is not None:
exist_email = User.objects.filter(email=value).first()
if exist_email:
raise serializers.ValidationError("This Email is already taken")
return value
from rest_framework response when input validation occur we should return status_code_400 for BAD_REQUEST but in this scenario we should or we need to return status_code_409 for conflicting entry. What is the best way to customize status_code response from serializer_errors validation.
I think is better to define custom exception_handler like:
settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'myproject.common.custom_classes.handler.exception_handler',
}
handler.py
def exception_handler(exc, context):
# Custom exception hanfling
if isinstance(exc, UniqueEmailException):
set_rollback()
data = {'detail': exc.detail}
return Response(data, status=exc.status_code)
elif isinstance(exc, (exceptions.APIException, ValidationError)):
headers = {}
if getattr(exc, 'auth_header', None):
headers['WWW-Authenticate'] = exc.auth_header
if getattr(exc, 'wait', None):
headers['Retry-After'] = '%d' % exc.wait
if hasattr(exc, 'error_dict') and isinstance(exc, ValidationError):
exc.status_code = HTTP_400_BAD_REQUEST
data = exc.message_dict
elif isinstance(exc.detail, (list, dict)):
data = exc.detail
else:
data = {'detail': exc.detail}
set_rollback()
return Response(data, status=exc.status_code, headers=headers)
elif isinstance(exc, Http404):
msg = _('Not found.')
data = {'detail': six.text_type(msg)}
set_rollback()
return Response(data, status=status.HTTP_404_NOT_FOUND)
return None
exceptions.py
class UniqueEmailException(APIException):
status_code = status.HTTP_409_CONFLICT
default_detail = 'Error Message'
And finally the validator:
def validate_email(self, value):
if value is not None:
exist_email = User.objects.filter(email=value).first()
if exist_email:
raise UniqueEmailException()
return value
I would go for intercepting ValidationError exception and return the Response object with 409 status code:
try:
serializer.is_valid(raise_exception=True)
except ValidationError, msg:
if str(msg) == "This Email is already taken":
return Response(
{'ValidationError': str(msg)},
status=status.HTTP_409_CONFLICT
)
return Response(
{'ValidationError': str(msg)},
status=status.HTTP_400_BAD_REQUEST
)
Short answer:
You can't return custom response codes from a serializer.
This is because the serializer is just that: A Serializer. It doesn't, or shouldn't, deal with HTTP at all. It's just for formatting data, usually as JSON, but it'll usually do HTML for showing your API, and one or two other formats.
Long answer:
One way to accomplish this is to raise something (doesn't matter what, but make it descriptive) in your serializer, and add code to your view to catch the error. Your view can return a custom response code with a custom response body as you like it.
Like this:
add something like this to your view class:
def create(self, request, *args, **kwargs):
try:
return super().create(request, *args, **kwargs)
except ValidationError as x:
return Response(x.args, status=status.HTTP_409_CONFLICT)