How to do AJAX in Django CMS Admin - ajax

I have 2 models in Django CMS - a Map (which has name and an image attributes), and a Location, which one of it's attributes is a Map. I want, when the user changes the Map, to perform an AJAX request to get the map details for that item so that I can add the Map image to the page to do some further jQuery processing with it. But I'm new to Django and I can't seem to figure it out. Anything I find seems unrelated - in that it talks about using AJAX on front end forms.
I have my jQuery file ready to go but I don't know what to put for the URL of the AJAX call and how/where to set up the endpoint in Django.

Your question seem related to custom Django admin url.
First, update your MapAdmin to provide an endpoint to search location
from django.contrib import admin
from django.http import JsonResponse
class MapAdmin(admin.ModelAdmin):
def get_urls(self):
admin_view = self.admin_site.admin_view
info = self.model._meta.app_label, self.model._meta.model_name
urls = [
url(r'^search_location$', admin_view(self.search_location), name=("%s_%s_search_location" % (info))),
]
return urls + super(VideoAdmin, self).get_urls()
def search_location(self, request, *args, **kwargs):
map = request.GET.get('map')
# Do something with map param to get location.
# Set safe=False if location_data is an array.
return JsonResponse(["""..location_data"""], safe=False)
Next, somewhere in your template file, define the URL point to search location endpoint. And use that URL to fetch location data
once map is changed.
var searchLocationUrl = "{% url 'admin:appName_mapModel_search_location' %}";

Related

drf custom response to override Response()

I'm using DRF and to return response, I used Response() which located at from rest_framework.response import Response
To make custom response, first, I copied all of the source to custom file.
And in my views, I changed Response() to my own file.
But when I running django server and access via web, it through errors.
AssertionError: .accepted_renderer not set on Response
I just copied original Repsonse() and re-use it.
Why it occur errors?
Purpose of custom response is I want to add more argument that something likes cursor for pagination.
As you know that in original Response, takes 6 arguments.
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
And return it in def rendered_content(self), line of ret = renderer.render(self.data, accepted_media_type, context)
So my scenario is, add cursor to __init__ and pass through it to renderer.render().
Any problem with my way?
Thanks.

How to restrict the ajax call from out side of the browser in django

i am working in a project, there is no user authentication and authorization. Bascially i am calling ajax in client side and it executes a view in django and return a json out. How can i validate this request is only coming from browser and how to restrict the if this not coming from the browser or any manual script?
You can use request.is_ajax() method
HttpRequest.is_ajax()
Returns True if the request was made via an XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the string 'XMLHttpRequest'. Most modern JavaScript libraries send this header. If you write your own XMLHttpRequest call (on the browser side), you’ll have to set this header manually if you want is_ajax() to work.
If a response varies on whether or not it’s requested via AJAX and you are using some form of caching like Django’s cache middleware, you should decorate the view with vary_on_headers('HTTP_X_REQUESTED_WITH') so that the responses are properly cached.
docs
Im updating my answer to fit what we commented above
In your views
from django.core import signing
from django.views.generic import View, TemplateView
from django.http import HttpResponseBadRequest
class BrowserView(TemplateView):
template_name = 'yourtemplate.html'
def get_context_data(self, **kwargs):
ctx = super(BrowserView, self).get_context_data(**kwargs)
ctx['token'] = signing.dumps(self.request.session_id)
return ctx
class AjaxView(View):
def get(self, *args, **kwargs):
if self.request.is_ajax():
try:
sign = signing.loads(self.request.GET.get('token'), max_age=(20))
if sign == self.request.session_id:
## return ajax
return HttpResponseBadRequest('You are not authorized to see this page')
except signing.BadSignature:
return HttpResponseBadRequest('You are not authorized to see this page')
else:
return HttpResponseBadRequest('You are not authorized to see this page')
In your template
In this case I used a meta tag, but you get the idea
<meta name="validation" content="{{token}}" />
In your javascript
var t = document.querySelector("meta[name='validation']").getAttribute('content');
$.ajax({
url:'yoururl',
data: yourData + '&token=' + t,
type: 'get',
success: function(response){
// do whatever
},
error: function(e){
console.log(e);
}
});
I don't believe it's possible to 100% prevent this, but there are some things you can do:
a set-cookie header w/some unique ID on the page, but not on API responses.
if the cookie isn't received by your API, return a 401.
tracking API calls per unique ID could be a good indicator of "proper" usage.
associate IDs w/IPs.
the tracking metrics can be combined w/a threshold that blocks requests if exceeded.
you can check the referrer header (easy to spoof).
finally, lookup the is_ajax method of Django's, but this just checks for an XMLHttpRequest header (again, easy to spoof).

Scrapy check if image response is 404

I want to process image URLs, I enabled and configured as Scrapy Docs; but what happens if the image URL returns 404 or is redirected. I want to log that, save the failed URLs and the HTTP error/redirect code. Where can I put the code to do that?
It is completely wrong to handle that in the pipleline, because the response would go throw all the middlewares back to your spider then to your pipleline, while your purpose is just logging the failure.
You should build your own middleware to handle any HTTP response code.
By default, scrapy allows responses with statues codes between 200 and 300. You can edit that by listing the statue codes that you would like to receive like this:
class Yourspider(spider):
handle_httpstatus_list = [404, 302] #add any other code you need
Then you should build your middleware and add it to your configuration like this:
DOWNLOADER_MIDDLEWARES = {
'myProject.myMiddlewares.CustomSpiderMiddleware': SELECT_NUMBER_SUITS_FOR_YOU,
}
in your CustomSpiderMiddleware check the status like this:
process_spider_input(response, spider):
if response.status == 404
#do what ever you want
You have to create your custom pipeline, inherit it from the Imagepipeline, then override the item_completed method, as mentioned in the documentation
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images")
item['image_paths'] = image_paths
return item
and lastly in the settings.py add your custom pipeline
ITEM_PIPELINES = {
'myproject.mypipeline': 100,
}

Django POST data dictionary is empty when posting from test client

I am trying to test and AJAX view in my Django Project. When submit the post from JQuery the data is correctly accessible in the Django View but when I try to make queries for the Django test client it is emplty.
Here is the code I use:
The view
def add_item(request):
if request.is_ajax() and request.method == 'POST':
post_data = request.POST
print post_data ## <----- THIS IS EMPTY
name = post_data.get('name')
# Render the succes response
json_data = json.dumps({"success":1})
return HttpResponse(json_data, content_type="application/json")
else:
raise Http404
And the test
class TestAddItem(TestCase):
def test_some_test(self):
data = {
'description':"description",
}
response = self.client.post('theurl', data, content_type='application/json')
Any Idea what I might be doing wrong?
I tried also without content type and also using plain url like thurl/?name=name without succes.
Any help will be appreciated.
Olivier
After trying different combinations of parameter formating, content types, etc..
I found one solution that works :
response = self.client.post(reverse('theurl'), data,
**{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'})
And I get the following dictionary on the POST parameters of the request:
<QueryDict: {u'name': [u'name']}>
Edit I love testing :)

Redirect user in Grails if browsing an action

I have a Grails controller action that is used for Ajax purposes, though you can still navigate and view the page in the browser.
class QuoteController {
def quoteService
/**
* This page uses the ajaxRandom function defined below to display random quotes.
*/
def random = {
def randomQuote = quoteService.getRandomQuote()
[quote:randomQuote]
}
/**
* I do not want this to be a valid page, but maintain its use as a simple Ajax method.
*/
def ajaxRandom = {
def randomQuote = quoteService.getRandomQuote()
response.outputStream << "<q>${randomQuote.content}</q><p>${randomQuote.author}</p>"
}
}
Is there a way to redirect if someone visits the URL via browser while maintaining the method's Ajax functionality from within a page?
def ajaxRandom = {
if(!request.xhr) { // this calls the dynamic method request.isXhr()
redirect action: 'random'
} else {
def randomQuote = quoteService.getRandomQuote()
response.outputStream << "<q>${randomQuote.content}</q><p>${randomQuote.author}</p>"
}
}
This works because most of the Ajax JS Libraries add the X-Requested-With header to the request. Grails add this isXhr() method dynamically to the HttpServletRequest class.
// test whether the current request is an XHR request
HttpServletRequest.metaClass.isXhr = {->
'XMLHttpRequest' == delegate.getHeader('X-Requested-With')
}
A simple way is to append a param to the url when calling it via ajax e.g. ?ajax=true
Then check for it and redirect if it's not there (such as when a use hits it with their browser).
If that is too easy to work around, inspect the request to see what is different between a browser request and an ajax request.
cheers
Lee
If you AJAX requests are always POSTS then you could check the method and assume a POST is an AJAX call because it's pretty hard for the average user to create a POST accidentally, where as they can always GET any URL (if they know of it)
Hope this helps.

Resources