django + angularjs resource + ajax POST = 500 (Internal Server Error) - ajax

I can do GET requests, but when I do POST, in Chrome developer tools I see: "Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)"
I thought the problem is in Django's csrf_token, so I found this solution:
.config(function($httpProvider){
$httpProvider.defaults.headers.common['X-CSRFToken'] = CSRF_TOKEN;
});
In my index.html, in <head> I have:
<script>
CSRF_TOKEN = '{{ csrf_token }}';
</script>
But it still raises 500 error. Am I doing something wrong or the problem is not in csrf?
P.S. CSRF_TOKEN is declared before
<script src="{{ STATIC_URL }}lib/angular/angular.js"></script>
and other scripts.

I've figured out the problem.
Django by default appends slash to your URL. If you enter:
http://mydjangosite.com/page Django will redirect you to: http://mydjangosite.com/page/
Angular's $resource removes trailing slash (you can read about it on github: https://github.com/angular/angular.js/issues/992).
Django has APPEND_SLASH setting which uses HTTP 302 redirection to
append slash to urls without slash. This works with GET method but not
with others (POST,PUT,DELETE) because redirection cannot and will not
pass the data to the new URL
So, there are two options:
1) Use $http insread of $resource
or
2) In Django's settings.py add this line:
APPEND_SLASH = False
and in your urls.py remove all trailing slashes

simply escape the backslash like: /custom_api/get_nearest_hotels/:eventId\/
(From: http://pragmaticstartup.wordpress.com/2013/04/27/some-lessons-learnt-from-messing-with-django-and-angularjs/)

As you all know you need to dump dictionary in your HTTPRESPONCE object.
sometimes what happens, in your view; you try to dump something in to your dict that can not be serialized. that is python/django can not serialize that object.
the examples can be (FORM OBJECT), (MODEL OBJECT), etc
so you need to get those away.
context = {}
context['office_form'] = OfficeCompleteForm(request.POST)
this can not be serialized and you will get 500 error.
be free to add following data.
context['success'] = {"msg": "successfully updated. "}
context['error'] = {"msg": "error can not update. "}
and at last do not forget to call you response method like this.
return HttpResponse(json.dumps(context), content_type="application/json")

Related

AJAX Routing to Django URLs (Using Django 2.0 "path" urlpatterns)

This used to work before Django 2.0 changed url patterns from "url" to "path":
index.html
<!DOCTYPE html>
{% load static %}
<head>
<script type="text/javascript" src="{% static 'main/js/jquery-3.3.1.js' %}">
</head>
<body>
<div id='test'>
<p><button class="btn">Click Here!</button></p>
</div>
<script>
$('.btn').click(function(){
console.log('button is clicked!')
$.ajax({
url: 'main/all_json',
sucess: function(serverResponse){
console.log('success.serverResponse', serverResponse)
}
})
});
APP LEVEL urls.py
urlpatterns = [
url(r'^all_json$',views.all_json, name="all_json")
]
Project Level urls.py
app_name= "main"
urlpatterns = [
path('', include ('apps.main.urls', namespace='main')),
path('admin/', admin.site.urls),
]
views.py
def all_json(request):
return HttpResponse ('hello world!')
But now, Django 2.0 uses "path" instead of the url regex pattern. When I use path:
app_name= "name"
urlpatterns = [
path('all_json',views.all_json, name="all_json"),
]
I get the:
GET http://127.0.0.1:8000/main/all_json 404 (Not Found)
I looked in the new documentation and release notes and there are some SO answers that explain how to use it SO post 1 & SO post 2. That has been useful up to this point, where I'm unable to pass the url from the AJAX function to the "path".
I'm new to AJAX and I'm used to using the {% url main:all_json %} in Django for my actions. But with AJAX I believe I can't use this notation. Is that right?
And for some reason, the examples that I have that used url(r'^$') urlpatterns before Django 2.0 worked, but now I get a code 404 when using 'path'. Most of the questions and tutorials available are pre Django 2.0 and use url(r'^$') urlpatterns. Release notes and documentation do not mention anything about differences in working with AJAX.
My questions is the following:
Is there something else that I need to add in my template and/or urls.py to help it find the urls(get rid of the 404)?
First, url is still perfectly valid in Django 2.0. In later versions exactly the same functionality is available as re_path.
However, the problem is not there. It is that you have added a final slash in the new version where you didn't have one before. Remove it:
path('all_json', ...)
or, preferably, add it to the Ajax call:
url: 'main/all_json/',
Note finally that since the Ajax script is directly in the template file, it's absolutely possible to use the {% url %} tag there.
Try to build API's that clear and useful. Using main, all_json names are unclear. Nevertheless, let's try on your examples:
In your urls.py use main/all_json/ and name="all_json". Accoding to documentation:
There’s no need to add a leading slash, because every URL has that. For example, it’s articles, not /articles. link
...each pattern requires that the URL end with a slash. link
In your HTML template (by the way, it's maybe mistake, but you named it html.py. I advise to refactor this to somename.html), in the js block use template tag {% url "all_json"" %} like:
$.ajax({
url: '{% url "all_json" %}',
sucess: function(serverResponse){
console.log('success.serverResponse', serverResponse)
}
})
By using url template tag you can avoid many mistakes when changing urls.

Scrapy ajax POST request not working, though working in Postman

I am implementing a scrapy spider to crawl a website that contains real estate offers. The site contains a telephone number to the real estate agent, which can be retreived be an ajax post request. The request yielded by scrapy returns an error from the server, while the same request sent from Postman returns the desired data.
Here's the site URL: https://www.otodom.pl/oferta/piekne-mieszkanie-na-mokotowie-do-wynajecia-ID3ezHA.html
I recorded the request using Network tab in chrome's dev tools. The url of the ajax request is: enter link description here The data needed to send the request is the CSRFtoken contained in the page's source, which changes periodically. In Postman giving only the CSRFtoken as form-data gives an expected answer.
This is how I construct the request in scrapy:
token_input = response.xpath('//script[contains(./text(), "csrf")]/text()').extract_first()
csrf_token = token_input[23:-4]
offerID_input = response.xpath('//link[#rel="canonical"]/#href').extract_first()
offerID = (offerID_input[:-5])[-7:]
form_data = {'CSRFToken' : csrf_token}
request_to_send = scrapy.Request(url='https://www.otodom.pl/ajax/misc/contact/phone/3ezHA/', headers = {"Content-Type" : "application/x-www-form-urlencoded"}, method="POST", body=urllib.urlencode(form_data), callback = self.get_phone)
yield request_to_send
Unfortunately, I get an error, though everything should be ok. Does anybody have any idea what might be the problem? Is is maybe connected with encoding? The site uses utf-8.
You can find the token in page source:
<script type="text/javascript">
var csrfToken = '0ec80a520930fb2006e4a3e5a4beb9f7e0d6f0de264d15f9c87b572a9b33df0a';
</script>
And you can get it quite easily with this regular expression:
re.findall("csrfToken = '(.+?)'", response.body)
To get the whole thing you can use scrapy's FormRequest which can make a correct post request for you:
def parse(self, response):
token = re.findall("csrfToken = '(.+?)'", response.body)[0]
yield FormRequest('https://www.otodom.pl/ajax/misc/contact/phone/3ezHA/',
formdata={'CSRFToken': token},
callback=self.parse_phone)
def parse_phone(self, response):
print(response.body)
#'{"value":"515 174 616"}'
You can debug your scrapy requests by insersting inspect_response call and looking into request object:
def parse_phone(self, response):
from scrapy.shell import inspect_response
inspect_response(response, self)
# shell opens up here and spider is put on pause
# now check `request.body` and `request.headers`, match those to what you see in your browser

configuring ajaxAppender of log4javascript with Django backend

I am trying to configure ajaxAppender of log4javascript in DJango. I have made a file frontendlog.json where I want to write the logs going from the front end. This is how I write the script in myPage.html.
<script type="text/javascript" src="/static/js/log4javascript.js"></script>
<script language="javascript">
var url = '/frontEndLog/';
var log = log4javascript.getLogger("serverlog");
var ajaxAppender = new log4javascript.AjaxAppender(url);
ajaxAppender.addHeader("Content-Type", "application/json");
var jsonLayout = new log4javascript.JsonLayout();
ajaxAppender.setLayout(jsonLayout);
log.addAppender(ajaxAppender);
window.onerror = function(errorMsg, url, lineNumber){
log.fatal("Uncaught error "+errorMsg+" in "+url+", line "+lineNumber);
};
log.info("Front End Log");
alert('!!')
</script>
In my django urls.py I have this entry url(r'^frontEndLog/$', 'TryOn.views.frontEndLog'),
and in my django view I have this view function
def frontEndLog(request):
LOGGER.info ("frontEndLog")
return render_to_response('frontEndLog.json', mimetype="text/json")
So I expected the frontEndLog to be written in frontEndLog.json in the same location as other HTMLs are found in django. However, it tells me that XMLhttpRequest Request to URL returned status code 500. Can somebody please tell me where I am going wrong here and is this the correct way to use log4javascript in django?
I solved it. I printed the django request object in views.py. There I was able to find the log messages in the request.POST. It appears in the form of a dictionary since it is JSON-ified. You can access the logs with this
clientLogs = request.POST.get('data')
'data' is the key in the key : value pair here. (You can easily understand that when you see the POST object).
Whether you want to print it in the views.py itself or write it to a a txt file is up to you. So all this while the logs were actually getting logged without me being able to identify it! I guess I should have read the documentation better.

JavaScript code in view issue in Laravel

I put JavaScript code in a view file name product/js.blade.php, and include it in another view like
{{ HTML::script('product.js') }}
I did it because I want to do something in JavaScript with Laravel function, for example
var $path = '{{ URL::action("CartController#postAjax") }}';
Actually everything is work, but browser throw a warning message, I want to ask how to fix it if possible.
Resource interpreted as Script but transferred with MIME type text/html
Firstly, putting your Javascript code in a Blade view is risky. Javascript might contain strings by accident that are also Blade syntax and you definitely don't want that to be interpreted.
Secondly, this is also the reason for the browser warning message you get:
Laravel thinks your Javascript is a normal webpage, because you've put it into a Blade view, and therefore it's sent with this header...
Content-Type: text/html
If you name your file product.js and instead of putting it in your view folder you drop it into your javascript asset folder, it will have the correct header:
Content-Type: application/javascript
.. and the warning message will be gone.
EDIT:
If you want to pass values to Javascript from Laravel, use this approach:
Insert this into your view:
<script type="text/javascript">
var myPath = '{{ URL::action("CartController#postAjax") }}';
</script>
And then use the variable in your external script.
Just make sure that CartController#postAjax returns the content type of javascript and you should be good to go. Something like this:
#CartController.php
protected function postAjax() {
....
$contents = a whole bunch of javascript code;
$response = Response::make($contents, '200');
$response->header('Content-Type', 'application/javascript');
....
}
I'm not sure if this is what you're asking for, but here is a way to map ajax requests to laravel controller methods pretty easily, without having to mix up your scripts, which is usually not the best way to do things.
I use these kinds of calls to load views via ajax into a dashboard app.The code looks something like this.
AJAX REQUEST (using jquery, but anything you use to send ajax will work)
$.ajax({
//send post ajax request to laravel
type:'post',
//no need for a full URL. Also note that /ajax/ can be /anything/.
url: '/ajax/get-contact-form',
//let's send some data over too.
data: ajaxdata,
//our laravel view is going to come in as html
dataType:'html'
}).done(function(data){
//clear out any html where the form is going to appear, then append the new view.
$('.dashboard-right').empty().append(data);
});
LARAVEL ROUTES.PHP
Route::post('/ajax/get-contact-form', 'YourController#method_you_want');
CONTROLLER
public function method_you_want(){
if (Request::ajax())
{
$data = Input::get('ajaxdata');
return View::make('forms.contact')->with('data', $data);
}
I hope this helps you... This controller method just calls a view, but you can use the same method to access any controller function you might need.
This method returns no errors, and is generally much less risky than putting JS in your views, which are really meant more for page layouts and not any heavy scripting / calculation.
public function getWebServices() {
$content = View::make("_javascript.webService", $data);
return (new Response($content, 200))->header('Content-Type', "text/javascript");
}
return the above in a method of your controller
and write your javascript code in your webService view inside _javascript folder.
Instead of loading get datas via ajax, I create js blade with that specific data and base64_encode it, then in my js code, I decode and use it.

Django - Start Session by Ajax Request

I need to know how to start a session by Ajax in Django. I'm doing exactly as described bellow, but it is not working! The request is sent correctly, but don't start any session. If a request directly without ajax it works! What is going on?
'# urls
r'^logout/$', 'autenticacao.views.logout_view'
'# view of login
def login_view(request):
username = request.GET.get('username', '')
password = request.GET.get('password', '')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse(user.get_profile().sos_user.name)
return HttpResponse('user invalido')
'# ajax in a html page
$(function(){
$.get('http://localhost:8000/logout/?username=usuario?>&password=senha', function(data){
alert(data);
});
You're not calling the login_view. You're ajax request is going to the /logout/ url which is calling the autenticacao.views.logout_view.
Also, The ?> after username=usuario doesn't look right in the your get url.
My guess is you should be doing something like http://localhost:8000/login/?username=usuario&password=senha. (but I'd need to see your login url mapping to be sure).
Also, you should be POSTing the login information and using HTTPS for security reasons, but that's a different issue.

Resources