I created a custom "like" button. The "like" is inside a post form html element. For my view.py after i process the form post, i only want to return http response success and not load any type of success page. What kind of object would i return in this case?
Thanks,
David
You'll need to use Javascript to fire an ajax POST request, rather than a standard browser request because the behaviour you're trying to avoid is exactly what a standard request / response cycle does: browser triggers request and displays response as the next page.
Alternatively, you could probably use some kind of iframe, but that'd be just ugly.
You can just return a HTTP response without any content:
from django.http import HttpResponse
return HttpResponse()
Related
I am quite new to the web development world and have just built a Todo app using Django. I have used Django ModelForm for adding tasks to my TaskModel.
Now my problem is that each time I add a task, the whole page refreshes as the added task goes to the database. It is not a very good user experience, as it is refreshing the page on each task addition and also it is taking time for reloading the page. What should I do to stop page refresh but still add the task to the database?
my views.py looks something like this:
def index(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
form.save()
all_tasks = TaskModel.objects.all()
return HttpResponseRedirect(reverse("index"))
else:
all_tasks = TaskModel.objects.all()
return render(request, "todo_list/index.html", {"all_tasks": all_tasks})
Note: I have used authentication in my todo app so that the tasks can be accessed from any device, so I don't think storing my task merely in the browser cache will work. But I am open to any suggestions.
Back-end
Use django-rest-framework so that you can handle the server traffic manually.
Front-end
You can use a DOM API called XMLHttpRequest, but also you can use more easy to use APIs such as fetch.
When the form event is emitted we have to e.preventDefault().
form.addEventListener("submit", (e)=>{
e.preventDefault();
// use the same URL in form's action <form action="{{url}}"></form>
fetch(url, {
method: "POST",
data: new FormData(form),
})
.then((response)=>{
return response.json()
})
.then((json)=>{
return console.log(json);
})
.catch((err)=>{
console.err(err); // an error occured
});
});
The Django server can respond with a different type of data, plain/text or application/json are suitable in this situation.
BTW, fetch is a function that returns a Promise, so you can use async and await to make you code look better. You can use axios, or JQuery.ajax to make XMLHttpRequest more easy to handle.
Use django-restframework to create the API and then use frontend frameworks like react, vue and etc, to send post request to your Django server, So this way it wouldn't have to reload the page everytime
I am trying to do the following:
1) A payment solution is supposed to send an HTTP Post to my site
2) I would like to read the contents of the request(xml) and update my records to reflect the payment
I am trying this for the first time. When I create a URL path, and send a post to that address I get the csrf error.
Is there a way using Django wherein I can accept a post and don't have to return a response.
Thanks
Tanmay
Your view should return an http response, otherwise you will get an error. However, Django does not mind if that response does not contain any content. Your view can be as simple as:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def my_view(request):
# do something with request.POST
return HttpResponse("")
Since it is a third party that is submitting the post request, and not a user submitting a form on your site, you can mark the view as exempt from CSRF protection using the csrf_exempt decorator, as above.
Note that anyone could submit a post request to your url, so you should have some way of checking that the response is genuine. Your payment solution should be able to advise a suitable way to do this.
I have the following code
def ajax_login_request(request):
try:
request.POST[u'login']
dictionary = request.POST
except:
dictionary = request.GET
user = authenticate(username = dictionary[u'login'], password = dictionary[u'password'])
if user and user.is_active:
login(request, user)
result = True
else:
result = False
response = HttpResponse(json.dumps(result), mimetype = u'application/json')
return response
which is being called via ajax. I'm a noob and this is from an example in a book. Unfortunately the version of Django I'm using throws a CSRF error on this. I've done the other CSRF bits, but I don't know how to change the HttpResponse bit to a render call. I do not want to use CSRF_exempt, because I have no idea when that is appropriate. Can someone please provide me the equivalent render call for the HttpResponse above.
Thanks
To make your original code work, you need to get a RequestContext object and pass it along with your response, something like this:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ajax_login_request(request):
# ...
# This bit of code adds the CSRF bits to your request.
c = RequestContext(request,{'result':json.dumps(result)})
t = Template("{{result}}") # A dummy template
response = HttpResponse(t.render(c), mimetype = u'application/json')
return response
Do read up on the CSRF documentation as you might run into strange errors if you don't understand all the ways CSRF is "wired" in your app. The page also has a javascript snippet to make sure CSRF cookies are sent with your ajax requests if you are sending them without a form.
You can also use the render_to_response() shortcut, but you would need to have an actual template to load (in your case, you don't need a template, hence the "dummy" template in my example).
Ok, I'm going to re-draft this answer so you understand where I'm coming from. The CSRF middleware works like this:
You make request -------> request hits csrf --(invalid/no token)--> render 403
middleware
|
(valid token)
|
\ /
Call view
|
\ /
middleware sets
csrf cookie
|
\ /
Response appears
In other words, if you are seeing a 403 csrf page, your view was never called. You can confirm this by sticking a spurious print statement in the view and watching the output from runserver when you make your request.
To solve this, you either need to disable csrf (not good) or use one of the ajax methods available to you. If the required token is passed in your view will actually be executed.
The reason your view is not called is to prevent the action from the forged site from actually ever taking place - for example, if you denied the template at response time the user would already be logged in. The same behaviour occurs with the function decorators.
As for the middleware setting the cookie, that does not alter or depend on the render function at all - this sets the HTTP header Cookie: ... in the response. All responses in Django are HttpResponse objects until it finally converts them to output; render functions are helpers, but that's not what's causing your problem here.
Edit I'll convert what you've got to a render call. You could do this:
return render_to_response(`ajax_templates/login_response.html`,
{'loginresponse': json.dumps(result)})
Where ajax_templates/login_response.html is just:
{% loginresponse %}
That's it. HttpResponse has a main default argument which is the string to return (literally, the html of the web page); that's what you're doing initially. render_to_response and render are shortcuts to this which do this:
render_to_response called ----> open template asked for --> substitute arguments
|
\ /
django instructs web server <--- return this from view <-- create HttpResponse
to send to client object
suppose that you have a webpage that uses the post and get method, and you wrote the following view to generate it:
def homepage(request):
if 'login' in request.POST:
# ......... code goes here, and you return an appropriate response
if 'register' in request.POST:
# ......... code goes here, and you return an appropriate response
# When no Post request, just render the page
return render_to_response('homepage.html')
Question:
Is it considered good programming practice to split the above view into three views: one for login, one for register and one that would render the page? Or is it OK to keep it as it is.
EDIT
in the case listed above, I am not checking if the server received a "GET". But the idea is still the same :)
I think a better idea would be to have each of the two forms submit to a different URL. Then you can define views for, e.g., /login, /register, and / (the default homepage handler). Your views for /login and /register can use if request.method == 'POST', and then redirect to the homepage if they are called with a GET request.
I redirect the user to the home page after logout. In between I would like to delete all/or specific client cookies (I have previously set).
def logoutuser(request):
logout(request)
return redirect('app.home.views.home')
To call response.delete_cookie('user_location'), there is no response object. How do I do this?
Like jobscry said, logout() cleans session data, but it looks like you have set your own cookies too.
You could wrap auth logout view, which will return a HttpResponse:
def logout_user(request):
response = logout(request, next_page=reverse('app.home.views.home'))
response.delete_cookie('user_location')
return response
Or if you're just using the logout method as opposed to the view, you can use the return value for the redirect() method you have (which I assume returns a HttpResponse too).
def logout_user(request):
logout(request)
response = redirect('app.home.views.home')
response.delete_cookie('user_location')
return response
according to http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.logout
Changed in Django 1.0: Calling logout() now cleans session data.
Hope this helps:
delete cookie when caling "/clear-cookies"
location.href = '/clear-cookies';
Define a method in views.py:
def clear_cookies(request):
response = HttpResponseRedirect('/')
response.delete_cookie('_gat', domain='example.com')
response.delete_cookie('_ga', domain='example.com')
response.delete_cookie('_gid', domain='example.com')
return response
Add the path and method to your urls.py:
url(r'^clear-cookies', clear_cookies),
This is slightly tangential, but maybe helpful to others in a similar situation.
If you are setting cookies that need to be deleted when the user logs out, maybe you shouldn't be using cookies in the first place. For that use case, it's much better to use session data instead. Like:
request.session['myKey'] = myValue
retrievedValue = request.session.get('myKey')
From the docs: "The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies".
Using session data is more secure and more performant than setting cookies, because the data stays on the server side.
The only use case where I would recommend setting your own cookies is if you need to store information that persists beyond a session (say you want to store preferences across sessions for a visitor who does not sign in).