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

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">

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?

Flask's Jinja nesting some rendered elements in 'strong' elements

I'm experiencing a weird behavior with Jinja. I made a dynamic flask route and so I made a jinja modular template, it's just a for loop to create an element for each article present in some data (in a dict) I give to Jinja, the template looks like this :
{% for theme in article_data %}
{% for article in theme["article"] %}
{% if article["main"] == 1 %}
<div style="background-image: url('{{article['content']['image1']}}');" class="theme-item-bg frow space-between">
{% endif %}
{% endfor %}
<div class="wrapper-row space-between pinkfilter">
<div class="uB theme-item-text">{{theme["name"]}}</div>
<div class="pageChanger waves-effect waves-light btn uL primaryB" page="/nos-articles/{{theme['name']}}" title="{{theme['name']}}">Voir plus d'articles</div>
</div>
</div>
{% endfor %}
It does work correctly for most of my pages but for one, it have a really weird behavior, Jinja render one of the article correctly and nest the others in a strong element.
The data used to render the page have the same structure and is correctly parsed.
Is there a way to prevent Jinja from nesting stuff in a strongelement?
There must be either some html inside theme["name"] (fix it by escaping it with theme["name"]|escape), or a <strong> tag not closed in one your templates.
Jinja doesn’t insert random html tags, but the browsers do when trying to parse and fix a broken html code

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/.

Python Flask SQLAlchemy-Paginator Access next page in html view

I have currently a problem to include the pagination function into my project. I know there is LIMIT/OFFSETor yield_per(), but I was not able to implement them.
I am using SQLAlchemy not Flask-SQLAlchemy so paginate wont work.
My Database is not that big. I am trying to show rooms which have been added by a user. So all in all a user will have 20~ rooms, big users maybe 100. I want to show on the profile page the 6 last inserted rooms and if there are more, there should be pagination, like page 2 shows the next 6 etc.
I am using SQLAlchemy-Paginator.
I already implemented it and tested it, it works fine. It also limits already the results depending on which page I am. But how do I access the next page while on HTML?
Here is the python code:
#app.route("/user/logged_in")
#login_required
#check_confirmed
def logged_in():
if current_user.email_verified:
users_room = db_session.query(Zimmer).filter_by(users_id=current_user.id).order_by(desc("id"))
paginator = Paginator(users_room, 2)
for page in paginator:
print "page number of current page in iterator", page.number
print "this is a list that contains the records of current page", page.object_list
return render_template('logged_in.html', paginator=paginator)
return redirect(url_for('unconfirmed'))
Here is the view. The solution must be somewhere here. I can access pages by page.previous_page_number or page.next_page_number. But there is no example in the docu how to do it in view.
<div class="user-rooms">
<h2> Ihre Zimmer </h2>
{% for page in paginator %}
{% if page.number == 1 % }
{% for zimmer in page.object_list %}
{% if zimmer.users_id == current_user.id %}
<div class="col-sm-4 col-xs-6 col-xxs-12 img-holder">
<img src="../static/userimg/{{ zimmer.hauptbild }}"/>
<div class="buttons-del-work"> Bearbeiten Löschen </div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
If I manually change the page numbers here it show me the correct items, so I feel like I am close:
{% if page.number == 1 % }
Okay here is a solution (which does not use any further methods from the SQLAlchemy-Paginator package). I coded everything myself, but I would still like to know how it is done with page.next_page_number etc.
Explained:
First of all I added an argument (pagenumber) to my logged_in function. Everytime url_for("logged_in", pagenumber=1) is called the pagenumber has to be set to the defaultvalue 1.
I created an empty list, where I add all the page.number items, so I know how many pages my resultset will have:
pages_list = []
for page in paginator:
pages_list.append(page.number)
I use the pages_list also in the view to generate the buttons which can be clicked to see the next page, I also give the pagenumber to the html view:
return render_template('logged_in.html', paginator=paginator, pagenumber=pagenumber, pages_list=pages_list)
Here is the HTML view where I show the buttons:
<div class="col-xs-12">
{% for number in pages_list %}
{{ number }}
{% endfor %}
</div>
Now if a user clicks one of the Buttons the logged_in will be called with a new pagenumber argument (the actual pagesite you clicked)
In the logged_in I added also typecasted pagenumber to int before giving it to html view:
pagenumber = int(pagenumber)
Solution Code
Python:
def logged_in(pagenumber):
if current_user.email_verified:
users_room = db_session.query(Zimmer).filter_by(users_id=current_user.id).order_by(desc("id"))
paginator = Paginator(users_room, 2)
pages_list = []
for page in paginator:
pages_list.append(page.number)
pagenumber = int(pagenumber)
return render_template('logged_in.html', paginator=paginator, pagenumber=pagenumber, pages_list=pages_list)
return redirect(url_for('unconfirmed'))
HTML:
<div class="user-rooms">
<h2> Ihre Zimmer </h2>
{% for page in paginator %}
{% if page.number == pagenumber %}
{% for zimmer in page.object_list %}
<div class="col-sm-4 col-xs-6 col-xxs-12 img-holder">
<img src="../static/userimg/{{ zimmer.hauptbild }}"/>
<div class="buttons-del-work"> Bearbeiten Löschen </div>
</div>
{% endfor %}
{% endif %}
{% endfor %}
</div>
<div class="col-xs-12">
{% for number in pages_list %}
{{ number }}
{% endfor %}
</div>

Django Extend Content perserving old Get Results

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.

Categories