I'm trying to do an endpoint API. And for that, i'm using django.
My url in urls.py is :
path('tutorials/', tutorial_list_test.as_view()),
and my views.py is like
class tutorial_list_test(GuestOnlyView, FormView):
print("test");
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
request = self.request;
if request.method == 'POST':
alldata=request.POST
username = alldata.get("username", "0")
print("POST name: " + username)
return Response('The tutorial does not exist', status=status.HTTP_404_NOT_FOUND)
But when i'm doing a request, i have everytime the same error "Forbidden (CSRF cookie not set.): /accounts/tutorials/"
So I did some research, and I could see several proposed solutions.
The first was to use csrf_exempt but it's not working for me:
path('tutorials/', csrf_exempt(tutorial_list_test.as_view())),
And it's the same for all the methods I used. Even if I remove this line from my settings.py, nothing changes
# django.middleware.csrf.CsrfViewMiddleware',
To test, I use Postman, but even using my angular front end, it does the same.
const formData = new FormData()
formData.append('username', this.username_signup);
this.http.post('http://127.0.0.1:8000/accounts/tutorials/', formData)
.map((data: Response) => {
if (data !== null) {
console.log(JSON.stringify(data));
};
}).subscribe(response => console.log(response))
I would like to know if you have any idea how I can do this.
Because I need to be able to access my Models, so not using a class and directly making a def is not an option, even if it works.
(I tried, effectively my requests pass, if I remove the class and my route is only linked to my def tutorial_list).
Thank you.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
# code
Related
I have the following requirement:
Send data to backend using fetch()
receive the data in a view and render another template ( route to a different view)
The following is my code snippet:
JS:
fetch("/addpost", {
method: "POST",
body: JSON.stringify({ value: selecteddict }),
headers: {
"Content-type": "application/json;",
},
})
.then((res) => {
return res.text();
})
.then((text) => {
console.log(text);
});
// the data is being sent successfully
Django View1:
#csrf_exempt
def addpost(request):
if request.method == 'POST':
song = json.loads(request.body.decode('utf-8'))['value']
print(song)
# I want to redirect to another view called createpost that renders a new page
return JsonResponse({'status':201})
return render(request, 'addpost.html')
Django createpost view:
def createpost(request):
return render(request, 'createpost.html')
The view createpost is working fine when given the required path but it is not rendering when it's redirected from addpost
Please suggest a solution to this.
Your addpost view returns as JsonResponse in case of a POST request. If you want to redirect somewhere you need to use redirect() instead of JsonResponse()
I have a Django view where when a user performs a certain task, an external Python microservice retrieves and then sends some data to the Django view, which is supposed to show it to the user on the template. To send the data i'm using Python requests, the problem is that the Json response is being refused by Django for two reasons: 1) The CSRF Token is not set 2) The view is #login_required
Here is my view:
#login_required
def myTestView(request):
if request.method == 'POST':
received_json_data=json.loads(request.body)
print(received_json_data)
print('received.')
And here is how i send the response:
import requests
req = requests.post('http://127.0.0.1:8000/myTestView/', json={"test": "json-test"})
print('SENT')
With the actual code, i get this error from Django:
Forbidden (CSRF cookie not set.): /myTestView/
[2019-12-24 15:36:08,574] log: WARNING - Forbidden (CSRF cookie not set.): /myTestView/
I know i can use #csrf_exempt, but since the data that i'm sending is personal, i would like it to be as safe as possible, so i need to find a way to send the CSRF Token. The second thing i need to do, is how do i "login" using the request?
I like this question, so I'll try to describe the whole process in detail.
Server side.
First step is to get csrf_token which you'll use in the further post request.
After that you have to authenticate the session.
So let's write a view to serve get for getting csrf_token and post for authenticating session. The same idea for protected view.
After we get authenticated it is possible to access protected view.
import json
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseForbidden
from django.middleware.csrf import get_token
#login_required
def myTestView(request):
if request.method == 'POST':
data = request.POST.get('data')
print(json.loads(data))
print('received.')
response = HttpResponse(get_token(request))
return response
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return HttpResponse('authenticated')
else:
return HttpResponseForbidden('wrong username or password')
response = HttpResponse(get_token(request))
return response
Client side.
requests.post does not fit for this task because it can't track (or it's really hard) request cookies and headers.
But you can use for this purpose requests.session()
Django is not able to process csrf_token in json, that's why you have to pass json in request data.
import json
import requests
session = requests.session()
token = session.get('http://127.0.0.1:8000/login/')
session.post('http://127.0.0.1:8000/login/',
data={
'username': '<username>',
'password': '<password>',
'csrfmiddlewaretoken': token})
token = session.get('http://127.0.0.1:8000/myTestView/')
data = json.dumps({'test': 'value'})
session.post('http://127.0.0.1:8000/myTestView/',
data={
'csrfmiddlewaretoken': token,
'data': data})
Mind adding urls.py for the views
I checked this code and it is working well. If anyone has an ideas how to improve it I will love to update it.
I need return redirect(url) or something like this in django, and force template to do to this url.
It returns me template html-code instead when EXACTLY redirect is required.
Any ideas? Now i have to write redirect in templates window.location='url' , it works, but make code tangled.
django.__version__ == '2.0.1'
I need django text, that does like javascript window.location='myurl'
Part of view
#csrf_exempt
def CheckState(request):
...
try:
... if (condition):
a = redirect('/mypage/')
...
return a #redirect('http://localhost:port/mypage/')
part of template (js.code)
$(document).ready(function() {
$.get('/my/CheckState/', {})
.success(function(data){
console.log(data);
//window.location = 'url' works here, otherwice no redirect!
//In console i see html-code of 'http://localhost:port/mypage/'
})
.error(function(xhr, textStatus, errorThrown){
console.log(xhr.responseText);
})
--comment--
a._headers = {'content-type': ('Content-Type': 'text/html; charset=utf-8'),
'location' : ('Location', '/mypage' )}
I saw this header before i asked question, but problem exists - no jump doing. Why is this redirect not working?
It's not possible to prevent $.get() (which uses Xmlhttprequest) from following the redirect. See this question for an explanation.
You might be able to use the fetch API which does allow you to prevent redirects.
If you can't do that, you could change the view to return the new URL in the response,
from django.http import JsonResponse
def CheckState(request):
return JsonResponse({'status': 'redirect', 'url': '/new/url/'})
...
Then in your ajax handler, check the response for status=redirect, and if so set window.location to the url.
I'm trying to figure out how to redirect to a simple html response page after post in Django rest framework application.
this is how model looks like in web:
Form for file upload:
And after click on post button I have code in views.py that should redirect it on simple html but instead it stays on same page with empty queryset results and I don't know what I'm I doing wrong?
from rest_framework import viewsets
from api.models import UploadImage
from api.serializers import UploadedImageSerializer
from rest_framework import permissions
from rest_framework.parsers import MultiPartParser,FormParser
from sqlite_queries import user_ips
class FileUploadViewSet(viewsets.ModelViewSet):
#create queryset view
permission_classes = (permissions.IsAuthenticated,)
queryset = UploadImage.objects.all()
serializer_class = UploadedImageSerializer
parser_classes = (MultiPartParser, FormParser,)
#after post action get this
def perform_create(self, serializer):
#grab request
image_name = self.request.data['image']
meta_data = self.request.META
username = self.request.user
REMOTE_ADDR = meta_data['REMOTE_ADDR']
#check user status, how many ip's he had over last 24 hours
user_status = user_ips(username)
#if user has more than allowed redirect to html page
if user_status == 400:
print ("how to redirect here?")
#return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#return HttpResponseRedirect("limit.html")
#if user iz valid continue with upload
serializer.save(user = username, meta_data= meta_data,remote_ip=REMOTE_ADDR)
If I have understand this correctly you don't want that some user overexcites the specific number of logins from different IP address in 24 hours. You can try like this but i suggest you do these steps in virtual environment python.
1.You can delete this part of code from your views.py:
#check user status, how many ip's he had over last 24 hours
user_status = user_ips(username)
#if user has more than allowed redirect to html page
if user_status == 400:
print ("how to redirect here?")
#return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#return HttpResponseRedirect("limit.html")
2.copy this sqlite_queries.py to Python 3\Lib so it could be used globally if you didn't.
3.Then we want to stop a login from a username that has exceeded number of allowed logins from different IP addresses. And based on the conversation with Fazil Zaid that you just want to do it with Django Rest Framework this is the way you could do it. How we gonna do it?
3.1 You have to open Python 3\Lib\site-packages\django\contrib\auth\forms.py
3.2 Inside you will go to function confirm_login_allowed that is inside class AuthenticationForm and at the start of the start of the function and this lines
from sqlite_queries import user_ips
#check user status, how many ip's he had over last 24 hours
user_status = user_ips(user,r'full_path_to_you_sqlite_db')
#if user has more than allowed redirect to html page
if user_status == 400:
raise forms.ValidationError(
self.error_messages['inactive'],
code='inactive',
)
Now if user matches you sql query and he will be stopped at login with message "This account is inactive.".
3.4 If you want to change error message to some custom text you should go to top of class AuthenticationForm and there you will find dictionary error_messages. Just add your key and value to dictionary and that is it.
Dragon, Assuming that you made this api call using ajax, you can get the response back to the calling ajax function and you can read the status / response and redirect using window.location.
Django rest framework
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Javscript Side
$.ajax({
url: 'link to your django restframe work api',
success: function (response) {
$('#post').html(response.responseText);
},
error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 400) {
window.location = "limit.html" //window.location = "{% django named url to limit view %}";
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
},
});
You can catch the 400 in the error part. Alternatively you may send a 200 with a custom message and handle the same within ajax success function too.
Hope it helps
I have a backend in django, and endpoint (rest framework) to login.
simple ajax
$.ajax({
type : "POST",
url : url+login/",
data : {username:username, password:password}
})
and simple view
#api_view(['POST'])
def login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = auth.authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth.login(request, user)
#When I type here: print request.session.items()
#I get _auth_user... things.
else:
pass
return Response({})
But when I change page in my native app, and there call another ajax e.g. url "test/", and this url call this view:
def test(request):
if request.user.is_authenticated():
print "Logged in
else:
#redirect to home...
return response
Then request.user.is_authenticated return False, looks like session expire is to small, so I try this:
...
auth.login(request, user)
#When I type here: print request.session.items()
#I get _auth_user... things.
request.session.set_expire(0)
...
But this doesn't work.
** EDIT **
Im using Django Rest Framework. And 'turn on':
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
I think you should consider using
'rest_framework.authentication.TokenAuthentication'
which will be much easier to handle on a mobile app, as you can just store the token after login, and use that token for any other API call. It also allows you to safely use csrf_exempt
AFAIK, $.ajax won't send any cookies if you are crossing domains, which you are doing by definition from a mobile app. So, I think your issue has to do with CORS and how you initialize the ajax call.
Try using:
xhrFields: { withCredentials:true }
on your .ajax call.
You also need to set up CORS (use django-cors-headers)
See http://www.django-rest-framework.org/topics/ajax-csrf-cors/ for other things that you may need to worry about. In particular
https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
But as I said, consider using tokens instead of sessions.
I've had troubles with Django and post variables before.
Try changing your $.ajax call to:
$.ajax({
type : "POST",
url : "yourURL/",
contentType: "application/x-www-form-urlencoded",
data : 'username='+encodeURIComponent(username)+'&password='+encodeURIComponent(password),
});