Django Extend Content perserving old Get Results - python

I am proficient with python but quite new to django and html.
What is the best method to include additional data while keeping data that was previously queried for displayed on the same page?
Some of the sql data involves large datasets being manipulated in python, so I would rather not recalculate everything for a new view, when I am only intending to reuse the old view with 1 extra method/query. Thanks for the help.
This is a very stripped down template for exampleurl/experiment1/ to illustrate my problem.
{% extends "base.html" %}
{% load poll_extras %}
{% block content %}
{% block info %} #(loaded on default) {% endblock %}
{% block chart %} #(loaded with default values) {% endblock %}
{% block addinfo1 %}
<select class="selectpicker" data-style="btn-info" onchange="if (this.value) window.location.href = this.value" method="get">
<option value="?addinfo1=X">additional data X</option>
<option value="?addinfo1=Y">addtional data Y</option>
#(etc.)
</select>
{{if addinfo1}} #(nothing loaded by default)
#(display table)
{% endblock %}
{% block addinfo 2 %}
<form class="addinfo search" action="/search/" role="search" method="get">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name=q>
</div>
</form>
{{if search_results }} #(nothing loaded by default)
{% endblock %}
{% endblock %}
I.e. Someone loads experiment 1, selects addinfo=X and then searches in the additional addinfo2 field - what is the best way to preserve the already loaded experiment1 and addinfo1 data while displaying new responses to his query (it really needs to work both ways though, that someone could get addinfo2 data and then change the addinfo1 from =x to =y without removing the addinfo2 data either) ?

EDIT:
Based on the question you want to do this:
Show the page with one or more forms. When a form is submitted keep the old GET data displayed as it was.
The answer is AJAX
You create the form with an id, then you create a view with a unique url. send the GET data using AJAX to the url and when the result back you process it and show it in the same page.
<input type="text" class="form-control" placeholder="Search" id="queryHolder">
<input type="button" id="mySearchButton">
<div id="searchResults">
</div>
<!-- make sure you included jQuery library -->
<script>
$("#mySearchButton").click(function(){
var query = $("#queryHolder").val();
$.get("/search/", {q: query}, function(data){
// the data came from the Django view.
$("#searchResults").html(data)
})
})
</script>
When the search button clicked jQuery will send an Ajax request which will never reload the page. the GET request will be sent to /search/ with 1 parameter called q which is equal to the input value.
When the data returned from the search view as an HttpResponse() you can use it if it's JSON or display it if it's pure HTML
Fact:
You don't need a form if you don't need an action to be triggered.

Related

How do I capture data with a html button without using a form?

I'm using Flask and am sending reports and displaying them in html. I want each report entry to have a corresponding delete button that when clicked, will trigger a python function to delete that report from a database I have. I am not struggling with the logic of how to delete the report from within that python function, I am trying to figure out how to send the information to python. I know this can be done with a form where the user enters the name of what they want deleted but I would prefer that the button just correspond to the report and not have to have the user type out which report they want to delete.
{% if report_data %} {% for report in report_data %}
<div class="report">
<dl>
<h1><b>{{ report['name'] }}</b></h1>
<dt><b>Date of Report:</b> {{ report['time'] }}</dt>
<dt><b>Overall Score:</b> {{ report['overall'] }}</dt>
<dt><b>Cleanliness Score:</b> {{ report['cleanliness'] }}</dt>
<dt><b>Availability Score:</b> {{ report['avail'] }}</dt>
<dt><b>Location Score:</b> {{ report['location'] }}</dt>
</dl>
<button method="post"> <a href='/delete_report'>Delete Report</a></button>
</div>
{% endfor %} {% elif error_message %}
My main.py has the following function:
#app.route('/delete_report', methods = ["GET", "POST"])
def delete_report():
#remove report from database
which is being reached but how do I send say report['name'] to it? Is that something that can be done without having to create a form?

what does {% random code here %} means in HTML file

I was given an assignment and I came across this line of code in one of HTML file of problem set. What does {% random code here %} means in HTML, is it a comment or what? I tried google but could not find it.
one TODO looks like this:
{% extends "layout.html" %}
{% block body %}
<div class="col">
<form action="/compare" enctype="multipart/form-data" method="post">
<!-- TODO -->
</form>
</div>
{% endblock %}
So please sort it out what it is for me ?
It is probably some kind of templating, for example:
http://jinja.pocoo.org/
This means that the {% random code here %} is meant to be filled out by a webserver before returning proper HTML.
{} is an object. Most likely this is part of a template that will process some code from a backend language or javascript. Take a look at mustache which utilizes this syntax https://mustache.github.io/.

How can I generate buttons or fields (forms) in Flask according to a list of strings?

Well, suppose we have a list of strings (objects with a toString() method respectively) and a jinja2 template that shall have selection forms (buttons or something alike) that agree in number and label to the list. This list may alter during the session. So far, I tried to work with submit buttons and radio buttons. Problems are: submit buttons vary in size because of different string length and I dislike that radio buttons force the user to first make a choice and then submit it.
The jinja2 markup looks like this:
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
<input type="radio" name="question" value={{q}}> {{q}} <br>
{% endfor %}
{% endif %}
<input type="submit" /><br /><br />
</form>
The flask function looks like this:
#app.route("/turn", methods=['POST'])
def add_dialogue_turn():
label = request.form["question"]
print(label)
return render_template("sometemplate.html", questions=aListOfQuestions, answers = aListOfAnswers)
Can I make the radio buttons submit the value directly after ticking off the circle? Or can I define some field that returns the string when clicking on it?
Thank you for your help in advance!
This is a Front end problem. You would need either JavaScript to submit your form when a button/radio is ticked. And it also depends on how you submit your form but if you want just the data to be passed into the server without page reloading, I'd suggest Ajax. And if you just want to pass the input value into the server, you do not have to use post.
A simple example would be,
-HTML
<input type="radio" name="question" value={{q}} id="{{something_unique_for_each_iterable}}" onclick="submitFunction(this)">
-JavaScript
function submitFunction(event){
id_of_radio_ticked = '#' + event.id;
$.ajax({
url: "{{url_for('to_your_flask_view_function')}}",
type: 'GET',
data: {'radio_value':$(id_of_radio_ticked).val()},
success: function(resp){
alert('do something with returned data')
}
});
}
I found another solution within the jinja template:
<nav>
<ul>
<div class="sideMenuL">
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
{% autoescape false %}
<input type="submit" name="question" value="{{q}}"><br>
{% endautoescape %}
{% endfor %}
{% endif %}
</form>
</div>
</ul>
</nav>

Why is my flask form validation returning Not a valid choice?

I have been trying to figure out why my Flask form will not properly validate my select field choices even though the choices are coming from the select field options.
My assumption is that the select option when passed back from the server is unicode and is being compared to the choice which is a string, however, I thought coerce=str would fix that. I printed out the form data and request data which is the output below. Why isn't it working?
My code is attached below, removed csrf token key from the output dict. It seems like a very simple thing, but I can't figure it out.
forms.py
class PlatformForm(FlaskForm):
platform_options = [('test', 'Test'), ('test2','Test2')]
platforms = wtforms.SelectField('Platforms', choices=platform_options, coerce=str, validators=[DataRequired()])
views.py
#app.route('/', methods=['POST', 'GET'])
def index():
form = forms.PlatformForm()
if form.is_submitted():
print form.data
print request.form
if form.errors:
print form.errors
return render_template('home.html', form=form)
index.html
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.csrf_token }}
<select class="custom-select" name="platform">
{% for value, text in form.platforms.choices %}<br>
<option value="{{ value }}">{{ text }}</option>
{% endfor %}
</select>
<button id="submit_inputs" type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
output
{'platforms': 'None'}
ImmutableMultiDict([('platform', u'test')])
{'platforms': [u'Not a valid choice']}
EDIT:
I figured out the problem. It's the way I'm creating the Select drop down through HTML and Jinja. Iterating through the choices and creating option tags doesn't seem to instantiate anything in the form data itself when passed back into Python. Changing that whole for loop to just
{{form.platforms}}
created a select drop down field that actually works.
You have a name mismatch. In the form, you named your select field platforms (plural). In the HTML, you use platform (singular).
I recommend that instead of manually rendering the fields in your template, you let WTForms generate the HTML for you. For the form label, you can use {{ form.platforms.label }}, and for the actual field {{ form.platforms() }}. You can pass any attributes you want to field to have as keyword arguments.
I think something might be going wrong because of the way you are rendering the form in your html file. If my hunch is right, try this:
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.hidden_tag() }}
Select: {{ form.plaforms}}
{{ form.submit(class="btn btn-default") }}
</form>
{% endblock %}
and then try if form.validate_on_submit() in your views.py file
taken from this stack overflow answer by pjcunningham:
"validate_on_submit() is a shortcut for is_submitted() and validate().
From the source code, line 89, is_submitted() returns True if the form
submitted is an active request and the method is POST, PUT, PATCH, or
DELETE.
Generally speaking, it is used when a route can accept both GET and
POST methods and you want to validate only on a POST request."

Flask & Bootstrap Multiple collapsibles, but they each only open the first

I have an HTML page displaying a database populated by emails. I have them displayed in a collapsible, and for each post the timestamp of it is what toggles it and the innards are the email itself. The HTML page is structured like this:
{% extends "base.html" %}
{% block content %}
{% for email in emails %}
<div><button class="btn" data-toggle="collapse" data-target="#demo">{{ email.timestamp }}</button>
<div id="demo" class="collapse">
{{ email.body }}
</div>
{% endfor %}
{% endblock %}
relevant portion of views.py
#app.route('/cruz')
def cruz():
u = Politician.query.get(1)
emails = u.emails.all()
return render_template('cruz.html',title='Ted Cruz',emails=emails)
which produces a webpage that looks like this: http://imgur.com/noqC40E
The problem is that no matter which of those timestamps I click, only the first collapsible opens and closes. I've tried a number of things to fix it, mostly messing around with the HTML page and the for blocks and where I place the {{ email.body }}, but nothing I do seems to work. Can anyone see where this is going wrong?
You are generating the same id attribute for your div each time:
<div id="demo" class="collapse">
You almost certainly need to generate unique ids. You could generate unique ids by adding the loop index perhaps:
<div id="demo-{{loop.index}}" class="collapse">

Categories