How to implement a next button in flask? - python

I am trying to use Flask to implement a basic query over a database. Each page should show up to 8 results, and if there are more than 8, it should have a next page button. Everything is working as intended except for the next page button, but I'm not sure what I'm doing wrong.
Here is the Python code I have:
#app.route("/results", methods=["POST"])
def results(result = None):
"""
result page
:return:
"""
query_text = request.form["query"] # Get the raw user query from home page
#~results processing code removed as it's not relevant
hasnext = False
if len(r)>1:
hasnext=True
return render_template("results.html", query=query_text, hits=h , result=r[0], page=1, start = 1, hasnext = hasnext) # add variables as you wish
#app.route("/results/<int:page_id>", methods=["POST"])
def next_page(page_id):
"""
"next page" to show more results
:param page_id:
:return:
"""
s = (page_id-1)*8+1 #numbering of results
next = False
if len(r) >= page_id:
next = True
return render_template("results.html", query=query_text, hits=h, result=r[page_id-1], page=page_id, start = s, hasnext = next)
and then here are the two ways I tried to implement the HTML I have for the button that isn't working:
This one doesn't work (even if I change the variable {{page_id}} to hard code a number)
<a href="{{ url_for('next_page', page_id={{page_id}}+1)}} ">Next
<span class="a-letter-space"></span>
<span class="a-letter-space"></span>
</a>
This one shows the button, and when I tried this code, I also added more to the Python:
Button:
{% if hasnext %}
<form method ="POST" action="/">
<input type="submit" name="Next" value="Next"/>
{% endif %}
</form>
added to Python:
if request.method == 'POST':
if request.form.get('Next') == 'Next':
return render_template("results.html"...)
Any advice on how to implement the next button would be appreciated, thanks!

It's an old post but let me give it a shot. Have you tried to paginate your results? Try this in your python file.
#app.route("/results")
def results():
page = request.args.get('page', 1, type=int)
query_text = Text.query.paginate(page=page,per_page=5)
return render_template('result.html', query_text =query_text)
Then at your results.html insert this code before {% endblock content %} :
{% for page_num in query_text.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
{% if page_num %}
{% if query_text.page == page_num %}
<a class="btn btn-info mb-4" href="{{ url_for('results', page=page_num) }}">{{ page_num }}</a>
{% else %}
<a class="btn btn-outline-info mb-4" href="{{ url_for('results', page=page_num) }}">{{ page_num }}</a>
{% endif %}
{% else %}
...
{% endif %}
{% endfor %}

Related

why pagination is not showing ? django

def allProductCat(request, c_slug=None):
c_page = None
products_list = None
if c_slug is not None:
c_page = get_object_or_404(Category, slug=c_slug)
products_list = Product.objects.all().filter(category=c_page, available=True)
else:
products_list = Product.objects.all().filter(available=True)
paginator = Paginator(products_list, 6)
try:
page = int(request.GET.get('page', '1'))
except:
page = 1
try:
products = paginator.page(page)
except(EmptyPage, InvalidPage):
products = paginator.page(paginator.num_pages)
return render(request, "category.html", {'category': c_page, 'product': products})
// Code for Html //
<div class="mx-auto">
{% if product.paginator.num_page %}
<hr>
<div class="text-center">
{% for pg in product.paginator.page_range %}
{{pg}}
{% endfor %}
</div>
{% endif %}
</div>
when i add all these codes pagination doesnt shows up anything when i type the links to next page manually its working perfectly i dont understand whats wrong in this code, also these div doesnt shows anything inside it when i type anything...
====== views.py =======
from django.core.paginator import Paginator
def HomeView(request):
show_data = VehicleModel.objects.all() # Queryset For pagiantion
# Pagination code start
paginator = Paginator(show_data, 3, orphans=1)
page_number = request.GET.get('page')
show_data = paginator.get_page(page_number)
# Pagination code end
context = {'page_number':page_number}
return render(request,'dashboard.html',context)
======= in HTML ==========
# <!-- Pagination Block with page number -->
<div class="container mt-5">
<div class="row float-right ">
<span class="m-0 p-0">
{% if show_data.has_previous %} # <!-- For Previous Button -->
<a class="btn btn-outline-info" href="?page={{show_data.previous_page_number}}&ok=#ok">Previous</a>
{% endif %}
<span>{% for pg in show_data.paginator.page_range %} # <!-- For Page Numbers Buttons -->
{% if show_data.number == pg %}
<a href="?page={{pg}}" class="btn btn-sm btn-primary">
<span class="badge">{{pg}}</span>
</a>
{% else %}
<a href="?page={{pg}}" class="btn btn-sm btn-secondary">
<span class="badge">{{pg}}</span>
</a>
{% endif %}
{% endfor %}</span>
{% if show_data.has_next %} # <!-- For Next Button -->
<a class="btn btn-outline-info" href="?page={{show_data.next_page_number}}&ok=#ok">Next</a>
{% endif %}
</span>
</div>
</div>

How to fix custom pagination (Python+Flask)?

I am trying to write my own pagination in Python, Flask, SQLite and sqlalchemy. The idea is that when the "next_page" button is pressed, the code sends a query to the database and loads next results. The "previous" button takes the view back to the previous results.
At the moment the pagination works partially. If I press "next_page" once, nothing happens. If I press "next_page" a second time, the next results load correctly. But if I press "previous_page" then it takes me back to the first page (and it should take me back to the previous page).
I tried to add...
previous_page_number = int(request.args.get("previous_page_number", 0))
if not (page_number := previous_page_number):
page_number = 1
...but then the"next_page" button stops working completely.
Does anyone know what I'm missing here?
PYTHON
list_of_games = list_of_games.order_by(GamesDatabase.date_added)
next_page_number = int(request.args.get("next_page_number", 0))
# previous_page_number = int(request.args.get("previous_page_number", 0))
if not( page_number := next_page_number ):
page_number = 1
# if not( page_number := previous_page_number ) :
# page_number = 1
c = list_of_games.count()
if next_page_number * 8 < c:
has_next_page = True
else:
has_next_page = False
list_of_games = list_of_games.order_by(GamesDatabase.date_added)[(page_number-1)*8:(page_number)*8]
args = []
if request.args:
for arg, val in request.args.items():
args.append({"name": arg, "value": val})
if next_page_number >1:
has_prev_page = True
else:
has_prev_page = False
return render_template("test.html", list_of_games=list_of_games, args=args,
has_next_page=has_next_page, previous_page_number=page_number-1,
has_prev_page=has_prev_page, next_page_number=page_number+1)
HTML
</div>
{% if has_next_page %}
<form action="" method="GET">
{% for arg in args %}
{% if "next_page_number" != arg.name %}
{% if "previous_page_number" !=arg.name %}
<input type="hidden" name="{{ arg.name }}" value="{{ arg.value }}" >
{% endif %}
{% endif %}
{% endfor %}
<input type="hidden" name="next_page_number" value="{{ next_page_number }}" />
<button type="submit">Next page </button>
</form>
{% endif %}
{% if has_prev_page %}
<form action="" method="GET">
{% for arg in args %}
{% if "next_page_number" !=arg.name %}
{% if "previous_page_number" !=arg.name %}
<input type="hidden" name="{{ arg.name }}" value="{{ arg.value }}" >
{% endif %}
{% endif %}
{% endfor %}
<input type="hidden" name="previous_page_number" value="{{ previous_page_number }}" />
<button type="submit">Previous page </button>
</form>
{% endif %}
https://pastebin.com/QLv3CqZW

Why is my checkbox is unchecked after saving?

I have created a checkbutton with Python (Django) like this:
in my views.py:
def list(response, list_id):
ls = ToDoList.objects.get(id=list_id)
if response.method == "POST": # If we are POST-ing something (saving, adding items, etc..)
print(response.POST)
if response.POST.get("save"): # SAVING CHECK-BUTTONS
for item in ls.listitem_set.all(): # Loop through all items
if response.POST.get("c" + str(item.id)) == "clicked": # Check if it has been clicked or not
item.complete = True
else:
item.complete = False
item.save()
elif response.POST.get("newItem"): # ADDING ITEM TO LIST
txt = response.POST.get("new") # Get text-input by name
if len(txt) > 2: # Check for valid input
ls.listitem_set.create(text=txt, complete=False)
else:
print("Invalid")
return render(response, "myapp/list.html", {"ls": ls})
and this is my list.html:
{% extends "myapp/base.html" %}
{% block title %}View List of Items{% endblock %}
{% block content %}
<h1>{{ls.name}}</h1>
<form method="POST" action="#">
{% csrf_token %}
<ul>
{% for item in ls.listitem_set.all %}
{% if item.complete == TRUE %}
<li><input type="checkbox" , value="clicked" , name="c{{item.id}}" checked>{{item.text}}</li>
{% else %}
<li><input type="checkbox" , value="clicked" , name="c{{item.id}}">{{item.text}}</li>
{% endif %}
{% endfor %}
</ul>
<button type="submit" , name="save" , value="save">Save</button> <!--Updates checked items -->
<input type="text" , name="new">
<button type="submit" , name="newItem" , value="newItem"> Add Item </button> <!--Adds new items -->
</form>
{% endblock %}
When I open 127.0.0.1:8000/list/1 in my broweser, it displays my 1st list with items and corresponding checkboxes. When I click on a checkbox it gets 'checked' but when I press save and reload, the box is unchecked again. What am I doing wrong here?
Hard to be certain without seeing the page in action, but I would try:
Changing your Django HTML tag if/else condition to 'True' rather than 'TRUE' as I believe in Python it's case sensitive.
Ensure you're ending up in the right path in your if/else statement.

How to get dynamic html table entries in a form to flask?

I am trying to create a form with an embedded table that the user can dynamically add and remove table rows while entering content into the cell inputs.
HTML
<form id="myForm" action="{{ url_for('hello_world') }}" method="POST">
<div class="form-row text-left">
<div class="col-1 text-left">
<input type="checkbox" id="skills" name="skills" value="Yes">
</div>
<div class = "col-11 text-left">
<h2>TECHNICAL SKILLS</h2>
</div>
</div><!--form-row-->
<div class="form-row">
<table id="myTable" name="skillsTable">
<tr>
<th>Category</th>
<th>Entries</th>
</tr>
</table>
</div><!--form-row-->
<br>
<button type="button" onclick="addSkill()">Add Row</button>
<button type="button" onclick="deleteSkill()">Delete row</button>
<hr>
<input type="submit" value="Submit" onclick="submit()" />
</form>
As you can see in the screenshot [![screenshot of the user form][1]][1] the name attribute is correctly being appended to added cell.
The goal is to have a way to get the table values dynamically created by the user over to the flask template where they can be displayed.
Javascript
<script>
var c1=0;
var c2=0;
function addSkill() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
cell1.innerHTML = "<input type='text' value=' ' name=cell1_"+c1.toString()+"> ";
cell2.innerHTML = "<input type='text' value=' ' name=cell2_"+c2.toString()+"> ";
c1++;
c2++;
}
function deleteSkill() {
document.getElementById("myTable").deleteRow(-1);
}
</script>
I have tried setting the name attribute for each newly created cell using a counter, but this still does not show up rendered in the flask template:
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['value'] = request.form['cell1_1']
except:
pass
return render_template("result.html",result = result)
result.html
{% if result.skills %}
<p>{{ result.value }}</p>
{% endif %}
In this example, I would expect to see "Language" show up on rendered after submitting the form if the checkbox is selected.
How can I refer to the table in the form from flask and loop through the <input> elements if they are dynamically created? Thx
[1]: https://i.stack.imgur.com/samhG.png
result.html
{% if result.skills %}
{% set skillsTable = result.skillsTable %}
<h2>TECHNICAL SKILLS</h2>
<table>
{% for skill in skillsTable %}
{% if loop.index|int % 2 == 0 %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% else %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% endif %}
{% endfor %}
{% endif %}
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['skillsTable'] = []
form = request.form
for key, value in form.items():
if key.startswith("cell"):
result['skillsTable'].append(value)
except:
pass
return render_template("result.html",result = result)

Flask - how to keep list index after form submit?

I have a list of images that I want to display on a page. These image names are formatted basically YYYYMMDD_HHMMSS.jpg. I want this single page to either list all images, or only list and show those taken on a certain date (meaning a main page, not like /index to show all images, /date-specific to show some images).
So far, I have been able to show all images, and click "next"/"previous" buttons to loop through all images. I also have a table below the image, showing all the images that are in the index.
Works great - no issues.
However, I am also trying to implement a date filter, where the user can select a date from the Calendar Picker, and have the site filter out and only show photos on that day. So far, I can successfully filter one time. However, when I click "next"/"previous" buttons, or choose an image from the table, it resets back to the full list of images.
How do I keep the filtered list? I thought I could do it by keeping the date chosen in the Input field, but after using the "next"/"previous" buttons, the whole page resets and it clears that field.
I also tried including the list in the HTML portion, but it still returns all the photos. (Also makes the URL ugly, since it includes the image list for each photo listed in the table):
<td> {{ image }} </td>
Here's a .gif of the page I'm working on.. First, you'll see I can successfully click around, navigate between all photos. Then, I can successfully filter to show photos on a specific date. However, anything past that keeps sending me back to the full image list.
Anyways, without further ado, here's the codes. (Note I try to keep it minimal, so might have omitted an important piece, so please let me know if I need to post something else here):
routes.py
import os
import random
from flask import render_template, url_for, request, Blueprint, redirect # noqa
from app import app
IMAGE_FOLDER = r"C:/MyPath/Test"
FAVORITE_LIST = os.path.join(IMAGE_FOLDER, "favorites.txt")
blueprint = Blueprint('images', __name__,
static_url_path='/static/images',
static_folder=IMAGE_FOLDER)
app.register_blueprint(blueprint)
images = os.listdir(IMAGE_FOLDER)
image_urls = ["20190411_123200.jpg", ... other images in a list]
class Photo_Index():
def __init__(self, index=0):
self.index = index
def increase_number(self, num_images):
if self.index == num_images:
self.index = 0
else:
self.index = self.index + 1
return self.index
def decrease_number(self, num_images):
if self.index == 0:
self.index = num_images
else:
self.index = self.index - 1
return self.index
def random_number(self, num_images):
self.index = random.randint(0, num_images)
return self.index
def set_number(self, number):
self.index = number
return self.index
# functions to create and edit Favorites. this works so I'm excluding]
def day_month_year(filename):
"""
Takes a string `20190212` and pulls out Year, Month, Date
"""
year = filename[:4]
month = filename[4:6]
day = filename[6:8]
return str(year + "-" + month + "-" + day)
def get_files_on(specific_date):
_files = []
print("\nLooking for files on:", specific_date, "\n")
for file in image_urls:
# print(file, day_month_year(file))
if day_month_year(file) == specific_date:
_files.append(file)
return _files
photo_index_obj = Photo_Index()
fav_photo_index = Photo_Index()
def update_index(rqst, indx_obj, num_images):
print("Updating index, have", num_images, "photos")
if num_images == 1:
indx_obj.set_number(0)
elif 'prev-photo' in rqst.form:
indx_obj.decrease_number(num_images)
elif 'next-photo' in rqst.form:
indx_obj.increase_number(num_images)
elif 'random-photo' in rqst.form:
indx_obj.random_number(num_images)
return indx_obj
#app.route("/<chosen_image>", methods=["GET", "POST"])
#app.route("/", methods=["GET", "POST"])
def default_template(date=None, image_list=None, chosen_image=None):
if image_list is None:
image_list = image_urls
num_images = len(image_list) - 1
if request.method == "POST":
if 'go-to-date' in request.form:
date = request.form['go-to-date']
image_list = get_files_on(date)
num_images = len(image_list) - 1
photo_index_obj.set_number(0)
if len(image_list) == 0:
image_list = ["no_images_for_date.jpg"]
elif 'prev-next-buttons' in request.form:
print("Updating index, have", num_images, "photos")
update_index(request, photo_index_obj, num_images)
elif 'favorite-photo' in request.form:
add_to_favorites(image_list[photo_index_obj.index])
elif 'un-favorite-photo' in request.form:
remove_from_favorites(image_list[photo_index_obj.index])
if chosen_image is None:
chosen_image = image_list[photo_index_obj.index]
elif chosen_image is not None:
photo_index_obj.set_number(image_list.index(chosen_image))
favorite = is_favorite(image_list[photo_index_obj.index])
print("Images:", image_list)
return render_template('index.html',
title="Local Image Viewer",
photo_index=photo_index_obj.index,
image=chosen_image,
image_list=image_list,
favorite=favorite)
#app.route("/<chosen_image>", methods=["GET", "POST"])
def chosen_image(chosen_image):
date = request.form['go-to-date']
return default_template(date=date,
chosen_image=chosen_image)
index.html (I omitted the Select list, as that's kind of superfluous for this post)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='styles/index.css') }}">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
{% extends "layout.html" %}
{% block content %}
<h3>Index: {{ photo_index }}</h3>
<h3>Filename: {{ image }}</h3>
<div id="calendar-selector">
{% include "/HTML Snippets/calendar.html" %}
</div>
<div class='image-container' id='image'>
{% include "/HTML Snippets/favorite_button.html" %}
<img src="{{ url_for('images.static', filename=image) }} " id="the-photo">
</div>
<div class='button-container' id='buttons'>
<form action="" method="post">
<input type="hidden" name="prev-next-buttons">
<input type="submit" value="Prev photo" name='prev-photo'>
<input type="submit" value="Next photo" name='next-photo'>
<input type="submit" value="Random photo" name='random-photo'>
<br/>
<button type='button' id='rotate-button' onclick="rotateMeCounterClockwise('#the-photo')">Rotate Photo CounterClockwise</button>
<button type='button' id='rotate-button' onclick="rotateMeClockwise('#the-photo')">Rotate Photo Clockwise</button>
</form>
</div>
<div class='table-container'>
<table id='image-list' name='select-from-table'>
{% for image_row in image_list | batch(3) %}
<tr>
{% for image in image_row %}
<td> {{ image }} </td>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
</body>
</html>
and the calendar bit, calendar.html
{% block topscripts %}
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='styles/calendar.css') }}">
<script>
$(function() {
$("#datepicker").datepicker({dateFormat: 'yy-mm-dd'});
});
</script>
{% endblock %}
{% block content %}
<form method="post" action="{{ url_for('default_template') }}">
<input type="hidden" name="calendar-form">
<p>
Date: <input type="text" id="datepicker" name='go-to-date'
{% if request.form['go-to-date'] is not none %}
value="{{request.form['go-to-date']}}"
{% endif %}
></p>
<input type="submit">
</form>
{% endblock %}
{% block endscripts %}
{% endblock %}
You need to pass along enough information in your next/previous form and in the table links to re-apply the date filter. Your calendar form is separate from the next/previous navigation form, the browser won't serialise information from one when submitting the other. Clicks on <a href="..."> links will not include the date input field value either.
Note that clicks on the table links generate GET requests, so you need to look for go-to-date in the request.values mapping to accommodate both query parameters and form data.
You need to look for this parameter not only when you receive a POST request, but for all requests:
if 'go-to-date' in request.values:
date = request.values['go-to-date']
image_list = get_files_on(date)
photo_index_obj.set_number(0)
if len(image_list) == 0:
image_list = ["no_images_for_date.jpg"]
else:
image_list = image_list or image_urls
num_images = len(image_list) - 1
if request.method == 'POST':
# ...
Then generate URLs that include the parameter:
{%- set url_params = {'go-to-date': request.values['go-to-date']} if request.values['go-to-date'] else {} -%}
{% for image in image_row %}
<td> {{ image }} </td>
{% endfor %}
For the next/previous form, just add a hidden input field with the current go-to-date value:
<form action="" method="post">
<input type="hidden" name="prev-next-buttons">
{%- if request.values['go-to-date'] -%}
<input type="hidden" name="go-to-date" value="{{ request.values['go-to-date'] }}">
{%- endif -%}
<input type="submit" value="Prev photo" name='prev-photo'>
<input type="submit" value="Next photo" name='next-photo'>
<input type="submit" value="Random photo" name='random-photo'>
<br/>
<button type='button' id='rotate-button' onclick="rotateMeCounterClockwise('#the-photo')">Rotate Photo CounterClockwise</button>
<button type='button' id='rotate-button' onclick="rotateMeClockwise('#the-photo')">Rotate Photo Clockwise</button>
</form>

Categories

Resources