Passing pk in a get request function - django-rest-framework

I am new to Django so I figure this question could be a bit stupid.I have an api endpoint that returns a list of Doctors(and their details) and another that returns one doctor(and his details)-this is the call am trying to make.I think the issue I am having is with how to ref the pk in the request url.
As it is, when I test on postman I get the error {
"errors": "JSONDecodeError('Expecting value: line 1 column 1 (char 0)',)",
"status": "error"
}
I am almost certain the issue is in api_services.py.I really hope someone can just point it out to me.
views.py
`class FinanceDoctorsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
response = {}
pk = kwargs.get("pk")
try:
result = {}
auth = cc_authenticate()
res = getDoctorInfo(auth["key"], pk)
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_services.py
import requests
def getDoctorInfo(auth, params):
print("getting doctorInfo from Callcenter")
try:
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/finance/doctor-info/<int:pk>'
res = requests.get(url, headers=headers)
print("returning doctorInfo response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path(
"doctor-info/<int:pk>", views.FinanceDoctorsView.as_view(), name="doctor_info"
),

I think in the api service file, you have made a typo
url = f'{CC_URL}/finance/doctor-info/<int:pk>'
Should had be
# as in the function you have defined params,
# and I think it could have been renamed as pk
url = f'{CC_URL}/finance/doctor-info/{params}'

Related

My function does not execute when using await in a async function pyscript

I try to fetch data from my api in python using pyscript. Following the pyscript documentation I use the async keyword on my main function and use asyncio.ensure_future to execute it, everything before the first await work but not the await keyword and any other line of code after it.
This is my code:
async def request(url: str,
method: str = "GET",
body: Optional[str] = None,
headers: Optional[dict[str, str]] = None,
**fetch_kwargs: Any) -> FetchResponse:
kwargs = {
"method": method,
"mode": "no-cors"
} # CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
if body and method not in ["GET", "HEAD"]:
kwargs["body"] = body
if headers:
kwargs["headers"] = headers
kwargs.update(fetch_kwargs)
response = await pyfetch(url, **kwargs)
return response
async def get_barycenter(
filename: str,
base_url: str = "http://localhost:8001") -> dict[str, Any] | None:
headers = {"Content-type": "application/json"}
response = await request(f"{base_url}/barycenter/?image_name={filename}",
headers=headers)
body = await response.json()
if body.status != 200:
return None
return body.msg
async def main():
print('start')
test = await get_barycenter("img.jpg")
print(test)
print("end")
asyncio.ensure_future(main())
The result is only the print of start and nothing else no print of test are even "end".
I tested the API the data is visible in Insomnia and I set up correctly the cors Policy.
Part of the issue here is an existing issue in PyScript where exceptions raised in Coroutines aren't displayed on the page. To help with this for now, I would recommend adding the following snippet before your request function:
import js
def handler(loop, context):
js.console.error(context.message)
raise(context.exception)
pyscript.loop.set_exception_handler(handler)
This way, exceptions raised in coroutines are displayed in the browser's console log.
What the root issue of the the fetch request is I couldn't say, but at least this will get errors displaying and help you troubleshoot. For example, when I run your code, I see:
GET http://localhost:8001/barycenter/?image_name=img.jpg net::ERR_CONNECTION_REFUSED
Since I don't have a local server running - hopefully the errors that appear for you are more helpful.

Adding user object to scope django-channels

I am trying to add websockets to my app. I use JWT tokens so I have to overide middleware for it.
#database_sync_to_async
def get_user(token):
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=ALGORITHM)
except:
return AnonymousUser()
token_exp = datetime.fromtimestamp(payload['exp'])
if token_exp < datetime.utcnow():
return AnonymousUser()
try:
response = requests.get(settings.OAUTH_URL, headers={'Authorization': f"Bearer {token}"})
if response.status_code == 200:
user = response.json()
return user
except:
error_logger.exception("Server is not available!")
class TokenAuthMiddleware(BaseMiddleware):
async def __call__(self, scope, receive, send):
close_old_connections()
try:
token_key = (dict((x.split('=') for x in scope['query_string'].decode().split("&")))).get('token', None)
except ValueError:
token_key = None
scope['user'] = await get_user(token_key)
return await super().__call__(scope, receive, send)
def JwtAuthMiddlewareStack(inner):
return TokenAuthMiddleware(AuthMiddlewareStack(inner))
My service is a microservice so the User model is located in another service. So I have to send a request to the service where the instance model is located. When I try to add "user" dict-like object to scope it returns me an error:
helpdesk_web | File "/usr/local/lib/python3.10/site-packages/channels/auth.py", line 176, in resolve_scope
helpdesk_web | scope["user"]._wrapped = await get_user(scope)
helpdesk_web | AttributeError: 'dict' object has no attribute '_wrapped'
If I delete this line scope['user'] = await get_user(token_key) or pass to the function model instance everything works.
Is there a way to add 'users' dict-like object instead of model instance to scope?

Accessing data POST'd to a python AWS Lambda Function URL

I'm attempting to invoke an AWS Lambda Function URL in Python. Using their example lambda code as follows the value for action is always returning null. How do I access the value in the json data I POST to the Function URL?
Lambda Code (taken from here):
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
result = None
action = event.get('action')
if action == 'increment':
result = event.get('number', 0) + 1
logger.info('Calculated result of %s', result)
else:
logger.error("%s is not a valid action.", action)
response = {'result': result}
return response
Invoking using a Function URL
curl -X POST 'https://[redacted].lambda-url.eu-west-1.on.aws/' -d '{"action":"increment","number": 3}'
Result:
{"result":null}
Problem:
How do I reference the value of 'action' correctly to produce the result?
Out of interest, this is how I adapted the AWS sample code to parse the required fields
import logging
import json
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
message = json.loads(event['body'])
result = None
action = message['action']
if action == 'increment':
result = message['number'] + 1
logger.info('Calculated result of %s', result)
else:
logger.error("%s is not a valid action.", action)
response = {'result': result}
return response

Testing POST with authentication in Django Rest Framework issue 401 returing

I'm trying to test POSTing data to a view in django-rest-framework that requires authentication. But I can't. I've read many threads of supposed solutions, but can't find any that solves to me.
Test:
class TodoListCreateAPIViewTestCase(APITestCase):
url = reverse("todolist:add")
def setUp(self):
self.username = "john"
self.email = "john#snow.com"
self.password = "you_know_nothing"
self.user = User.objects.create_user(self.username, self.email, self.password)
self.token = Token.objects.create(user=self.user)
#checking token here
def test_create_todo(self):
self.client.login(email=self.email, password='you_know_nothing')
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = self.client.post(self.url, {"list_name": "Clean the room!"}, format='json')
self.assertEqual(201, response.status_code)
View
class Addtodolist(APIView):
authentication_classes = (JSONWebTokenAuthentication,TokenAuthentication)
permission_classes = [IsAuthenticated, ]
def post(self, request):
data = request.data
todolist_instance = Todolist.objects.filter(for_user=self.request.user).first()
if not todolist_instance:
list_serilaizer = AddtodolistSerializers(data=data, context={'user': request.user})
if list_serilaizer.is_valid():
list_serilaizer.save()
return Response(data=success_response(data=list_serilaizer.data, msg='Successfully Created list!'),
status=status.HTTP_200_OK)
else:
return Response(
failure_response(data={'detail': list_serilaizer.errors()}, msg='Following errors occured'),
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(
failure_response(data={'detail': 'User can have only 1 List'}, msg='User can have only 1 List'),
status=status.HTTP_409_CONFLICT)
Change your code like this:
from django.shortcuts import reverse
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient, APITestCase
from rest_framework.authtoken.models import Token
class TodoListCreateAPIViewTestCase(APITestCase):
url = reverse("todolist:add")
def setUp(self):
self.username = "john"
self.email = "john#snow.com"
self.password = "you_know_nothing"
self.user = get_user_model().objects.create_user(self.username,
self.email,
self.password)
self.token = Token.objects.create(user=self.user)
def test_create_todo(self):
client = APIClient()
client.login(username=self.username,
email=self.email,
password=self.password)
client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = client.post(self.url,
{"list_name": "Clean the room!"},
format='json')
self.assertEqual(response.status_code, 201)

How to get and delete access token django api

I want to get access token and delete it in logout api.But i am unable to get access token for the current log in user.
models.py
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
account = self.model(
email=self.normalize_email(email),
)
account.account_type = extra_fields.get('account_type')
account.set_password(password)
account.save(using=self._db)
return account
def create_superuser(self, email, password, **extra_fields):
account = self.create_user(
email,
password=password,
)
account.account_type = 'A'
account.is_admin = True
account.save(using=self._db)
return account
class Account(AbstractBaseUser):
type_choice = (
('A', 'Admin'),
('S','Student'),
('T','Teacher'),
)
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
account_type = models.CharField(choices=type_choice, max_length=1, null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
#views.py
class AccountViewSet(viewsets.ViewSet):
def create(self,request):
# permission_classes = [TokenHasReadWriteScope]
try:
email=request.data.get('email')
password=request.data.get('password')
print(request.data)
# account_type=request.data.get('account_type')
if not all([email,password]):
raise Exception('All Fields are mandatory')
obj=Account()
obj.email=email
obj.set_password(password)
obj.save()
Application.objects.get_or_create(user=obj, client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_PASSWORD)
token = get_access_token(obj)
return Response({"response":token, "success": True}, status=status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
def list(self,request):
try:
user=Account.objects.all()
users=[]
for i in user:
users.append({
"name":i.name,
"Address":i.Address,
"account_type":i.account_type,
})
return Response({"success":True, "users":users})
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
def retrieve(self, request, pk=None):
user = Account.objects.get(id=pk)
data = {
"name":user.name,
"email":user.Address,
#"password" : user.password,
#"date_of_birth":user.date_of_birth,
"account_type":user.account_type
}
return Response({"data":data,"success":True})
def destroy(self, request, pk=None):
employee = Account.objects.get(id=pk).delete()
print('>>>>>>>>>>',employee)
#employee.delete()
return Response({"success":'done',"message":"delete called"})
class LoginViewSet(viewsets.ViewSet):
def create(self,request):
try:
email = request.data.get('email')
password = request.data.get('password')
print(email,password)
if not all([email,password]):
raise Exception('all fields are mandatory')
acc = Account.objects.get(email = email)
print(acc.check_password(password))
account = authenticate(username=email,password=password)
print(account)
if account is not None:
token = get_access_token(account)
obj = Account.objects.get(email=account)
data = {
"email":account.email,
}
else:
raise Exception('Credential not matched')
return Response({"message": "Login Successfully", "user_info": data, "token": token, "Success": True}, status = status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message":str(error),"success":False},status = status.HTTP_200_OK)
class LogoutViewSet(viewsets.ViewSet):
def list(self, request, format=None):
accesstoken=AccessToken.objects.get(token=request.META.get('HTTP_AUTHORIZATION'))
return Response('response',status=status.HTTP_200_OK)

Resources