I'm working on a Django app which parses xlsx input, processes series of REST API queries and returns the result of the queries as a table in one of my django templates. The HTML code containing the results table is generated with Pandas.to_html() functionality. The HTML code is stored in a variable ("table") and passed to the html template, where it is displayed as {{ table | safe }}. This mechanism works just fine. However, I'm now struggling to add a button which would generate a pdf file to be downloaded by the user.
NOTE: I'm aware it would probably make more sense to use JS to render the PDF on the client side, but at the moment the point is to avoid doing so.
Upon some research, I decided to go with the django-easy-pdf library. I based my solution on the example included in the documentation, but so far to no avail.
In urls.py:
urlpatterns = [
[...]
path('result.pdf', views.PDFView.as_view(), name='PDFview'),
]
In views.py:
class PDFView(PDFTemplateView):
template_name = 'whitelist/listresult.html'
table = None
def get_context_data(self, **kwargs):
return super(PDFView, self).get_context_data(pagesize='A4', title='Hi there!', table=self.table, date=date.today)
Please note that the template "listresult.html" is the one expecting the {{ table }} variable.
Last but not least, in the very listresult.html (where I want to place the button to render the PDF file), I added a simple button object:
<a class="btn btn-secondary btn-lg" href="{% url 'PDFview' table %}">Download PDF</a>
My expectation was that since I'm sending the "table" variable along with the request for PDF url, the view would process it nicely and prompt the user with a download pop-up for the PDF file looking exactly (or almost exactly) as the page which presented the result in the first place. However, I'm cought in a vicious circle where if I add "table" to the url reference on the site I get an error during template rendering for the very website displaying results (NoReverseMatch for ..., Reverse for 'PDFview' with arguments '['table' contents go here] not found). On the other hand, if I remove the "table" argument from the url reference, the results website renders OK with the "Download PDF" button, but upon clicking it I'm left with a Runtime Error (since context is missing).
I'm 97% confident my mistake is ostentatiously stupid, but after x hours of struggle I'm ready for StackOverflow's judgement.
Related
I don't really get how to make a button click trigger my view function... I already googled, but nothing really helps me understand...
In my html, I have:
<a class="btn btn-large btn-info" href="{% url "device-detail" device.pk %}" name = 'rotateleft'>Rotate Left</a>
And in my views.py:
class DeviceDetail(DetailView):
....
def rotate_left(request, self):
if request.GET.get('rotateleft') == 'rotateleft':
print 'TEST!!!!'
self.image.open()
self.image.rotate(-90)
self.image.save()
If I click the button, the page seems to be reloaded as planned, but as 'TEST' is not printed (and the image is not rotated, but it might be that the code that is supposed to rotate it doesn't work yet, I wanted to call the function to see if it works), I'm guessing that this function is never called.
I am relatively new to Django and very new to the web interface side of Django, so help would be really appreciated!
You seem to be confusing a few things here. Clicking the link will "refresh" the DeviceDetail page as you noticed. Adding a name attribute on your HTML link won't however affect the request made to the server.
Based on what you are trying to accomplish it seems you should use a simple view function and perhaps read in a a GET parameter for deciding which way to rotate your image. Note that the parameters you pass to your view needs to be within the link URL, like:
href="{% url "device-detail" device.pk %}?rotate=right"
I'm pretty much trying to create a web app that takes 2 svn urls and does something with them.
The code for my form is simple, I'm also using WTForms
class SVN_Path(Form):
svn_url=StringField('SVN_Path',[validators.URL()])
I'm trying to create 2 forms with 2 submit buttons that submit the 2 urls individually so my test3.html looks like this:
<form action="" method="post" name="SVNPath1">
{{form1.hidden_tag()}}
<p>
SVN Directory:
{{form1.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form1.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
<form action="" method="post" name="SVNPath2">
{{form2.hidden_tag()}}
<p>
SVN Directory:
{{form2.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form2.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
MY FIRST QUESTION is how do I know which submit button was clicked so I can run the proper function on the corresponding svn url. I have tried doing something like
if request.form1['submit'] == 'Update':
if request.form2['submit'] == 'Update':
but that does not work at all. I'm new to web dev in general and flask so a detailed explanation would be helpful.
SECONDLY, since submits weren't working properly I also tried an alternative to keep my work moving so in my .py file I have
#app.route('/test3', methods=['GET','POST'])
def test3():
basepath=createDir()
form1=SVN_Path()
form2=SVN_Path()
if request.method=="POST":
if form1.validate_on_submit():
svn_url = form1.svn_url.data
prev_pdf=PDF_List(svn_url,basepath,'prev') #some function
if form2.validate_on_submit():
svn_url2 = form2.svn_url.data
new_pdf=PDF_List(svn_url,basepath,'new') #some function
return render_template('test3.html', form1=form1, form2=form2)
CreateDir is a function that creates a directory in the local /tmp using timestamps of the local time.
Whenever I go the webpage it creates a directory, lets call it dir1, since its calling CreateDir. Thats what I want, but when I click submit on the form it creates another directory dir2 in the tmp folder which is NOT what I want since I want everything to being the same dir1 directory.
In addition when I put a url in one of the forms and click submit, it automatically puts it the same value in the 2nd form as well.
Sorry if this is really long and possibly confusing, but any help is appreciated.
:) Let's see if we can clarify this a little.
To your first question:
As #dim suggested in his comment, You have a few options:
You can submit your form to separate unique urls. That way you know which form was submitted
You can create two similar but different Form classes (the fields will need different names like prev_svn_url and cur_svn_url). This way in your view function, you instantiate two different forms and you'll know which form was submitted based on form.validate_on_submit()
The third option would be to add a name attribute to your submit button and then change the value attributes to something like 'Update Previous' and 'Update Current'. This way in your view function you can check the value of request.data[<submit button name>] to determine if 'Update Previous' was pressed or 'Update Current'.
To your second question:
Multiple directories are being created because you're calling createDir() each time the page is loaded to show the forms and when the forms get posted. In order to create just once, you'll need some kind of logic to determine that the directory was not previously created before calling createDir()
In addition: Since both forms are from the same SVN_Path class, they read post data exactly the same way, that's why whatever you type in form 1 appears in form 2.
Now for my 2 cents:
I assume you're trying to write some kind of application that takes two SVN urls as input, creates a folder and does something with those URLs in that folder. If this is the case, the way you are currently going about it is inefficient and won't work well. You can achieve this with just one form class having 2 svn_url fields (with different names of course) and then handling all of that in one post.
EDIT: The job of the submit button is to tell the browser that you're ready to send the data on the form to the server. In this case you should only need one submit button (SubmitFiled => when rendered). Clicking that one submit button will send data from both input fields to your view function.
Your form should look something like:
class SVN_Path(Form):
prev_svn_url=StringField('Previous SVN_Path',[validators.URL()])
new_svn_url=StringField('New SVN_Path',[validators.URL()])
and your view function:
def test():
form = SVN_Path()
if request.method == "POST":
if form.validate_on_submit():
basepath = createDir() # Only create dir when everything validates
prev_svn_url = form.prev_svn_url.data
new_svn_url = form.new_svn_url.data
prev_pdf = PDF_List(prev_svn_url, basepath, 'prev')
new_pdf = PDF_List(new_svn_url, basepath, 'new')
...
return render_template('test3.html', form1=form1, form2=form2)
I'm in the design stages of a single page web app, and would like to make it so that a user can click on a formatted URL and the data requests will load in the page.
For example, a url of http://www.mysite.com/?category=some_cat will trigger the Category view with the relevant data.
My intention is to parse the URL, gather the data, then pass it to the index.html template for rendering on page load. Once the page has been loaded, a Javascript trigger setting will trigger the appropriate button to load the client view.
However, I'm having an issue setting up the URL parser, as the following settings are not matching the example url above.
from app.views import app_views, photo_views, user_views, admin_views
urlpatterns = patterns("",
url(r'^/(?P<category>\d+)/$', app_views.index)
)
You're confusing between sending information through your urls with GET and formatting you urls with arguments for the view functions. Say I am visiting a site called http://www.mysite.com/ and the page has a form that looks like this:
<form>
<input type='text' name='category' id='category'></input>
<button type='submit'>Send!</button>
</form>
upon clicking, the url will automatically change to http://www.mysite.com/?category=<value of input>. The ? marks that everything afterwards should be treated as GET data, with the syntax of <id>=<value>. You can then access them like so:
def response(request):
category = request.GET['category']
formatting urls is different, because it means looking for patterns that are part of the url. i.e. a pattern that looks like r'^/(?P<category>\d+)/$' will look for this: http://www.mysite.com/<category>/ and it will send it to the request in your views as an additional argument like so:
def response(request, category):
...
The regex is used to define how you recognize that part of the url. For example, the \d+ you're using means that category needs to be a number. You can search how to define different types of patterns according to your needs
Note that with GET you are sending the data to the same view function that rendered the page you are currently visiting, while using a different url means you tell it where to go through your urls.py (usually a different function). Does that make things a bit clearer?
It has been 2day i am trying to figure out how to do that. I am a novice so please give as detailed explanation as possible.
I am doing this in my views.py
dict1 = simplejson.dumps(dict1)
return render_to_response('main_page.html', {
'js_testsuite':testsuite_dict,
'js_testset':js_testset,
'dict1':dict1})
In main_page.html
{% if js_testsuite %}
<select id="testsuites" name="testsuite" onchange="setOptions(document.selection.testsuite.selectedIndex);">
{% for key, value in js_testsuite.items %}
<option value={{ value }} name="testsuite">{{ key }}</option>
{% endfor %}
</select>
{% endif %}
In setoptions.js, which contains the function setOptions(value), to which i am passing selected index of the select box, and using this value i have to set the second select box and the data for this select box has to come from the views.py given above.
Also, I tried doing
var value_from_django = {{ dict1 }};
what are the other things im missing. Could you please provide a detailed explanation on this. I had been trying this for 2 days.
Is there a way in which I can pass the value from django views to the javascript directly bypassing the django template?
Can I pass the information from django views to the html template and then to the javascript?
The javascript I am referring to is a simple javascript not jquery.
Thanks for your support,
Vinay
You cannot pass values to javascript bypassing the template, unless you use an ajax call to start a separate request or unless you do something very unusual like embedding the data in a response header (don't actually do this, it is not what response headers are for!). The response, which includes the header and the body (the body being the part generated by the template) is the sum total of the information your application provides to your client, so unless you generate an additional request and fetch an additional response with ajax, you have no other options.
If you don't want to do that, then your options for passing information to the javascript via the template are basically the following:
Using an inline tag, create properly formatted javascript dynamically via the templating system. The example line you have, var value_from_django = {{ dict1 }}; is essentially what I'm talking about here, except that I'm not sure you can pass a dict through from django to javascript like that, because django's text output of a dict in the template is unlikely to be exactly the correct formatting for a javascript variable declaration. So, instead you can...
Translate your data into JSON and put that into your template, and then process that with the javascript. (This is usually done with an ajax call, but there's nothing stopping you from injecting the JSON data into the initial template directly.)
Or populate your HTML with the data you want and then use javascript to locate the HTML tag containing the data and parse the data out.
If you are trying to pass simple variables like integers, it might be easiest to do it with the first or third options. If you are trying to pass a more complex data structure like a dictionary, you will probably be better off using JSON (that's what it's for!)
I would like to give you more detailed and concrete instructions, but for that you will need to post more detail about what exactly is going wrong with your current approach and what your desired functionality is.
By the way: if it is at all feasible to include jquery on this page and use that instead of trying to use basic javascript, you should do so. It will make your life much, much easier.
I am creating a django-based site that will serve flash apps that occasionally access data via pyamf. I need to be able to easily test the flash in the context of the django framework, i.e. with all the login cookies and everything available, so that when I make a pyamf call, it has all the user context there. And I need to be able to test and release both the swf's and the wrapper html's in a sane way. However:
The html templates in flex are already templates, so if I put template code in there for django, it gets scraped out before the flashapp.html is created.
The html's and swf's automatically get released to the same directory, but I want them to go to different directories because the swf's shouldn't be served by django and the html's should be in an area in control of django.
This leads me to believe, at first glance, that I need:
A way of having the html and swf files be released to different locations. (I don't know how to do this.)
A way of releasing the html's as stubs (no html/body tag) so that I can include them from another location in django. (I guess just strip what I don't want from the index.template.html?)
Then I can point flex to go to the django site that in turn includes the generated flashapp.html that in turn references the swf, and it should all work. (By feeding that alternate html to the run/debug settings, I assume.)
So my question comes down to:
Is the above the best way of doing this, or is this even the right direction?
If so, how do I release the html and swf to different directories? (For debug and release mode, if there are two different methods.)
If not, what is proper?
And if there are any other general bits of advice for me on this topic, please feel free to share. :-)
Finally figured this out myself. A combination of this and django get-parameters works. The general take-away:
You can put {% tags %} and {{ variables }} in index.template.html without worry, as there is no way to customize the currently-existing macros there like ${title}
If you make a foo.template.html and foo-debug.template.html in the html-template directory of your project, then the former will override index.template.html for release builds, and the latter for debug builds (note that the result will be foo-debug.html instead of foo.html though.)
You can pass the name of the SWF in a parameter to django, and have it fill in the directory for you
foo-debug.template.html
<object ...
<param name="movie" value="{{ bin_debug_url }}/${swf}.swf" ...
djangoflash.html
{% block content %}
{% include flash_template %}
{% endblock %}
views.py
def djangoflashview( request, **kwargs ):
if not kwargs.has_key('extra_context'):
kwargs['extra_context'] = {}
if request.GET.has_key('name'):
debug = "-debug" if request.GET.has_key('debug') else ""
bin_debug_dir = '/dir-to-bin-debug/'
bin_debug_url = 'url-to-bin-debug'
name = bin_debug_dir + request.GET['name'] + debug + '.html'
kwargs['extra_context']['flash_template'] = name
kwargs['extra_context']['bin_debug_url' ] = bin_debug_url
return direct_to_template( request, **kwargs )
urls.py
url( r'^djangoflash/', 'views.djangoflashview',
{ 'template': 'djangoflash.html' }
foo.mxml's run-debug target:
/url-to-django/djangoflash/?name=foo
When you debug foo.mxml, flex:
Adds &debug=true to the url
Brings up a browser to /url-to-djangoflash/djangoflash/?name=foo&debug=true
Which picks djangoflash/ in urls.py
Which passes the request to djangoflashview and {'name':'foo','debug':'true'} to request.GET in views.py
Which figures out the name and location of the foo-debug.html location, passing it to the flash_template context variable
And the url of the swf to the bin_debug_url context variable
And loads up the direct template djangoflash.html
Which, in djangoflash.html, includes the foo-debug.html wrapper for flash using the flash_template context variable
Which, in turn fills in the bin_debug_url context variable to point the foo.swf reference correctly to the thing you just compiled
Whew. :-P