Populating multiple plotly offline plots<div> of HTML page using flask - html

I am trying to embed multiple plotly offline plots into an HTML page at different locations on the page. I am using flask at the back-end. Currently I am unable to change the properties of the returned by plotly offline plot to change the location, width, height on the HTML page. I am new to the front-end development concept so pardon my ignorance.
I am using the below test code to create div plot.
from plotly.offline import plot
import plotly.graph_objs as go
def plot_test():
months = ['Jan', 'Feb', 'Mar']
user = [10,50,30]
t20h = [17, 46, 39]
trace1 = go.Scatter(x= months, y=user, mode='lines+markers', name="OHR")
trace2 = go.Scatter(x= months, y=t20h, mode='lines+markers', name="T20H")
data = [trace1, trace2]
layout = go.Layout(title='Test', xaxis=dict(title='Months'), yaxis=dict(title='Test'))
fig = go.Figure(data=data, layout=layout)
div_output = plot(fig, output_type='div', include_plotlyjs=False)
return div
And below code to render the results in my HTML
from plot_test import plot_test
#app.route('/')
def home():
plotly_graph = plot_test()
return render_template("index.html", plotly_graph=Markup(plotly_graph))
And below is my HTML. Currently the plot gets crated but at the top of everything else. All my other buttons.
<!DOCTYPE html>
<html>
<head>
<title>Intro</title>
<link href="static/index_style.css" rel="stylesheet">
</head>
<body>
<div id="home">
<form action="/" method="GET">
<input type="submit" class="btn btn-default>" value="HOME" id="home-btn">
</form>
</div>
<div id="logout">
<form action="/logout" method="GET">
<input type="submit" class="btn btn-default>" value="LOGOUT" id="logout-btn">
</form>
</div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{{ plotly_graph }}
<!-- errors -->
<!-- {% if error %}
<p class="error"><strong>Error:</strong> {{ error }}</p>
{% endif %}
-->
<!-- messages -->
<!-- {% for message in get_flashed_messages() %}
{{ message }}
{% endfor %} -->
</body>
</html>

I used a slightly different approach :
(simplified)
In my python code, I returned fig instead of the plot itself
In the HTML, I created a div with id( 'div_name'
In Javascript, through the API call received the data to recreate the plot
and then I only had to add Javascript: Plotly.plot("div_name",fig[("data],fig["layout"].
This way you have more flexibility trying out different sizing methods for either your div or the width-height arguments of the layout itself.

Related

How to save HTML tags + data into sqlalchemy?

I am creating a personal blog website with Flask and sqlalchemy.
While posting my blogs, I want the blog to be published with well formatted html.
Here is my model for Blogs:
class Blog(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(), index=True)
description = db.Column(db.Text(), index=True)
content = db.Column(db.Text(), index=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
likes = db.Column(db.Integer, default=0)
dislikes = db.Column(db.Integer, default=0)
comments = db.relationship('Comment', backref='commented_by', lazy='dynamic')
def __repr__(self):
return 'Title <>'.format(self.title)
And here is my form for adding blog:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">Add Blog</h1>
<br>
</div>
</div>
<form action="" method="POST" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.title.label }}<br>
{{ form.title(size=30) }}<br>
</p>
<p>
{{ form.description.label }}<br>
{{ form.description(size=30) }}<br>
</p>
<p>
{{ form.content.label }}<br>
{{ form.content() }}<br>
</p>
<p>
{{ form.submit() }}
</p>
</form>
{{ ckeditor.load() }}
{{ ckeditor.config(name='content') }}
{% endblock %}
This is how I am rendering my blog:
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h1 class="code-line text-center" data-line-start="14" data-line-end="15">{{ blog.title }}</h1>
<br>
{{ blog.content }}
</div>
</div>
</div>
{% endblock %}
While adding blog, I am using a text editor
But once it has been posted and I render it on view blog page, no html content is being rendered not even linebreaks
How can I save html content and tags in my sql database and then render it using jinja template?
first, what is wrong:
the text you get from the text field in the form is not the same thing as HTML that renders it, what you are getting is the text.
in case you want to get the HTML generated inthat form, you should integrate a rich text editor, like quilljs.com, or tiny.cloud in your template, that will have a field that you can use, to grab the HTML it generated, and it will also allow you to create nice looking blog articles.
if you do not want this either, to get html from that form, writing HTML directly in that form will give you what you want.
In the context of markdown, it is actually possible to apply the same format to your database-saved content. You can use a few packages to help you work with HTML in your database.
To begin, let me suggest Stackoverflow QA forms. Notice how it has enabled markdown editing and a nice little preview of the text being written. To enable the preview, you can install the flask-pagedown package in your virtual environment.
(venv)$ pip3 install flask-pagedown
Initialize a pagedown object in your application's instance, say in __init__.py file, or whatever other file you are using.
# __init__.py
from flask import Flask
from flask_pagedown import PageDown
app = Flask(__name__)
pagedown = PageDown(app)
Within your head tags in HTML, add this CDN call whose files you do not need to have in your application.
<!-- base.html -->
{% block head %}
{{ pagedown.html_head() }}
{% endblock %}
Or this:
<head>
{{ pagedown.html_head() }}
</head>
If you prefer to use your own JavaScript source files, you can simply include your Converter and Sanitizer files directly in the HTML page instead of calling pagedown.html_head():
<head>
<script type="text/javascript" src="https://mycdn/path/to/converter.min.js"></script>
<script type="text/javascript" src="https://mycdn/path/to/sanitizer.min.js"></script>
</head>
Now, simply update your forms to use PageDownField:
# forms.py
from flask_pagedown.fields import PageDownField
class Post(FlaskForm):
post = PageDownField('Comment', validators=[DataRequired()])
Or this:
<form method="POST">
{{ form.pagedown(rows=10) }}
</form>
That's it! You should be able to have a client-side post preview right below the form.
Handling Rich Text in the Server
When the post request is made, then only raw markdown will be sent to the database and the preview will be discarded. It is a security risk to send HTML content to your database. An attacker can easily construct HTML sequences which don't match the markdown source and submit them, hence the reason why only markdown text is submitted. Once in the server, that text can be converted back to HTML using a Python markdown-to-html convertor. There are two packages that you can make use of. Install then in your virtual environment as seen below:
(venv)$ pip3 install markdown bleach
bleach is used to sanitize the HTML you want converted to allow for a set of tags.
At this point, the next logical step would be to cache your content field content while in the database. This is done by adding a new field, let us say content_html, in your database specifically for this cached content. It is best to leave your content field as it is in case you would want to use it.
# models.py
class Blog(db.Model):
content = db.Column(db.String(140))
content_html = db.Column(db.String(140))
#staticmethod
def on_changed_body(target, value, oldvalue, initiator):
allowed_tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code',
'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul',
'h1', 'h2', 'h3', 'p']
target.content_html = bleach.linkify(bleach.clean(
markdown(value, output_format='html'),
tags=allowed_tags, strip=True))
def __repr__(self):
return f'Title {self.title}'
db.event.listen(Blog.content, 'set', Blog.on_changed_body)
The on_changed_body() function is registered as a listener of SQLAlchemy’s “set” event for body , which means that it will be automatically invoked whenever the body field is set to a new value. The handler function renders the HTML version of the content and stores it in content_html , effectively making the conversion of the Markdown text to HTML fully automatic.
The actual conversion is done in 3 steps:
markdown() function does an initial conversion to HTML. The result is passed to clean() function with a list of approved HTML tags
clean() function removes any tags that are not in the whitelist.
linkify() function from bleach converts any URLs written in plain text into proper <a> links. Automatic link generation is not officially in the Markdown specification, but is a very convenient feature. On the client side, PageDown supports this feature as an optional extension, so linkify() matches that functionality on the server.
In your template, where you want to post your content you can add a condition such as:
{% for blog in blogs %}
{% if blog.content_html %}
{{ blog.content_html | safe }}
{% else %}
{{ blog.content }}
{% endif %}
{% endfor %}
The | safe suffix when rendering the HTML body is there to tell Jinja2 not to escape the HTML elements. Jinja2 escapes all template variables by default as a security measure, but the Markdown-generated HTML was generated by the server, so it is safe to render directly as HTML.

Why is using jinga template returning data as none on a webpage using flask?

I am trying to print basically a table to display data from a function I have called on flask on a webpage. I looked over Jinga templates and that is what I attempted to use, however to no avail.
My code is attached below. result from my cv_acp file is what I am trying to display in a table form.
Currently, my TSN_PIC returns result as follows:
The input video frame is classified to be PlayingCello - 99.33
PlayingGuitar - 0.28 PlayingPiano - 0.16 BoxingSpeedBag - 0.10
StillRings - 0.06
But I want to be able to display this on a web page using flask in a table format
My code is as follows:
cv_acp
def TSN_PIC(img):
img = image.imread(img)
fig, ax = plt.subplots(figsize=(18, 18))
ax.imshow(img.asnumpy())
transform_fn = transforms.Compose([
video.VideoCenterCrop(size=224),
video.VideoToTensor(),
video.VideoNormalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
img_list = transform_fn([img.asnumpy()])
net = get_model('vgg16_ucf101', nclass=101, pretrained=True)
pred = net(nd.array(img_list[0]).expand_dims(axis=0))
classes = net.classes
topK = 5
ind = nd.topk(pred, k=topK)[0].astype('int')
print('The input video frame is classified to be')
for i in range(topK):
result = ('\t%s - %.2f'%(classes[ind[i].asscalar()], nd.softmax(pred)[0][ind[i]].asscalar()*100))
print((result))
return plt.show()
app.py
#app.route("/cv/action_prediction/TSN_PIC", methods=['POST'])
def cv_acp_TSN_PIC_upload_image():
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No image selected for uploading')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
print(app.config)
path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
print(path)
file.save(path)
#print(file.config)
result = cv_acp.TSN_PIC(path)
# print (results)
#print('upload_image filename: ' + filename)
flash('Image successfully uploaded and displayed below')
return render_template('cv_acp_TSN_PIC.html', filename=filename, result=result)
else:
flash('Allowed image types are -> png, jpg, jpeg, gif')
return redirect(request.url)
#app.route('/cv/action_prediction/TSN_PIC/display/<filename>')
def cv_acp_TSN_PIC_display_image(filename):
#print('display_image filename: ' + filename)
#return MASK_RCNN('static', filename='uploads/' + filename)
return redirect(url_for('static', filename='uploads/' + filename), code=301)
if __name__ == "__main__":
#app.run()
app.run()
cv_acp_TSN_PIC.html
<div id="content" class="p-4 p-md-5 pt-5">
<h2 class="mb-4">TSN PIC</h2>
<!Doctype html>
<title>Python Flask File Upload Example</title>
<h2>Select a file to upload</h2>
<p>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</p>
{% if filename %}
<div>
<img src="{{ url_for('cv_acp_TSN_PIC_display_image', filename=filename) }}">
{% block content %}
<div class="container">
<p>{{results}}</p>
</div>
{% endblock %}
</div>
{% endif %}
<form method="post" action="/cv/action_prediction/TSN_PIC" enctype="multipart/form-data">
<dl>
<p>
<input type="file" name="file" autocomplete="off" required>
</p>
</dl>
<p>
<input type="submit" value="Submit">
</p>
</form>
</div>
Create a list of dictionaries of the data you need and return that. Then you can loop over the data and build your table.
results = []
for i in range(topK):
result = ('\t%s - %.2f'%(classes[ind[i].asscalar()], nd.softmax(pred)[0][ind[i]].asscalar()*100))
datadict = {
'header': yourheadername,
'data': yourdatahere
}
results.append(datadict)
return results
<table border=1>
{% for result in results%}
<tr>
<th>
{{result.header}}
</th>
</tr>
<tr>
<td>
{{result.data}}
</td>
</tr>
{% endfor %}
</table>
If you're working in a terminal or in a Jupyter notebook, plt.show() does what you want. For a web page, not so much.
You have a good start otherwise, based it seems on getting an uploaded image to display. So your challenge will be to either save the matplotlib image to disk before you generate the page, or to defer generating the image until it's requested by way of the <img src=..., then somehow return the image bits from cv_acp_TSN_PIC_display_image instead of a path to the saved file.
To do the former, plt.savefig('uploads/image.png') might be what you need, with the caveat that a fixed filename will break things badly as soon as you have multiple users hitting the app.
To do the latter, see this question and its answer.

Redirecting into another page in Django

I am working in a project in Django where someone tries to fill the info of some patients and after hitting the submit button i would like o redirect it into a page with the list of all the existing patients, i am trying using a action tag in the html but it seems not to work, i would like to know what i am doing wrong.
html
{%extends 'base.html'%}
{%load staticfiles%}
{%block body_block%}
<link rel="stylesheet" href="{%static 'patients/css/patientform.css'%}">
<form action="{% url 'patients'%}" method="POST">
<div class="wrapper">
{%csrf_token%}
<div class="Patient">
<h3>Informacion del Paciente</h3>
{{patientinfo.as_p}}
</div>
<div class="Medical">
<h3>Informacion Medica</h3>
{{medicalinfo.as_p}}
</div>
<div class="Insurance">
<h3>Informacion de Seguro</h3>
{{insuranceinfo.as_p}}
</div>
<div class="FirstRelative">
<h3>Antecedentes Familiares</h3>
<h5>Primer Caso</h5>
{{first_relative.as_p}}
<h5>Segundo Caso</h5>
{{second_relative.as_p}}
</div>
</div>
<input id="submit" type="submit" value="Agregar">
</form>
{%endblock%}
Url patterns
from django.urls import path
from .views import *
urlpatterns = [
path('',PatientsList.as_view(),name='patients'),
path('addpatient',PatientFormView,name='addpatient'),
]
Redirection should be made after Post request retrieval in your views.py
# AT POST REQUEST END
return redirect("patients")
Django Docs:
https://docs.djangoproject.com/en/3.0/topics/http/shortcuts/#redirect
In the end of your PatientFormView you should redirect with use of:
return redirect("patients")
For more details check Django documentation: docs.djangoproject.com/en/3.0/topics/http/shortcuts/#redirect

Django project - crispy forms not rendering in the browser

As part of a Django project, I have created the following in the views.py file
def profile(request):
u_form =UserUpdateForm()
p_form =ProfileUpdateForm()
context={
'u-form': u_form,
'p-form': p_form
}
I am now trying to render these forms on the html page (profile.html) with the following code:
{% extends "socialmedia/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
</div>
</div>
<form method="POST" enctype="multipart/form-data>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Information</legend>
{{u_form|crispy}}
{{p_form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update....</button>
</div>
</form>
</div>
{% endblock content %}
Everything else is rendering on the page correctly, except for this bit:
{{u_form|crispy}}
{{p_form|crispy}}
There are no errors on running the server, so I am finding it hard to trouble shoot.
The code in the forms.py file is as follows:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserRegisterForm(UserCreationForm): #form that inherits from the usercreationform
email = forms.EmailField()
class Meta:
model = User
#when this form validates it creates a new user
#type the fields to be shown on your form, in that order.
fields = ['username','email','password1','password2']
"""this gives us a nested name space for configurations and
keeps the configs in one place. The model that will be affected is
the user model e.g. when we do a form.save it saves it to the user model.
And the fields we have are the fields we want on the form. It shows order too.
"""
#create a model form...this allows us to create a form that#works with a specific database model#
#we want a form that works with our user model
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model= Profile
fields=['image']
My question is:
Could someone tell me why these additional fields (username, email and image update) are not being shown on the profile html above the 'update' button? In what file have I made the mistake. Note: I'd also appreciate an explanation of the rendering of these u-forms, along with the solution(pointing out my error). I understand that u-form is an instance of UserUpdateForm, but not much else.
context={
'u-form': u_form,
'p-form': p_form
}
You just have a typo. Change the - to _

Using One decorator instead of multiple? "One to many" and "many to one"?

I am trying to design a simple webpage as following to get the profile pics of students. My question below is just a simple example to ask my question and understand the logic.
Let's say; I have three classes named as Class_A2E, Class_F2J and Class_K2O. In a school, this can 1st year, 2nd year and 3rd year students. Each year student are divided by 5 class named as A-E [thus A,B,C,D,E] (1st year), F-J(2nd year) and K-O (3rd year). I want to show the picture of the student as png and give an a link as option to download as PDF file (which is high quailty).
As can be seen, I have a same decorator but with diffrent names to design such a webpage. What I would like to do; using the one decorator for all.
another problem: After printing the image, I want to return to the same class page to search for another student. However, it always gives the link for the 1stYear.
html files are in "templates" folder.
main.css is in "static" folder.
"static" folder contains png images in png_files and pdf images in pdf_files folder.
Here is my codes as below:
# run.py
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['SECRET_KEY'] = "7642e9aed5740e5ggca2de92ae021de5"
#app.route("/")
#app.route("/my_classes_A2E")
def my_classes_A2E():
return render_template("my_classes_A2E.html", title= "my_classes_A2E", class_ids=[{'name':'ClassA'},{'name':'ClassB'},{'name':'ClassC'},{'name':'ClassD'},{'name':'ClassE'}])
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_A2E():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_A2E", html_title="1stYear")
#app.route("/my_classes_F2J")
def my_classes_F2J():
return render_template("my_classes_F2J.html", title= "my_classes_F2J", class_ids=[{'name':'ClassF'},{'name':'ClassG'},{'name':'ClassH'},{'name':'ClassI'},{'name':'ClassJ'}])
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_F2J():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_F2J", html_title="2ndYear")
#app.route("/my_classes_K2O")
def my_classes_K2O():
return render_template("my_classes_K2O.html", title= "my_classes_K2O", class_ids=[{'name':'ClassK'},{'name':'ClassL'},{'name':'ClassM'},{'name':'ClassN'},{'name':'ClassO'}])
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_K2O():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_K2O", html_title="3rdYear")
if __name__ == "__main__":
app.run(debug= True)
## ANOTHER SOLUTION: the above code in run.py can be edited as below and it will also works fine. ###
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['SECRET_KEY'] = "7642e9aed5740e5ggca2de92ae021de5"
#app.route("/")
#app.route("/my_classes_A2E/")
def my_classes_A2E():
return render_template("my_classes_A2E.html", title= "my_classes_A2E", class_ids=[{'name':'ClassA'},{'name':'ClassB'},{'name':'ClassC'},{'name':'ClassD'},{'name':'ClassE'}])
#app.route("/my_classes_A2E/get_input_and_print_imgs_A2E", methods = ['GET','POST'])
def get_input_and_print_imgs_A2E():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_A2E", html_title="1stYear")
#app.route("/my_classes_F2J/")
def my_classes_F2J():
return render_template("my_classes_F2J.html", title= "my_classes_F2J", class_ids=[{'name':'ClassF'},{'name':'ClassG'},{'name':'ClassH'},{'name':'ClassI'},{'name':'ClassJ'}])
#app.route("/my_classes_F2J/get_input_and_print_imgs_F2J", methods = ['GET','POST'])
def get_input_and_print_imgs_F2J():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_F2J", html_title="1stYear")
#app.route("/my_classes_K2O/")
def my_classes_K2O():
return render_template("my_classes_K2O.html", title= "my_classes_K2O", class_ids=[{'name':'ClassK'},{'name':'ClassL'},{'name':'ClassM'},{'name':'ClassN'},{'name':'ClassO'}])
#app.route("/my_classes_K2O/get_input_and_print_imgs_K2O", methods = ['GET','POST'])
def get_input_and_print_imgs_K2O():
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",class_id=class_id, student_name=student_name, html_link="my_classes_K2O", html_title="1stYear")
if __name__ == "__main__":
app.run(debug= True)
#
########## this is layout.html as template for all other html fies ######
<!DOCTYPE html>
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
{% if title %}
<title> MY WEB PAGE - {{ title }} </title>
{% else %}
<title> MY WEB PAGE </title>
{% endif %}
<header class="site-header">
<nav class="navbar navbar-expand-md navbar-dark bg-steel fixed-top">
<div class="container">
<a style="color:#z00000" class="navbar-brand mr-4" href="/my_classes_A2E"><b>1stYear</b></a>
<a style="color:#z00000" class="navbar-brand mr-4" href="/my_classes_F2J"><b>2ndYear</b></a>
<a style="color:#z00000" class="navbar-brand mr-4" href="/my_classes_K2O"><b>3rdYear</b></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggle" aria-controls="navbarToggle" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
</header>
</head>
<body>
<div class="container">
{% block content %}
{% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
################ my_classes_A2E.html #######################
{% extends "layout.html" %}
{% block content %}
<h1 style="color:#f00000"> This page is under construction and will be updated soon! </h1>
<form style="width: 50px !important; min-width: 100px; max-width: 100px;" name="pass_class_idt" id="pass_class_id" action="." method="POST">
<label>Class ID 1stYear </label>
<select name="class_id_select" class="selectpicker form-control">
{% for class_id in class_ids %}
<option value="{{ class_id.name }}">{{ class_id.name }}</option>
{% endfor %}
</select>
<label> Student Name in1stYear :</label>
<input type="text" name="student_name">
<input type="submit" value="submit">
</form>
{% endblock %}
################ my_classes_F2J.html #######################
{% extends "layout.html" %}
{% block content %}
<h1 style="color:#f00000"> This page is under construction and will be updated soon! </h1>
<form style="width: 50px !important; min-width: 100px; max-width: 100px;" name="pass_class_id" id="pass_class_id" action="." method="POST">
<label>Class ID 2ndYear </label>
<select name="class_id_select" class="selectpicker form-control">
{% for class_id in class_ids %}
<option value="{{ class_id.name }}">{{ class_id.name }}</option>
{% endfor %}
</select>
<label> Student Name in 2ndYear:</label>
<input type="text" name="student_name">
<input type="submit" value="submit">
</form>
{% endblock %}
################ my_classes_K2O.html #######################
{% extends "layout.html" %}
{% block content %}
<h1 style="color:#f00000"> This page is under construction and will be updated soon! </h1>
<form style="width: 50px !important; min-width: 100px; max-width: 100px;" name="pass_class_id" id="pass_class_id" action="." method="POST">
<label> Class ID 3rdYear </label>
<select name="class_id_select" class="selectpicker form-control">
{% for class_id in class_ids %}
<option value="{{ class_id.name }}">{{ class_id.name }}</option>
{% endfor %}
</select>
<label> Student Name in 3rdYear:</label>
<input type="text" name="student_name">
<input type="submit" value="submit">
</form>
{% endblock %}
################ print_student_profilepics.html #######################
{% extends "layout.html" %}
{% block content %}
<h1 style="color:#f00000"> This page is under construction and will be updated soon! </h1>
<div class="container">
<embed src="/static/png_files/{{ class_id }}_{{ student_name }}_profilepics.png" width = "700" height= "700">
</div>
<p style="margin-left:23rem;"> <b> Download as: PDF </b> <small style="color:#f00000;"> (for High Quality) </small> </p>
<p style="margin-left:23rem;"> <b> Go Back To : {{ html_title }} </b> </p>
{% endblock %}
Parametrizing routes
When defining a flask route the < > syntax enables you to define a variable url string parameter, that will take care of all routes written in that form:
For instance:
#app.route("/my-classes/<class_group>")
def my_classes(class_group):
...
Would route urls like /my-classes/A2E through the my_classes(class_group) function with the class_group parameter set to str: "A2E". I have updated from your actual initial url pattern, /my_classes_A2E because it is a more standard way of routing, although you could achieve the same effect with /my_classes_<class_group>, if you want to keep yours. Also, it's more conventional to write routes with hyphens - instead of underscores _ (see the url of that stackoverflow link !)
Routes priority
another problem: After printing the image, I want to return to the same class page to search for another student. However, it always gives the link for the 1stYear.
Regarding this remark note that you had defined the same url routes for your 3 class groups !
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_A2E():
...
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_F2J():
...
#app.route("/", methods = ['GET','POST'])
def get_input_and_print_imgs_K2O():
...
Though flask doesn't raise any error when you launch the server, only the first function will treat your / url request, which explains why you would only get the 1stYear links.
Wrapping it up
You might be interesting in first defining the dictionary that will hold the logic of your classes: these are the first 3 dictionaries. Given this you can reduce your 2*3 routes to 2 routes because all the "group" logic would be factorized.
# run.py
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['SECRET_KEY'] = "7642e9aed5740e5ggca2de92ae021de5"
class_group_dict = {
"A2E": [{'name': 'ClassA'}, {'name': 'ClassB'}, {'name': 'ClassC'}, {'name': 'ClassD'}, {'name': 'ClassE'}],
"F2J": [{'name': 'ClassF'}, {'name': 'ClassG'}, {'name': 'ClassH'}, {'name': 'ClassI'}, {'name': 'ClassJ'}],
"K2O": [{'name': 'ClassK'}, {'name': 'ClassL'}, {'name': 'ClassM'}, {'name': 'ClassN'}, {'name': 'ClassO'}]
}
class_group_to_year = {
"A2E": "1stYear",
"F2J": "2ndYear",
"K2O": "3rdYear"
}
class_id_to_class_year = {
class_dict["name"]: class_year for class_year, list_class in class_group_dict.items()
for class_dict in list_class
}
#app.route("/my-classes/<class_group>/get-input-and-print-imgs", methods=['GET', 'POST'])
def get_input_and_print_imgs(class_group): # test
class_id = request.form.get('class_id_select')
student_name = request.form["student_name"]
return render_template("print_student_profilepics.html",
class_id=class_id, student_name=student_name,
html_link=f"my_classes_{class_id_to_class_year[class_group]}",
html_title=class_group_to_year[class_group])
#app.route("/my-classes/<class_group>")
def my_classes(class_group): # class_group: one of ["A2E", "F2J", "K2O"]
return render_template(f"my_classes_{class_group}.html",
title=f"my_classes_{class_group}",
class_ids=class_group_dict[class_group])
if __name__ == "__main__":
app.run(debug=True)
Final notes
I haven't taken the liberty of changing the .html names but conventions would suggest using hyphens instead. Also for clarity, maybe it be better to decide for one naming field for the class_name / id (ie. classA, classB, ect...) since it is referred with both.
HTML files update
You need to change the action field of the <form> tag in my_classes_A2E, my_classes_F2J, my_classes_K2O, to point to the good route, ie. this would be for my_classes_A2E
<form style="width: 50px !important; min-width: 100px; max-width: 100px;" name="pass_class_idt" id="pass_class_id" action="/my-classes/A2E/get-input-and-print-imgs" method="POST">