Redirect after pdf generation - javascript

I'm generating a pdf after a form submission and I'd like to redirect to a "pdf has been generated" or reload the page with the form. I don't know how to do that, I guess it can be done with javascript/jquery but I didn't found a way to do that.
This is the view that generates the pdf:
def myview(response):
resp = HttpResponse(content_type='application/pdf')
result = generate_pdf('my_template.html', file_object=resp)
return result

You can't redirect from same view tath you are creating the PDF file, one option is send the success page first, and after start the download.
Your success view:
def pdf_success(request):
# View stuff
return render_to_response('pdf.html', {}, context_instance=ctx)
And you need to add this to your pdf.html template:
<meta http-equiv="REFRESH" content="0;url={% url "myview" %}">

First create that success view:
def pdf_success(request):
return render_to_response('pdf_success.html', {},
context_instance=RequestContext(request))
Then do a redirection after success:
def myview(response):
resp = HttpResponse(content_type='application/pdf')
result = generate_pdf('my_template.html', file_object=resp)
if result:
return HttpResponseRedirect('/url/to/success/view')
Just to give you the idea

From this snippet you can create a custom decorator
from functools import wraps
from django.http import HttpResponsePermanentRedirect, HttpResponseRedirect
def redirect(url):
"""
Executes a HTTP 302 redirect after the view finishes processing. If a value is
returned, it is ignored. Allows for the view url to be callable so the
reverse() lookup can be used.
#redirect('http://www.google.com/')
def goto_google(request):
pass
#redirect(lambda: reverse('some_viewname'))
def do_redirect(request):
...
"""
def outer(f):
#wraps(f)
def inner(request, *args, **kwargs):
f(request, *args, **kwargs)
return HttpResponseRedirect(url if not callable(url) else url())
return inner
return outer
def permanent_redirect(url):
"""
Executes a HTTP 301 (permanent) redirect after the view finishes processing. If a
value is returned, it is ignored. Allows for the view url to be callable so the
reverse() lookup can be used.
#permanent_redirect('/another-url/')
def redirect_view(request):
...
#redirect(lambda: reverse('some_viewname'))
def do_redirect(request):
...
"""
def outer(f):
#wraps(f)
def inner(request, *args, **kwargs):
f(request, *args, **kwargs)
return HttpResponsePermanentRedirect(url if not callable(url) else url())
return inner
return outer
You can use any of these from the next way:
#redirect('http://stackoverflow.com')
def myview(response):
resp = HttpResponse(content_type='application/pdf')
result = generate_pdf('my_template.html', file_object=resp)
return result
or:
#permanent_redirect('http://stackoverflow.com')
def myview(response):
resp = HttpResponse(content_type='application/pdf')
result = generate_pdf('my_template.html', file_object=resp)
return result

Related

How to pass python string to javascript as string in Django?

I have a python string which is javascript code and I want to pass this string to javascript as string too.
My idea is to pass python string to javascript string and then use eval() function in javascript to turn that string to actual code and execute it.
def login(request):
success = '''
window.location = '{% url 'home' %}';
# some other codes
'''
return render(request, "app/login.html", {'success': success})
var code = "{{success}}"
console.log(code) // return Uncaught SyntaxError: Invalid or unexpected token
I have also tried pass the string as json like this
def login(request):
success = '''
window.location = '{% url 'home' %}';
# some other codes
'''
success = json.dumps(success)
return render(request, "app/login.html", {'success': success})
var code = JSON.parse("{{success|safe}}");
console.log(code) //return Uncaught SyntaxError: missing ) after argument list
Last thing that I have tried is
def login(request):
success = '''
window.location = '{% url 'home' %}';
# some other codes
'''
return render(request, "app/login.html", {'success': success})
<h3 id="success_id" hidden>{{success}}</h3>
<script>
var code = $("#success_id").text();
console.log(code) //return window.location = "{% url 'home' %}"
// if i do this
var code = "window.location = '{% url 'home' %}'";
console.log(code) // return window.location = /app/home/
// I want it to return the url like /app/home
</script>
How can I do this?
Ok in essence what you want to do is using Django to pass data to js?
That has to to do with Django creating a Json Response which the JavaScript will then make a request , in essence you are working with some API.
your view code where you wrote the render function won't need that anymore...
Something like
JsonResponse({'success':success})
will be needed , after importing the JsonResponse from 'django.http'
Then at the js file, you will have to use Ajax to call that url with it's required method to get the data needed.
in your script tag , you will then need something like this
const xhr= new XMLHttpRequest ()
xhr.open('django_url', 'method')
xhr.onload = function () {
const msg = xhr.response.success
}
xhr.send()
If you are familiar with fetch or axios you can as well use any library of your choice.
the django_url refers to the url that connects that view
the method refers to the http_method, either a 'GET' or 'POST' (most commonly used) .

Flask clear session not happening global

I have been trying to clear the session but it is not getting cleared globally.
Here is my code:
app = Flask(__name__)
app.secret_key = 'xxxxx'
#app.before_request
def make_session_permanent():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=30)
#app.route('/')
def index():
session['game'] = 1
session['level'] = 1
return render_template('index.html')
#app.route('/level', methods=['POST', 'GET'])
def show_session():
x = (session.get('game'), session.get('level'))
return jsonify(x)
#app.route('/clear-session', methods=['POST', 'GET'])
def clear_session():
session.clear()
response = {'level': session.get('level')}
return jsonify(**response)
An this is the JavaScript code snippet that I am using to send AJAX requests:
$.post('http://localhost:8000/level', function(data){console.log(data);}) // returns data
$.post('http://localhost:8000/clear-session', function(data){ console.log(data);}) // returns null as data is cleared
$.post('http://localhost:8000/level', function(data){console.log('session cleared'); console.log(data);}) //returns data again. Session not cleared properly
How can I overcome this and clear the session permanently when I send a request to clear-session?

Django + Angular method PUT and POST not allowed

I refactoring a project with Django/Django-Rest and AngularJS 1.4.9. All my GET requests are working fine, but PUT and POST requests don't. I receive a "405 (METHOD NOT ALLOWED)" error.
All my http requests were Ajax and worked fine, but I'm changing to $http now and having this trouble. What is wrong?
app.js
'use strict';
angular.module('myapp', [], function($interpolateProvider, $httpProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
$httpProvider.defaults.xsrfCookieName = 'jxcsrf';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}).run(function($http) {
$http.defaults.headers.common['Content-Type'] = "application/json";
});
UPDATE showing the django view (but I think is not a django problem, because worked with ajax)
The view
class MusicAction(APIView):
"""
Create a music instance or update the vote field in a music instance.
"""
permission_classes = (IsAllowedOrAdminOrReadOnly,)
def get_playlist(self, station, playlist_id):
try:
return Playlist.objects.get(station=station, pk=playlist_id, playing="1")
except Playlist.DoesNotExist:
raise ValidationError(u'Essa playlist não está em uso.')
def get_music(self, music_id, playlist_id):
try:
obj = Music.objects.get(music_id=music_id, playlist_id=playlist_id)
return obj
except Music.DoesNotExist:
raise ValidationError(u'Essa música já tocou ou não existe.')
def get_object(self, station_id):
try:
obj = Station.objects.get(pk=station_id, is_active=True)
self.check_object_permissions(self.request, obj)
return obj
except Station.DoesNotExist:
return Response(status=404)
def put(self, request, format=None):
station_id = request.data.get("sid")
station = self.get_object(station_id)
playlist_id = request.data.get("pid")
playlist = self.get_playlist(station, playlist_id)
music_id = request.data.get('mid')
music = self.get_music(music_id, playlist_id)
vote = int(request.data.get("vote"))
with transaction.atomic():
total = music.vote
music.vote = total + vote
music.save()
station.last_update = timezone.now()
station.save()
if vote > 0:
Voting.objects.create(voted_by=request.user, music=music)
else:
vote = Voting.objects.get(voted_by=request.user, music=music)
vote.delete()
serializer = MusicSerializer(music)
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is the header.
Try using one of the generic views of django rest framework:
http://www.django-rest-framework.org/api-guide/generic-views/
for example, if you'd like to accept get and put use the RetrieveUpdateAPIView:
from rest_framework import generics
class MusicAction(generics.RetrieveUpdateAPIView):
#code...

How do I send data from JS to Python with Flask?

I'm making a website with Flask and I'd like to be able to execute python code using data from the page. I know that I can simply use forms but it's a single page that is continually updated as it receives user input and it'd be a massive pain in the ass to have it reload the page every time something happens. I know I can do {{ function() }} inside the javascript but how do I do {{ function(args) }} inside the javascript using js variables? So far the only thing I can think of is to update an external database like MongoDB with the js then use Python to read from that, but this process will slow down the website quite a lot.
The jQuery needs to get a list of dictionary objects from the Python function which can then be used in the html. So I need to be able to do something like:
JS:
var dictlist = { getDictList(args) };
dictlist.each(function() {
$("<.Class>").text($(this)['Value']).appendTo("#element");
});
Python:
def getDictList(args):
return dictlistMadeFromArgs
To get data from Javascript to Python with Flask, you either make an AJAX POST request or AJAX GET request with your data.
Flask has six HTTP methods available, of which we only need the GET and POST. Both will take jsdata as a parameter, but get it in different ways. That's how two completely different languages in two different environments like Python and Javascript exchange data.
First, instantiate a GET route in Flask:
#app.route('/getmethod/<jsdata>')
def get_javascript_data(jsdata):
return jsdata
or a POST one:
#app.route('/postmethod', methods = ['POST'])
def get_post_javascript_data():
jsdata = request.form['javascript_data']
return jsdata
The first one is accessed by /getmethod/<javascript_data> with an AJAX GET as follows:
$.get( "/getmethod/<javascript_data>" );
The second one by using an AJAX POST request:
$.post( "/postmethod", {
javascript_data: data
});
Where javascript_data is either a JSON dict or a simple value.
In case you choose JSON, make sure you convert it to a dict in Python:
json.loads(jsdata)[0]
Eg.
GET:
#app.route('/getmethod/<jsdata>')
def get_javascript_data(jsdata):
return json.loads(jsdata)[0]
POST:
#app.route('/postmethod', methods = ['POST'])
def get_post_javascript_data():
jsdata = request.form['javascript_data']
return json.loads(jsdata)[0]
If you need to do it the other way around, pushing Python data down to Javascript, create a simple GET route without parameters that returns a JSON encoded dict:
#app.route('/getpythondata')
def get_python_data():
return json.dumps(pythondata)
Retrieve it from JQuery and decode it:
$.get("/getpythondata", function(data) {
console.log($.parseJSON(data))
})
The [0] in json.loads(jsdata)[0] is there because when you decode a JSON encoded dict in Python, you get a list with the single dict inside, stored at index 0, so your JSON decoded data looks like this:
[{'foo':'bar','baz':'jazz'}] #[0: {'foo':'bar','baz':'jazz'}]
Since what we need is the just the dict inside and not the list, we get the item stored at index 0 which is the dict.
Also, import json.
.html
... id="clickMe" onclick="doFunction();">
.js
function doFunction()
{
const name = document.getElementById("name_").innerHTML
$.ajax({
url: '{{ url_for('view.path') }}',
type: 'POST',
data: {
name: name
},
success: function (response) {
},
error: function (response) {
}
});
};
.py
#app.route("path", methods=['GET', 'POST'])
def view():
name = request.form.get('name')
...
im new in coding, but you can try this:
index.html
<script>
var w = window.innerWidth;
var h = window.innerHeight;
document.getElementById("width").value = w;
document.getElementById("height").value = h;
</script>
<html>
<head>
<!---Your Head--->
</head>
<body>
<form method = "POST" action = "/data">
<input type = "text" id = "InputType" name = "Text">
<input type = "hidden" id = "width" name = "Width">
<input type = "hidden" id = "height" name = "Height">
<input type = "button" onclick = "myFunction()">
</form>
</body>
</html>
.py
from flask import Flask, request
app = Flask(__name__)
html = open("index.html").read()
#app.route("/")
def hello():
return html
#app.route("/data", methods=["POST", "GET"])
def data():
if request.method == "GET":
return "The URL /data is accessed directly. Try going to '/form' to submit form"
if request.method == "POST":
text = request.form["Text"]
w = request.form["Width"]
h = request.form["Height"]
//process your code
return //value of your code

Django: SyntaxError: Unexpected token <

I'm using django with jquery to upload files using ajax. However, after the file has uploaded (and the files do upload correctly; the database is updated and they are on the server) javascript returns with an SyntaxError: Unexpected token < error.
I don't know if this is an error in javascript or an error in django; other questions I saw seemed to recommend making sure the information is indeed in JSON format, but it seems to be properly formatted in my case. I don't really understand why there is an error, since everything seems to work fine. There are no errors in my logs.
If I could only see a more helpful error message, I would have a much easier time fixing the issue.
Here's my views.py:
def response_mimetype(request):
if "application/json" in request.META['HTTP_ACCEPT']:
return "application/json"
else:
return "text/plain"
class JSONResponse(HttpResponse):
"""JSON response class."""
def __init__(self,obj='',json_opts={},mimetype="application/json",*args,**kwargs):
content = simplejson.dumps(obj,**json_opts)
a = super(JSONResponse,self).__init__(content,mimetype,*args,**kwargs)
class UploadedFileCreateView(CreateView):
model = UploadedFile
form_class = UploadedFileForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.project_id = self.kwargs['proj_key']
self.object.save()
f = self.request.FILES.get('file')
data = [{
'name': self.object.name(),
'url': "/uploads/xmlfiles/" + self.object.name().replace(" ", "_"),
'delete_url': reverse('fileupload:upload-delete',
kwargs={'pk':self.object.id,
'proj_key':self.kwargs['proj_key']}),
'delete_type': "DELETE"}]
response = JSONResponse(data, {}, response_mimetype(self.request))
response['Content-Disposition'] = 'inline; filename=files.json'
return super(UploadedFileCreateView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(UploadedFileCreateView, self).get_context_data(**kwargs)
context['files'] = UploadedFile.objects.all()
context['proj'] = int(self.kwargs["proj_key"])
return context
And here's my models.py:
class UploadedFile(models.Model):
"""This represents a file that has been uploaded to the server."""
STATE_UPLOADED = 0
STATE_ANNOTATED = 1
STATE_PROCESSING = 2
STATE_PROCESSED = 4
STATES = (
(STATE_UPLOADED, "Uploaded"),
(STATE_ANNOTATED, "Annotated"),
(STATE_PROCESSING, "Processing"),
(STATE_PROCESSED, "Processed"),
)
status = models.SmallIntegerField(choices=STATES,
default=0, blank=True, null=True)
file = models.FileField(upload_to=settings.XML_ROOT)
project = models.ForeignKey(Project)
def __unicode__(self):
return self.file.name
def name(self):
return os.path.basename(self.file.name)
def save(self, *args, **kwargs):
if not self.status:
self.status = self.STATE_UPLOADED
super(UploadedFile, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
os.remove(self.file.path)
self.file.delete(False)
super(UploadedFile, self).delete(*args, **kwargs)
def get_absolute_url(self):
return u'/upload/projects/%d' % self.id
class UploadedFileForm(ModelForm):
class Meta:
model = UploadedFile
exclude = ('project',)
According to the documentation here, the form_valid() method needs to return the JSON as a HTTPResponse. Calling the form_valid() on the super class will, instead, overwrite the response created on the previous two lines.
Edit - This is working for me:
def response_mimetype(request):
if "application/json" in request.META['HTTP_ACCEPT']:
return "application/json"
else:
return "text/plain"
class UploadedFileCreateView(CreateView):
model = UploadedFile
form_class = UploadedFileForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.project_id = self.kwargs['proj_key']
self.object.save()
f = self.request.FILES.get('file')
data = [{
'name': self.object.name(),
'url': "/uploads/xmlfiles/" + self.object.name().replace(" ", "_"),
'type': "application/xml",
'size': self.object.file.size,
'delete_url': reverse('fileupload:upload-delete',
kwargs={'pk':self.object.id,
'proj_key':self.kwargs['proj_key']}),
'delete_type': "DELETE"}]
return HttpResponse(simplejson.dumps(data), content_type = response_mimetype(self.request))
The code in the link above bundles the ajax response code as a Mixin which would allow other forms in the project to reuse the code.
Viewing the response to the Ajax call in the Firefox plugin Firebug, Net tab or Chrome equivalent will help. These will show both the request and response headers ensuring the correct settings are being sent and returned.

Categories

Resources