I am exporting HTML to PDF via Weasyprint in my Django app. I have noticed that if I send the template html to front end and return that html to backend to export it to pdf, it prints perfectly. But if I directly send template html to Weasyprint, it messes up everything! No css, no javascript.
This is how I'm using the template to generate html:
template = loader.get_template('Reporting/reportTemplate.html')
context = {
"reportObj" : result[0]
}
htmlContent = (template.render(context, request))
response['message'] = htmlContent
return JsonResponse(response)
In my JS controller I assign the htmlContent to my div:
$('#htmlContent').html(response.message);
Then I return the generated html back to my Django function to print pdf
HTML(string=htmlContent).write_pdf(target=response, stylesheets=[CSS(string=getCSS())])
This way it maintains the design and everything.
But when I send htmlContent directly to Weayprint without sending it to front end, the design and coloring is gone!
In my template, I even have included CSS and Javascript files like this:
{% load static %}
{% block content %}
<link href="{% static "css/ion.rangeSlider.css" %}" rel="stylesheet">
<link href="{% static "css/ion.rangeSlider.skinHTML5.css" %}" rel="stylesheet">
<script type='text/javascript' src='{% static "scripts/ion.rangeSlider.js" %}'></script>
<script type='text/javascript'>
$(document).ready(function(){
var creditScore = $("#creditScore").html();
$("#rangeCS").ionRangeSlider({
type: "double",
min: 0,
max: 1000,
step: 100,
from: 0,
to: creditScore,
from_fixed: true,
to_fixed: true,
grid: true,
grid_snap: true
});
});
</script>
{% endblock %}
How can I execute Javascript and CSS in Django template and export to PDF without having to send it to front end?
Are you meaning you've JS in the template that you render as source for Weasyprint ? Because JS used that way runs only on a client side (like browsers) and Weasyprint won't run it, it cannot. You must provided the final document (HTML) to Weasyprint.
If you've CSS issues in your PDF, so maybe you're using unsupported CSS features for Weasyprint.
Like mille_a said, you can't execute javascript code into a pdf.
So to resolve your problem you need to do it into your view :
# do some python stuff to get somes datas
datas = ...
# assign it into your html
htmlContent = my_html_template.render(datas)
# call the pdf generation
HTML(string=htmlContent).write_pdf(target=response)
You can see this example for more details : http://www.supinfo.com/articles/single/379-generate-pdf-files-out-of-html-templates-with-django
Hope it helps.
Related
As we know in Django framework we can generate the HTML page based on some predefined template files.
Inside those templates we can use and some specific django keywords/operators/functions.
Like:
{% block stylesheets %}
<link href="{% static 'js/jquery/jquery-ui.css' %}" rel="stylesheet">
<link href="{% static 'vendor/chosen/chosen.css' %}" rel="stylesheet">
{% endblock stylesheets %}
But most important things which I want to touch in this question are related to tag 'translate'
"{% trans 'List of all available masters' %}"
So I can be sure that the final content of my page will use some predefined language.
And the places where I am using such tags are different: "simple" html content with / and etc tags AND inline javascripts blocks. Like:
<script type="text/javascript">
$('#datepicker_value').on('change', function(){
....
var dialog = BootstrapModalWrapperFactory.createModal({
title: '{% trans 'Extended information about the event' %}',
message: '<pre>'+JSON.stringify(info.event.extendedProps.description, null, 4)+'</pre>',
buttons: [
{
label: '{% trans 'Close' %}',
cssClass: "btn btn-secondary",
action: function (button, buttonData, originalEvent) {
return this.hide();
}
}
]
});
....
</script>
So my main question here is such:
HOW correctly I can move ALL <script>...</script> blocks from html template into the external JS file?
To keep all the functionality of the django framework working! And my 1 variant was - I should use the same technique which I use for generating HTMLs with Django framework abilities. But maybe in a little shorten variant: Right inside the views.py file - CAN I somehow correctly generate on the fly full content of GLOBAL.js file which will contains ALL ... blocks from html template - where they all were previously stored.
And in a such manner - that standard django template engine can convert all {% ..... %} placeholders in a correct real content BEFORE the full content of GLOBAL.js will be generated and given out. And especially the content of translatable placeholders!!! Well, then in the HTML page template I can insert a call to a special command that can display the contents of this script at the moment the page is rendered by the browser on the client side. Something like:
<script type="text/javascript" src="{% url 'GLOBAL.js' %}"></script>
Am i right? If yes - how I can do that step-by-step? Or maybe there is something new and more logical way?
Django version is the latest one!!! 3.*
P.S. Also I've faced with a problem of transferring script block with content like document.addEventListener('DOMContentLoaded', function(){...}); Looks like such event handlers can't be moved out to the separate JS file from HTML page((
There is no reason you couldn't use Django template tags inside Javascript files (or any other filetype for that matter). As an example, here's is a view that returns rendered Javascript:
from django.shortcuts import render
def render_javascript(request):
return render(request, 'myapp/global.js', {})
If you hook this view into your urlpatterns like this:
urlpatterns = [
path("js/global.js", render_javascript, name="globaljs"),
]
You can then use the {% url %} template tag to refer to it from your HTML templates like this:
<script type="text/javascript" src="{% url 'globaljs' %}"></script>
Now when your browser requests js/global.js, the Django view will take the template myapp/global.js, process it with the templating system, and return the rendered template.
I've been teaching myself python and Django and wanted to show a clickable map on a webpage. I don't know javascript but I found jvectormap and it seems to be easy and works well.
However I am confused about template tags. With the code below I can show a world map, and using the onregion function can get the country code and send it to an alert, if I comment out the alert, I can send using the Django URL tag to another web page.
{% load static %}
{% load static %}
{{params}}
<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link href="{% static 'css/jquery-jvectormap-2.0.5.css' %}" rel="stylesheet" type="text/css" media="screen"/>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-jvectormap-2.0.5.min.js' %}"></script>
<script src="{% static 'js/jquery-jvectormap-world-mill-en.js' %}"></script>
</head>
<body>
<div id="world-map" style="width: 600px; height: 400px"></div>
<script>
$(function(){
$('#world-map').vectorMap({ map: 'world_mill_en',
onRegionClick:function(event, code){
var message = (code);
alert( code );
window.location.assign ("{% url 'mainapp:home2' %}")
}
});
});
</script>
</body>
</html>
So a couple of questions:
I thought I should be able to use the template tag in the alert like alert( {{params}} ) but that doesn't seem to work. I thought you might be able to pass the string in params that way. I saw found a different post that suggested wrapping the variable with a tag
'''
{{ params }}
'''
is that a good approach to use tags to get variables into the javascript?
More importantly with the URL template tag, I would like to pass the country code or other information back to the view. In the documentation it looks like you can either use:
{% url 'some-url-name' v1 v2 %}
or
{% url 'some-url-name' arg1=v1 arg2=v2 %}
How would I modify my current view and URL with that approach?
def home(request):
params='this is the home page '
return render(request,'mainapp/home.html',{'params':params})
Do I just start by replacing the return with a redirect?
return redirect('some-view-name', params= code )
and then set up a url path where the code is passed as an id or a slug or something?
Is there different way I should be trying where the onregion or an java onclick script sends something back to django?
Sorry for the multiple questions, but in learning mode...
To answer my own question, I found the following on stack overflow that were helpful in understanding.
Django Template Variables and Javascript
Get javascript variable's value in Django url template tag
and several others.
The short answer is that the template tags once rendered are just text in the html file.
1) You can assign a javascript variable something from a template tag, but that is probably not a great idea in some cases since it could be misused.
2) Since the template tag is just text in the file, there are ways to put a placeholder and then use the .replace function to alter the placeholder and then reverse the URL. The usual way seems to have the placeholder be a number that would never be accessed and and replace the placeholder with a pk or an object id.
3) Some people point out that using GET statement is better and simpler. Somehow AJAX can be used to do this. I'm just learning how to spell Ajax so I will leave it to others to explain.
So I was trying to add an audio recording function to my website developed with django.
I wanted to do something similar as https://github.com/addpipe/simple-web-audio-recorder-demo so I started by trying to run it without modification.
I took the same html as in the git linked above, put the js/ folder in my static/ folder, and simply changed the following lines (index.html, line 32-33)
<script src="js/WebAudioRecorder.min.js"></script>
<script src="js/app.js"></script>
for
{% load static %}
<script src={% static "js/WebAudioRecorder.min.js" %}></script>
<script src={% static "js/app.js" %}></script>
These js files load correctly, but the problem is that when I click record on my website, I get a "GET /myapp/record/js/WebAudioRecorderWav.min.js HTTP/1.1" 404 error in my django server.
WebAudioRecorderWav.min.js is called within WebAudioRecorder.min.js. I tried to use the {% load static %} trick in the js file, but it doesn’t work.
What would be the correct way to work around this?
Thanks in advance.
You should use the workerDir setting to set the correct path to the other imported js files. Probably your recorder is initialised in app.js, where you cannot use template tags like {% static %}. The best way is to create a global variable in your template before loading app.js:
In your HTML template:
<script>var jsFilesPath = "{% static 'js/' %}"</script>
<script src="{% static 'js/app.js' %}"></script>
In your app.js:
if (typeof jsFilesPath !== "undefined") {
audioRecorder = new WebAudioRecorder(sourceNode, {
workerDir: jsFilesPath // must end with slash
});
}
So for those of us who use Python and Django framework to develop a website, there is this awesome tool known as jinja which can be used as a template engine. For example:
Instead of hard-coding an import like this:
<script src="assets/js/onebutton.js"></script>
We can do this:
<script src="{% static 'assets/js/onebutton.js' %}"></script>
In this case, it automatically searches for a folder named static and goes inside to look for the needed code.
But why isn't it possible to use jinja template in Javascript.
For example:
homepage.html
<script src='whatever.js'></script>
<p>Another example</p>
<button id="clickme"> click me </button>
whatever.js
$(function()
{
$('#clickme').click(function(){
$.ajax({
headers : {'X-CSRFToken': getCookie('csrftoken')},
type: "POST",
url: '{% url "func" %}', //<--Problem arise here
datatype:"json",
data: {},
success: function(data){
var new_template = '<h1> %firstmsg% </h1>';
var new_frontend = new_template.replace('%firstmsg%',data.message);
console.log(new_frontend);
document.getElementById('wor').innerHTML+=new_frontend;
}
});
}
}
Django would recognize the url in the AJAX request as /'{% url "func" %}' instead of /func
The only way to solve this is to move the entire code from whatever.js into the homepage.html in a <script></script> block.
Perhaps we need to import something for Jinja templating to work?
<script src="{% static 'assets/js/onebutton.js' %}"></script>
In this case, it automatically searches for a folder named static and goes inside to look for the needed code.
This is inaccurate. All it does is it converts the given path to the static path provided in your settings file like this - /static/asssets/js/onebutton.js. That is it. Django or Jinja2 doesn't go through the folder and look for the file. It doesn't even care if file exists or not.
Later, the browser automatically fetches this file from the server when it receives the html document.
Coming back to your original questions about why you can't use Jinja2 or Django template syntax in your JS files. Well, you can. But you'll have to render your JS files from your views.
Now, I'm sure you're using the render function to return a template from your views. But what does it do?
The render function converts the django specific template tags into proper html content.
So, if you're using django's or jinja's template syntax in your js files, you'll have to render your js files too. But that seems like a bad idea. Instead, you can create some global variables in your html files, and use them in your js files.
<!-- define required variables in template -->
<script>
var URL = '{% url ... %}';
var OTHER_VARIABLE = '{{ other_variable }}';
</script>
<!-- include your js files -->
<script src="/path/to/file.js"></script>
I have a workaround for this kind of necessities. Put your js code inside <script></script> tag and save it as html file inside templates folder.
Now you can include your html file to your page.
{% include 'myapp/js_code_with_jinja.html' %}
All jinja code will work as expected.
Im trying to implement TinyMCE on Django, i have successfully implement it on admin page using settings like this :
admin.py:
class TinyMCEAdmin(admin.ModelAdmin):
class Media:
js = ('/media/js/tiny_mce/tiny_mce.js', '/media/js/tiny_mce/textareas.js',)
settings.py :
TINYMCE_JS_ROOT = '/media/js/tiny_mce/'
TINYMCE_JS_URL = '/media/js/tiny_mce/tiny_mce.js'
then when i try to implement it on my form(non-admin) :
forms.py:
from tinymce.widgets import TinyMCE
class Foo(forms.Form):
title = forms.CharField(max_length = 100)
content = forms.CharField(widget = TinyMCE())
When i see the result, it just showing plain html textarea, then i hit "F12" on Chrome, then it says : 'Uncaught reference error: tinyMCE is not defined'.
How do i fix that error? thx guys
Looking at the documentation, if you are using TinyMCE in your form outside of the admin, you need to tell it to include the JS/CSS required to render TinyMCE manually. So in your base template (or somewhere similar) you need to add:
<head>
...
{{ form.media }}
</head>
or you could simply manually load the js:
<head>
<script src="{{ MEDIA_URL }}js/tiny_mce/tiny_mce.js"></script>
<script src="{{ MEDIA_URL }}js/tiny_mce/textareas.js"></script>
</head>
but the former is probably easier
Looks like the file tiny_mce.js has not been loaded in this case.