Showing JSON data from DB to django template using Bootstrap tabs - python

Sorry I'm a programming newb....
But I am trying to use Bootstrap's tabs navigation to view JSON data from a DB. I'm transforming the JSON data to a 2d array and storing my data as the following dictionary:
tables = {u'table1': [[u'CS6140', u'Machine Learning', u'Sara
Arunagiri'], [u'CS5100', u'Foundations of
Artificial Intelligence ', u'Chris Amato'],
[u'CS6220', u'Data Mining', u'Pablo Esteves']],
u'table2': [[u'Paris, France', u'06/01/2019 - 06/15/2019',
u'James Fraser'], [u'Edinborough, Scotland',
u'10/14/2019 - 10/20/2019', u'Claire Beauchamp'],
[u'Rome, Italy', u'12/14/2019-12/24/2019',
u'Timothy Dalton']],
u'table3': [[32423, u'iced coffee', 3.67], [34241, u'bagel',
2.99], [3109247, u'sanwich', 5.99]]}
Thus each table dict entry corresponds to one table.So I'm trying to loop through the dictionary and 2d array to create different tables.
I'm currently trying to loop through the dictionary as follows but I am getting the 2d arrays replicated 3 times for each of the tables when instead I want each table in my dictionary to only be shown once for each tab.
{% for table in tables %}
<div class="tab-content">
<div id="{{ table }}" class="tab-pane active">
{% for table in tables.values %}
<table class="table">
<tbody>
{% for row in table %}
<tr>
{% for item in row %}
<td>{{ item }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
</div>
</div>
{% endfor %}
I'm hoping for some insight on to how else store or pass the data to my context to get what I want i.e.
<div class="tab-content">
<div id="table1" class="tab-pane active">
<table class="table">...</table>
</div>
<div id="table2" class="tab-pane active">
<table class="table">...</table>
</div>
<div id="table3" class="tab-pane active">
<table class="table">...</table>
</div>
</div>
...
vs. what I'm currently getting:
<div class="tab-content">
<div id="table1" class="tab-pane active">
<table class="table">...</table>
<table class="table">...</table>
<table class="table">...</table>
</div>
<div id="table2" class="tab-pane active">
<table class="table">...</table>
<table class="table">...</table>
<table class="table">...</table>
</div>
<div id="table3" class="tab-pane active">
<table class="table">...</table>
<table class="table">...</table>
<table class="table">...</table>
</div>
</div>
...

This should work:
<div class="tab-content">
{% for table_name, table in tables.items %}
<div id="{{ table_name }}" class="tab-pane {% if forloop.first %} active {% endif %}">
<table class="table">
<tbody>
{% for row in table %}
<tr>
{% for item in row %}
<td>{{ item }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
</div>
It's better to use your keys and values of your dictionary using .items at the beginning of your loop, rather than getting your values further down your loop logic. It avoids confusion in your loop logic.
EDIT:
The active class should only be for the first tab. Thus, you need to use the forloop.first template tag to add the class thr first time you run through the loop.

Related

Displaying details of api results using id

I am working with the omdb api (https://www.omdbapi.com/) and I was able to get the search results to display, but now I am trying to get the movie details when I click on each search result.
Right now I am getting a response of 'Not Found' which I think has something to do with retrieving the movie id, but I haven't been able to figure it out. I appreciate any tips/advice you may have.
app.py:
#app.route('/movies/search_results', methods=['GET'])
def show_search_results():
"""Logic for sending an API request and displaying the JSON response as an HTML. Expects a GET request."""
movies = []
s = request.args.get("s")
results = requests.get(f"{API_BASE_URL}search/movies/",params={"s": s}).json()
results = results['Search']
for movie in results:
movies.append(movie)
return render_template('movies/search_results.html', movies=movies, s=s, id=movie['imdbID'])
#app.route('/movies/<int:id>', methods=['GET'])
def show_movie_details(id):
"""For displaying information about the individual movie. Not a list. GET request only."""
movie = requests.get(f'{API_BASE_URL}movie/{id}')
print(movie)
return render_template('movies/detail.html', movie=movie, id=id)
search_results.html:
{% extends 'base.html' %}
{% block title %} {% endblock %}
{% block nav1 %} active {% endblock %}
{% block content %}
<div class="container-fluid" id="movie-list">
<div class="row row-cols-2 justify-content-center mt-2" style="--bs-gutter-x:0; ">
<p> Search Results for "{{s}}"</p>
<table class="movie-table">
<thead>
<tr>
<th>IMDB ID</th>
<th>Movie Title</th>
<th>Year Released</th>
</tr>
</thead>
<tbody>
{% for movie in movies %}
<tr>
<td>
<a href="/movies/{{id}}" id="id">
{{ id }}
</a>
</td>
<td>
{{ movie['Title'] }}
</td>
<td>
{{ movie['Year'] }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block footer %} {% endblock %}
movies/details.html:
{% extends 'movies/search_results.html' %}
{% block content %}
<div class="card text-center" style="width: 18rem;">
<div class="card-body">
<!-- <div class="d-flex justify-content-between align-items-center mb-3 "> -->
<h5 class="card-title text-center"> Title: {{ movie['Title'] }} </h5>
<form method="POST" action="/movie/add_like/{{ movie['imdbID'] }}" id="messages-form">
<button class="btn btn-sm float-left">
<i class="fa fa-thumbs-up"></i>
</button>
</form>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
</div>
</div>
{% endblock %}
I tried not using int:id in the route and just redirecting to movies/detail.html, but I was still not receiving any results and just viewing the template without any API information on it.

Flask-SQLAlchemy pagination with keywords returns an empty list

I have an issue with flask paginate. Upon advice here at Stackoverflow I solved an initial paginate typeerror by changed my code so the paginate takes keywords. This gave me a new issue, since my code now returns an empty list of tickers.
The issue seems to be related to the implementation of paginate with keywords and the filter_by function, since my code returns a list of stocks from all exchanges when i remove the filter for CPH. So below code is working, but gives my tickers for all exchanges and obviously not only the ones with exchange='CPH':
#app.route("/stocks/cphstocks")
#login_required
def cphstocks():
page = request.args.get('page', 1, type=int)
**tickers = Ticker.query.paginate(page=page, per_page=app.config['TICKERS_PER_PAGE'], error_out=False)**
next_url = url_for('cphstocks', page=tickers.next_num) \
if tickers.has_next else None
prev_url = url_for('cphstocks', page=tickers.prev_num) \
if tickers.has_prev else None
return render_template('cphstocks.html', title='Copenhagen Stocks', tickers=tickers.items, next_url=next_url,
prev_url=prev_url)
My code with keywords in paginate and the filtering is shown below. Does anyone know what I'm missing here, since it's not returning the tickers for exchange='CPH'? Advice is much appreciated!
#app.route("/stocks/cphstocks")
#login_required
def cphstocks():
page = request.args.get('page', 1, type=int)
tickers = Ticker.query.filter_by(index="CPH").paginate(
page=page, per_page=app.config['TICKERS_PER_PAGE'], error_out=False)
next_url = url_for('cphstocks', page=tickers.next_num) \
if tickers.has_next else None
prev_url = url_for('cphstocks', page=tickers.prev_num) \
if tickers.has_prev else None
return render_template('cphstocks.html', title='Copenhagen Stocks', tickers=tickers.items, next_url=next_url,
prev_url=prev_url)
And my jinja template:
{% extends "layout.html" %}
{% block content %}
<article class="media content-section">
<div class="media-body">
<h3>Copenhagen listed stocks</h3>
</br>
<p></p>
</div>
</article>
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm w-auto small">
<caption>Stocks listed at Copenhagen stock exchange</caption>
<thead>
<tr>
<th class="text-left"scope="col">Ticker</th>
<th class="text-right"scope="col">Company</th>
</tr>
</thead>
<tbody>
{% for items in tickers %}
<tr>
<td scope="row"> <a href="{{ url_for('stockpage', id=items.id) }}">{{ items.yahoo_ticker }}</td>
<td class="text-right">{{ items.company_name }}</td>
</tr>
{% endfor %}
</tbody>
</table> {% if prev_url %}
Previous page
{% endif %}
{% if next_url %}
Next page
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="content-section">
<h3>New menu </h3>
<p class='text-muted'>You can put any information here you'd like.
<ul class="list-group">
<li class="list-group-item list-group-item-light">Visit Yahoo Finance</li>
<li class="list-group-item list-group-item-light">Update1</li>
<li class="list-group-item list-group-item-light">Calendars</a></li>
<li class="list-group-item list-group-item-light">etc</a></li>
</ul>
</div>
</div>
{% endblock content %}
Solved it by using filter instead of filter_by, so code that works is as below:
tickers = Ticker.query.filter(Ticker.exchange.contains('CPH')).paginate(page=page, per_page=app.config['TICKERS_PER_PAGE'], error_out=False)

loop.last in jinja2 not working properly in django

guys I am trying to avoid printing two divs in my table in the last iteration of the loop of my Django template. I have used loop.last variable to check if the loop is in its last iteration, but it is not working for some reason. Here program session is simply a range(number_of_iterations_required).
Here is my code:
{% for n in program_sessions %}
<!-- 1st session start -->
<tr class="mb-2">
<td class="border border-0">
<div class="row">
<div class="col-6 mx-0 px-0">
<span class="float-end">Row: </span>
</div>
<div class="col-6 mx-0 px-0">
<span class="text-white">{{program.workout_time}}m</span>
</div>
{% if not loop.last %}
<div class="col-6 mx-0 px-0">
<span class="float-end">Rest: </span>
</div>
<div class="col-6 mx-0 px-0">
<span class="text-white">{{program.rest_time}}min</span>
</div>
{% else %}
<div class="col-6 mx-0 px-0">
<span class="float-end">Last Iteration boii! </span>
</div>
{% endif %}
</div>
</td>
</tr>
<!-- 1st session ends -->
{% endfor %}
</tbody>
</table>
</div>
Thank you in advance for your help.
Have a good day.
Looks like the syntax is not right. Try to change it to forloop instead of loop. You can have a look at the django docs for more info
{% if not forloop.last %}

JInja2 Template Syntax Error Encountered Unknown tag 'endif'

I am building a basic api based website as I was going to display some info om page and was checking for a condition i encountered --
jinja2.exceptions.TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.
Below is the palatte I copied form Bootstrap and was modifying and then the error happened -- And Yeah This is my first time posting question here as you can tell!
{% include "header.html" %}
{% block contnet %}
<div class="container-fluid">
<div class="row row-dark">
<div class="col px-2 py-5">
<h6 class="px-2 py-3">Click to Know Upcoming Events</h6>
<a href="{{ url_for('upcoming_events') }}"
><button type="button" class="btn btn-dark mx-2 my-3">Events</button></a
>
</div>
</div>
<div class="row">
<div class="col col-lg-4 col-md-6">
<table class="table table-borderless py-5 table-light">
<thead>
<tr class="table-light">
<th scope="col">Batting</th>
<th scope="col">Bowling</th>
<th scope="col">Wickets</th>
<th scope="col">Over</th>
</tr>
</thead>
<tbody>
{% if error %} # <========
<p>{{ error }}</p>
{% endif %} <======= Here is the error traceback
<tr>
<th scope="row"></th>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>#fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>#twitter</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
You close the "if" twice ({% endif %}) but only open one...
Try this:
Click to Know Upcoming Events Events Batting Bowling Wickets Over
{% if error: %}
{{ error }}
{% endif %}
Mark Otto #mdo 2 Jacob Thornton #fat 3 Larry the Bird #twitter
{% endblock %}
You can move the {% endif %} where you want

Django template for loop is empty in another block

I have a function in my view.py:
#login_required(login_url='login')
def gpd(request,pk):
# get gpd by id
current_gpd = get_gpd(pk)
# get current campaign year #TODO check types
current_campaign = get_campaign(current_gpd.gpd_year)
# get all corporate goals for current campaign
corp_goals = CorporateGoal.objects.filter(gpd_year=current_campaign.year)
compl_weight = []
for goal in corp_goals:
compl_weight.append(goal.corp_factor_weight*current_gpd.bonus.corporate_component//100)
corporate_goals = zip(corp_goals, compl_weight)
if is_manager(request)!=None:
team = get_team(request)
context = {'gpd':current_gpd,
'corporate_goals':corporate_goals,
}
return render(request, 'app/gpd_forms/form_gpd.html', context)
else:
context = {'gpd':current_gpd,
'corporate_goals':corporate_goals,
}
return render(request, 'app/gpd_forms/form_gpd.html', context)
As you can see, in context I have corporate_goal.
My form_gpd.html:
{% extends 'app/navbar/main.html' %}
{% load static %}
{% block content %}
{% include 'app/slidebar/gpd_form_slidebar.html' %}
<div class="container" style="background-color:white">
<div class="row">
<div id="section2" class="container-fluid">
{% include 'app/gpd_blocks/corporate_goal.html' %}
</div>
</div>
<hr />
</div>
<div class="container" style="background-color:white">
<div class="row">
<div id="section5" class="container-fluid">
{% include 'app/gpd_blocks/summary.html' %}
</div>
</div>
<hr />
</div>
</div>
{% endblock %}
for example in corporate block I am executing next:
{% load static %}
{% block content %}
<div class="row" id="super">
<p>&nbsp</p>
</div>
<div class="row" id="super">
<div class="col-11" style="color: ivory; font-weight: bold; font-size: 1.3em;">
CORPORATE GOALS BLOCK
</div>
</div>
<div class="row" id="super">
<p>&nbsp</p>
</div>
{% for goal, compl_weight in corporate_goals %}
<hr style="height:2px;border:none;color:rgb(87, 124, 161);background-color:rgb(87, 124, 161);" />
<!-- Corporate goal section-->
<div class="row">
<div class="col">
Corp. Goal: {{ goal.corp_goal_title }}
</div>
</div>
<div class="row">
<div class="col-8">
<div>
{% if goal.corp_factor_rate %}
<p style="color:mediumspringgreen">rated</p>
{% else %}
<p style="color:indianred">unrated</p>
{% endif %}
</div>
</div>
<div class="col-3">
<div style="margin-inline-start:auto">
{{compl_weight}} % of total score
</div>
</div>
</div>
<!-- Tabs for details-->
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#det1{{ goal.id }}">Goal Details</a></li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#det2{{ goal.id }}">Other Details</a></li>
</ul>
<!-- Tabs content for details-->
<div class="tab-content" >
<!--First tab-->
<div id="det1{{ goal.id }}" class="tab-pane fade show active">
<div class="row">
<!--Column 1-->
<div class="col">
<table class="table-bordless" style="margin-top:20px;">
<tbody>
<tr>
<th>Start Date</th>
<td width="50"></td>
<td>{{ goal.start_date }}</td>
</tr>
<tr>
<th>Weight</th>
<td width="20"></td>
<td>{{ goal.corp_factor_weight }} %</td>
</tr>
<tr>
<th><p>&nbsp</p></th>
</tr>
<tr>
<th style="color:dimgray">Goal description</th>
<td width="18"></td>
<td></td>
</tr>
</tbody>
</table>
<div class="row">
<textarea class="form-control" readonly title="Description" style="background-color:aliceblue !important;">{{goal.corp_goal_description}}</textarea>
</div>
</div>
<!--Column 2-->
<div class="col">
<table class="table-bordless" style="margin-top:20px;">
<tbody>
<tr>
<th>Due Date</th>
<td width="50"></td>
<td>{{ goal.end_date }}</td>
</tr>
<tr>
<th>Factor Rate</th>
<td width="50"></td>
<td>
{% if goal.corp_factor_rate %}
{{ goal.corp_factor_rate }}
{% else %}
<div style="color:mediumspringgreen; font-weight: bold;">ongoing...</div>
{% endif %}
</td>
</tr>
<tr>
<th><p>&nbsp</p></th>
</tr>
<tr>
<th style="color:dimgray">Goal comment</th>
<td width="18"></td>
<td></td>
</tr>
</tbody>
</table>
<div class="row">
<textarea class="form-control" readonly title="Comment" style="background-color:aliceblue !important;">{{goal.corp_goal_comment}}</textarea>
</div>
</div>
</div>
</div>
<!--Second tab-->
<div id="det2{{ goal.id }}" class="tab-pane fade" style="margin-top:20px;">
<p>Factor for Goal Achievement:</p>
<table class="table">
<tbody>
<tr>
<th>Factor</th>
<td>0</td>
<th>Description</th>
<td>{{ goal.corp_factor_0 }}</td>
</tr>
<tr>
<th>Factor</th>
<td>1</td>
<th>Description</th>
<td>{{ goal.corp_factor_1 }}</td>
</tr>
<tr>
<th>Factor</th>
<td>2</td>
<th>Description</th>
<td>{{ goal.corp_factor_2 }}</td>
</tr>
<tr>
<th>Factor</th>
<td>3</td>
<th>Description</th>
<td>{{ goal.corp_factor_3 }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<br />
<br />
<br />
{% endfor %}
{% endblock %}
And it works perfectly. But when in last block summary I want to use corporate_goals one more time - I have nothing on my page, looks like corporate_goals is not exist.
my summary.html
{% load static %}
{% block content %}
<div class="row">
<p>123</p>
</div>
<div class="row">
{% for goal, compl_weight in corporate_goals %}
{{ goal.corp_goal_title }}
{% endfor %}
</div>
<div class="row">
<p>123</p>
</div>
{% endblock %}
Even If I copy all my code from corporate_goal.html into summary - I will have nothing. Why ?
I think that the problem is that your html structure has no sense. You have three {% block content %}. Please, delete the content blocks of your include files (corporate_goal.html and summary.html) and check if this is the problem. I think that one of your content block is overriding the other one.
Just to clarify, when you use the "include tag" is like you were pasting the code from other file. So imagine the result. You have a block content that contains two other block contents inside it.
My problem was in zip objects. When we are iterating through a zip object it is exhausted and you cannot iterate through it again. So, solution is corporate_goals = list(zip(corp_goals, compl_weight)). Anyway, thank you, #LaCharcaSoftware, for the advice, I've changed my structure to avoid duplication with block content.

Categories

Resources