I am trying to send a JSON response from Django back-end to my angular front-end.
When I make the request I receive nothing in Postman or Angular but,opening the link in browser seems to be returning the correct result
My View is :
#api_view(['GET'])
def my_view(request):
print(request.user.username)
return JsonResponse({'username': request.user.username})
When I open http://127.0.0.1:8000/accounts/get_username/ in browser I receive
{"username": "aditya8010"} on the web page.
But when i do a get request using POSTMAN I recieve
{
"username": ""
}
Same with Angular
this.http.get("http://127.0.0.1:8000/accounts/get_username/").subscribe((res) => {
this.username = JSON.stringify(res["username"])
console.log(this.username," ", res)
})
this code also prints an empty username string.
Another thing I have noticed is that my print statement in the view does print anything random I put in there when called from POSTMAN or Browser but when I use request.user.username it doesnt print anything when called by POSTMAN.
And each time the response code is 200
What am I doing wrong.
When you're sending the request you are not providing authentication credentials (i.e. something that identifies the user that is sending the request). How do you obtain this credentials?
You need to establish an authentication method. There are several but I recommend using Token authentication with knox package. Basically, you have an endpoint that logins the user with his username and password (normal json post request) and that endpoint returns a token. This token is what identifies the user. You send this token in the header of each request you need to be authenticated. That means you probably should include an IsAuthenticated permission for the view. In postman:
API view:
from rest_framework.permissions import IsAuthenticated
#api_view(['GET'])
#authentication_classes([IsAuthenticated])
def my_view(request):
print(request.user.username)
return JsonResponse({'username': request.user.username})
When it is in a browser, your login information is remembered in the session. When using postman or Angular, you need to provide the user's information in the request header manually.
I am using Angular and Django in my stack for a website, and after a user registers it emails them a link to activate their account. As of right now everything is working but the link takes the user to the Django rest framework page.
I've been returning responses in my app like this
data = {'success': True, 'message': 'An account has been activated.', 'response': {}}
return Response(data, status=status.HTTP_201_CREATED)
I am curious on how to redirect a user back to the login page which at the current moment would be a localhost page such as http://localhost:4200/#/authentication/login.
From research I have found methods like
return redirect('http://localhost:4200/#/authentication/login')
but I am wanting to keep my responses consistent. Is there a way to redirect a user while still using the rest api Response object?
After thinking about the comment posted by Muhammad Hassan, I realized I was thinking about this all wrong. Instead of sending a Django url I have change the email to send a URL to an Angular page I made and then I just sent an HTTP request from that page to the Django URL.
I develop a django application where I have a d3js interactive tree. I use d3.json to get the tree data from the django view. I have create a decorator to check if user is logged to allowed the request or not. I have no problem when the user is logged but when the decorator return the jsonResponse with redirection url I have only the status error with the status description.
I read d3js and promise documentation but I'm not found a answer to return a jsonresponse with my custom response.
d3.json(d.data.url).then(function(data) {
// process data no problem
}, function(error){
console.log(error);
});
def check_user_permission_js(view_function):
#wraps(view_function)
def wrapper(request, *args, **kwargs):
if request.user.is_authenticated:
return view_function(request, *args, **kwargs)
messages.warning(request,
"Your account doesn't have access to this page "
+ "or your session has expired. "
+ "To proceed, please login with an account that has access.")
return JsonResponse({'not_authenticated': True,
'redirect_url': settings.LOGIN_URL,'data':[]}, status=500)
return wrapper
I think this question is not specific to d3 or frontend code.
If you are using d3 v5, d3.json is a thin wrapper around the browser fetch API documented here, which seems to be correctly returning a non 200 status code. If the problem is that you're not getting the custom fields provided in JsonResponse to appear in the response returned to the frontend, then the issue is related to usage of the Django JsonResponse method, it isn't something that using a different data fetching library would change.
I No I don't think the error comes from django because I already use JSONresponse with ajax requests that work very well. Exemple:
$.ajax({
url: "/browser/project/get-header",
type: "POST",
success: function(data) {
// process my data
},
error: function(jqXHR){
if (jqXHR.responseJSON.message){
writeMessages(jqXHR.responseJSON.message, 'error');
}
else{
writeMessages(
'An error occur: the sample list can not be loaded!',
'error');
}
}
});
My problem is related to fetch and how d3js returns the error with d3.json.
To temporarily solve my problem I use requests like the one above but in the end I would like to use only the functions of D3JS.
I'm using a django-oneall to allow social login session authentication on my site. While it isn't one of the suggested auth providers for django-rest-framework, rest_framework.authentication.SessionAuthentication uses django's default session authentication. so I thought it should be fairly simple to integrate.
On the permissions side, ultimately I'll use IsAdmin, but for development purposes, I just had it set to IsAuthenticated. When that returning 403s, I relaxed the permissions to AllowAny, but still no dice. Here's my rest framework config:
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
# 'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.permissions.IsAdminUser',
),
'PAGE_SIZE': 100,
'DEFAULT_FILTER_BACKENDS': (
'rest_framework.filters.DjangoFilterBackend',
),
}
EDIT:
I got this working based on the answer below. It turns out that rest_framework expects both the csrftoken cookie and a a X-CSRFToken Header of the same value, I setup my front-end code to send that header for all ajax requests and everything worked fine.
Django REST Framework returns status code 403 under a couple of relevant circumstances:
When you don't have the required permission level (e.g. making an API request as an unauthenticated user when DEFAULT_PERMISSION_CLASSES is ('rest_framework.permissions.IsAuthenticated',).
When you doing an unsafe request type (POST, PUT, PATCH or DELETE - a request that should have side effects), you are using rest_framework.authentication.SessionAuthentication and you've not included your CSRFToken in the requeset.
When you are doing an unsafe request type and the CSRFToken you've included is no longer valid.
I'm going to make a few demo requests against a test API to give an example of each to help you diagnose which issue you are having and show how to resolve it. I'll be using the requests library.
The test API
I set up a very simple DRF API with a single model, Life, that contains a single field (answer, with a default value of 42). Everything from here on out is pretty straight forward; I set up a ModelSerializer - LifeSerializer, a ModelViewSet - LifeViewSet, and a DefaultRouter on the /life URL route. I've configured DRF to require user's be authenticated to use the API and to use SessionAuthentication.
Hitting the API
import json
import requests
response = requests.get('http://localhost:8000/life/1/')
# prints (403, '{"detail":"Authentication credentials were not provided."}')
print response.status_code, response.content
my_session_id = 'mph3eugf0gh5hyzc8glvrt79r2sd6xu6'
cookies = {}
cookies['sessionid'] = my_session_id
response = requests.get('http://localhost:8000/life/1/',
cookies=cookies)
# prints (200, '{"id":1,"answer":42}')
print response.status_code, response.content
data = json.dumps({'answer': 24})
headers = {'content-type': 'application/json'}
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (403, '{"detail":"CSRF Failed: CSRF cookie not set."}')
print response.status_code, response.content
# Let's grab a valid csrftoken
html_response = requests.get('http://localhost:8000/life/1/',
headers={'accept': 'text/html'},
cookies=cookies)
cookies['csrftoken'] = html_response.cookies['csrftoken']
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (403, '{"detail":"CSRF Failed: CSRF token missing or incorrect."}')
print response.status_code, response.content
headers['X-CSRFToken'] = cookies['csrftoken']
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (200, '{"id":1,"answer":24}')
print response.status_code, response.content
Just for anyone that might find the same problem.
If you are using viewsets without routers like:
user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})
Django Rest framework will return 403 unless you define permission_classes at a class level:
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset for viewing and editing user instances.
"""
permission_classes= YourPermisionClass
Hope it helps!
For completeness sake, there is one more circumstance under which DRF returns code 403: if you forget to add as_view() to the view declaration in your urls.py file. Just happened to me, and I spent hours until I found where the issue was, so maybe this addition can save some time for someone.
For those that aren't able to even access their csrftoken from Javascript:
In my case I wasn't able to get the csrftoken from my Javascript code to be able to set it in my ajax POST. It always printed null. I finally discovered that the django CSRF_COOKIE_HTTPONLY environment variable was set to True.
From the Django Documentation
CSRF_COOKIE_HTTPONLY: If this is set to True, client-side JavaScript will not be able to access the CSRF cookie."
Changing CSRF_COOKIE_HTTPONLY to False allowed me to finally get the csrftoken.
https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_HTTPONLY
One more situation that someone may find is that you get a 403 error on an AllowAny route when you pass an token as null in the "Authorization" header in your request. For example, you may want to allow anyone to use the route but also want to know if the person that used the route is an authenticated user.
E.g.
if (token) {
headers = {
"Content-Type": "application/json",
"Authorization": "Token " + token
}
} else {
headers = {
"Content-Type": "application/json"
}
}
I have a Django site using a 5-star rating system for voting (I use django-ratings) and I would like to store the votings of the users with AJAX calls.
On the client side I have a JavaScript function sending a GET request to a URL:
$.ajax({
url: url,
success: function(data) {
alert('Load was performed.');
}
});
On the server side I have code setting the cookie:
def vote(request, slug, rating):
# Some irrelevant code...
response = HttpResponse('Vote changed.')
response.set_cookie('vote', 123456)
return response
The problem is that the cookie is never set in the browser.
What I am doing wrong?
Thanks!
Are sure that your problem is about Cross-site request forgery protection? most ajax requests rejected django by that. Don't you have any error messages?