Django testing - test the view which handles an ajax call - ajax

In testing Django, the view is returning 200 code but not sending any error message related.
def ajax_view(request):
msg = ''
if request.is_ajax():
username = request.POST['username']
user = User.objects.get(username=username)
msg = 'user exists'
return HttpResponse(msg)
In tests.py
response = self.client.post(reverse('ajax_view'), data={'username': 'hello'})
self.assertEqual(200, response.status_code)
self.assertContains(response, 'exist')
It seems it is not going through the request.is_ajax().. How can I mock the ajax call in Django testing?

The docs on the test client mention this; you need to pass the HTTP_X_REQUESTED_WITH header, which you can do as a keyword argument.
Also, if you pass content_type as 'application/json', Django will automatically serialize to JSON. So:
response = self.client.post(
reverse('ajax_view'),
data={'username': 'hello'},
content_type='application/json',
HTTP_X_REQUESTED_WITH='XMLHttpRequest'
)

Not entirely sure this will resolve the entire issue but your method may be expecting the data in a json format:
json_data = json.dumps({'username': 'hello'})
response = self.client.post(reverse('ajax_view'), data=json_data)

Related

Django response send file as well as some text data

Currently I am send a zip file in response from my Django-Rest controller, the zip file will get downloaded in front-end and this feature is working fine but now I want to send some data as well with the zip file in response, is there any way?
This is my Django-REST controller code
response = HttpResponse(byte_io.getvalue(),content_type='application/x-zip-compressed')
response['Content-Disposition'] = f'attachment;filename{my-sample-zip-file}'
return response
How can I send some data with this zip file on front-end?
You can do it with HTTP Request-Response module of django.
Refer: https://docs.djangoproject.com/en/2.2/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment
If you want to do it in production like code, you might also want to handle case where file is not available, set error and return neat. Also, better put that in a common file and then define download_file like below:
from common_library import FileResponse
from django.http import JsonResponse
def download_file( self ):
if self.error_response:
response = JsonResponse( { "error" : self.error_response } )
else:
response = FileResponse(self.report_file_abs_path, self.report_filename)
response['Content-Type'] = 'application/xlsx'
response['Content-Disposition'] = 'attachment; filename=' + self.report_filename
return response
NOTE: FileResponse is a user defined wrapper function which you can define.

Django ajax warning on same page after DoesNotExist exception on form POST

I have a django form attached to a view. In the form a user types in a query which is passed to a Model.objects.get( query ) like so:
def post(self, request):
try:
Model.objects.get(query)
except Model.DoesNotExist:
# something here
Upon exception i'd like to send an ajax request to my template that stops it from refreshing, and displays a warning to the user that there's nothing in the database matching that get request. What would I put in the view and the template?
The http standard response would be a 404 response. Django has a shortcut function for this: get_object_or_404
def post(self, request):
my_object = get_object_or_404(Model, query)
If the lookup fails, django will raise an 404 error, which will result in a 404 http response back to the client. In your javascript ajax handling code, you should check the http status, and handle any 404 responses appropriately.
For example, if you are using the fetch api, the code might look like this.
fetch('/some/url/?query=foobar').then(response => {
if (response.ok) return response.json()
if (response.status == 404) throw new Error('404')
})

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 :)

how can i make django file upload work with valums/file-uploader

I want to make valums/file-uploader run with django upload, using it with model fields (FileField)
basic django model:
class Image(models.Model):
user = models.ForeignKey(User)
url = models.FileField(upload_to='%Y/%m/%d')
basic view, working with non ajax upload:
def ajax_upload(request):
if request.method == 'POST':
newfile = Image()
newfile.user = request.user
file_content = ContentFile(request.FILES['file'].read())
file_name = request.FILES['file'].name
newfile.url.save(file_name, file_content)
results = {'url': newfile.url, 'id': newfile.id}
return HttpResponse(json.dumps(results))
raise Http404
The problem is that valums uploader does not put the files in "request" files, it put it in the POST, and django get it as a querydic.
Using it with the top code django says:
"Key 'file' not found in "
If i change:
file_content = ContentFile(request.POST)
django says:
expected read buffer, QueryDict found
I can make it work but i still want to hold on django's native file upload, it's much cleaner.
Use request.body (or request.raw_post_data if older than 1.4)

How to use Httpresponse in view in django while using Ajax

I am using this
def ajax_create( request ):
if request.is_ajax():
form = SourceForm()
template = 'ajax_form.html'
data = {
'form': form,
}
return render_to_response( template, data,
context_instance = RequestContext( request ) )
I get this error
ajax_create didn't return an HttpResponse object
Are you sure your request is an ajax call ? It doesn't look like it.
Try:
if request.is_ajax():
...
else:
# If the request is not an ajax call, it will return a 400 Error.
return HttpResponseBadRequest()
Perhaps if request.is_ajax(): is returning False, if that's your entire view function?
Typically, you should follow this pattern when making Django view functions:
def my_view(request):
if request.method == 'POST':
form = MyForm(data=request.POST, files=request.FILES)
if form.is_valid():
# do something with form...
else:
initial = {...}
form = MyForm(initial=initial)
context = {'form':form, ...}
return render_to_response('path/to/template.html', context, context_instance=RequestContext(request))
It's not entering to your "if" scope. it returns None
https://docs.djangoproject.com/en/1.3/ref/request-response/#django.http.HttpRequest.is_ajax
Check your ajax call and make sure it returns something in case the request is not ajax

Resources