I am not sure how to explain the issue, but I am trying to get flask to load my main() function once, and then stay "within" that function as the user clicks buttons.
I have a list of image names (e.g. 20190101.jpg, 20190111.jpg, 20190323.jpg) that are baiscally in YYYYMMDD.jpg format.
When I first load my site, I want it to show all images. However, I have also added a Calendar Picker that allows the user to select a date, and on the date selection, my routes.py looks for images in that range only, and returns those for view.
I can do this part, no problem. The issue is when the users click the "next photo"/"previous photo"/"random" button, or select an image from my table list. When they do that, the default photo list loads, instead of the filtered one.
As I have it, I understand that's because main() is getting called on the button click, and I have _images = image_urls at the very top, so it is effectively resetting the list.
How can I write my function(s) to load _images = image_urls ONCE, and then keep that list and update only as the user tells it to?
index.html:
<!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>
{% include "/HTML Snippets/calendar.html" %}
<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>
<h3>Choose image from list:</h3>
<form method="post">
<input type="hidden" name="photo-select">
<select name="select-image" onfocus='this.size=5;' onblur='this.size=1' onchange="this.size=1; this.blur(); this.form.submit()">
{% for eimage in image_list %}
<option
{% if eimage == image %}
selected
{% endif %}
value = {{ eimage }}
>
{{eimage}}
</option>
{% endfor %}
</select>
</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>
calendar.html
{% block topscripts %}
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='styles/calendar.css') }}">
<script>
$(function() {
$("#datepicker").datepicker();
});
</script>
{% endblock %}
{% block content %}
<form method="post">
<p>Date: <input type="text" id="datepicker" name='go-to-date'></p>
<input type="hidden" name="calendar-form">
<input type="submit">
</form>
{% endblock %}
{% block endscripts %}
{% endblock %}
routes.py
[imports and misc]
images = os.listdir(IMAGE_FOLDER)
def create_urls(files):
image_urls = []
for file in files:
if file.endswith(".jpg"):
image_urls.append(file)
return image_urls
image_urls = create_urls(images)
image_urls.append('favicon.ico')
# Subtract 2 below, so you don't include the
# favicon.ico
num_images = len(image_urls) - 2
class Photo_Index():
def __init__(self, index=0):
self.index = index
def increase_number(self):
if self.index == num_images:
self.index = 0
else:
self.index = self.index + 1
return self.index
def decrease_number(self):
if self.index == 0:
self.index = num_images
else:
self.index = self.index - 1
return self.index
def random_number(self):
self.index = random.randint(0, num_images)
return self.index
def set_number(self, number):
self.index = number
return self.index
...
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):
if 'prev-photo' in rqst.form:
indx_obj.decrease_number()
elif 'next-photo' in rqst.form:
indx_obj.increase_number()
elif 'random-photo' in rqst.form:
indx_obj.random_number()
return indx_obj
#app.route("/", methods=["GET", "POST"])
#app.route("/<chosen_image>", methods=["GET", "POST"])
def main(chosen_image=None):
_images = image_urls
if request.method == "POST":
if 'go-to-date' in request.form:
spec_date = request.form['go-to-date']
spec_date = datetime.datetime.strptime(spec_date, "%m/%d/%Y").strftime("%Y-%m-%d") # noqa
_images = get_files_on(spec_date)
elif 'prev-next-buttons' in request.form:
update_index(request, photo_index_obj)
elif 'photo-select' in request.form:
img = request.form.get("select-image")
photo_index_obj.set_number(_images.index(str(img)))
elif 'favorite-photo' in request.form:
add_to_favorites(_images[photo_index_obj.index])
elif 'un-favorite-photo' in request.form:
remove_from_favorites(_images[photo_index_obj.index])
if request.method == "GET":
if chosen_image is not None:
photo_index_obj.set_number(_images.index(chosen_image))
favorite = is_favorite(_images[photo_index_obj.index])
return render_template('index.html',
title="Local Image Viewer",
photo_index=photo_index_obj.index,
image=_images[photo_index_obj.index],
image_list=_images,
favorite=favorite)
(I tried to keep routes.py to show just the minimum required, but if you want to see any functions specifically, please let me know).
Here's an example of what I mean - on load, it shows all images. I can then choose a date, and the routes.py updates the _images list to include just those on that date (yay!). But when I click "next picture", instead of going to the next picture in the new _images, it reloads the images from image_urls. I understand that's because the first line in main() is _images = image_urls. (I'm learning Flask so I also understand my function is a little kludgy).
My question is how do I properly set these at first, but then after main is called the first time, use _images as set in the code?
What you ask for is quite similar to URL filters and pagination. Widespread practice (you can see it on most php-based blogs/e-shops/etc.) is when you click on a date, you apply a date filter, so your front-end makes a request like GET localhost?date=1.1.2019 and your flask app should extract that date and return images based on that filter. By default, first image of that list should be returned and when you click a next photo button, you make a request like GET localhost?date=1.1.2019&offset=2. Offset means that you need a second image (or page) from the all filtered results.
Related
I am a beginner in this field and in the process of preparing a final project for a CS50 course using Flask, Python and SQLite 3
The error appears when I try to delete the question whose position is first in the list, but the code works for the rest of the questions that are in different indexes
I don't know how to solve this bug please help!!
Thank you in advance
I have tried to print the id for each question to be deleted. Everyone is printed except for the first one print None, which gives me the error, even though it appears in the application interface.
this is my app.py code
#app.route("/list", methods=["GET", "POST"])
def list():
if request.method == "POST":
category = request.form.get("language")
if category == "All":
data = db.execute("SELECT * FROM questions")
question = []
answer = []
index = []
for item in data:
question.append(item["question"])
answer.append(item["answer"])
index.append(item["id"])
return render_template("list.html", data=zip(question,answer,index))
if request.form.get("language") == category:
data = db.execute("SELECT * FROM questions WHERE language=?", category)
question = []
answer = []
index = []
for item in data:
question.append(item["question"])
answer.append(item["answer"])
index.append(item["id"])
return render_template("list.html", data=zip(question,answer,index))
else:
data = db.execute("SELECT * FROM questions")
question = []
answer = []
index = []
for item in data:
question.append(item["question"])
answer.append(item["answer"])
index.append(item["id"])
return render_template("list.html", data=zip(question,answer,index))
#app.route("/delete", methods=["GET", "POST"])
def delete():
if request.method == "POST":
index = request.form["delete"]
print(index)
db.execute("DELETE FROM questions WHERE id=?", index)
flash("Questio deleted")
db.execute("UPDATE questions SET id = id - 1 WHERE id >?", index)
return redirect("/")
else:
data = db.execute("SELECT * FROM questions")
question = []
answer = []
index = []
for item in data:
question.append(item["question"])
answer.append(item["answer"])
index.append(item["id"])
return render_template("list.html", data=zip(question,answer,index))
and this is my list.html
{% extends "layout.html" %}
{% block title %}
list
{% endblock %}
{% block main %}
<form action="{{ url_for('list')" method="POST">
<div class="nestedGrid">
<div class="language">
<h2>Languages</h2>
<button class="list-item" name="language" value="All">ALL</button> <br>
<button class="list-item" name="language" value="python">PYTHON</button> <br>
<button class="list-item" name="language" value="c">C</button> <br>
<button class="list-item" name="language" value="javaScript">JS</button> <br>
<button class="list-item" name="language" value="java">JAVA</button> <br>
</div>
<div class="question">
<h2>Questions</h2>
<ul class="list">
{% for i, j, z in data %}
<li class="list-item panel" name=question_deleted>{{ i }}
<span class="tooltiptext">Show answer</span>
</li>
<li class="list-item panel">{{ j }}</li>
<form action="{{ url_for('delete')" method="post">
<button class="list-item" name="delete" value="{{ z }}">{{ z }} <i class="fa fa-trash"></i> </button>
</form>
{% endfor %}
</ul>
</div>
</div>
</form>
{% endblock %}
i attached screen shots of my code and my frontend app is in this repo:
screen shots
For everyone who faces the same problem, the problem was in the overlapping of requests between the list and the delete, so I combined them together in the same route using this answer:
multiple requests from the same form
and my app.py will:
#app.route("/list", methods=["GET", "POST"])
def list():
if request.method == "POST" and "language" in request.form:
cat = request.form.get("language")
if request.form['language'] == cat:
if cat == 'All':
data = db.execute("SELECT * FROM questions")
item = []
answer = []
id = []
for x in data:
item.append(x["question"])
answer.append(x["answer"])
id.append(x["id"])
return render_template("list.html", data=zip(item,answer,id))
else:
py = db.execute("SELECT * FROM questions WHERE language = ?", cat)
py_ques = []
py_answer = []
py_id = []
for i in py:
py_ques.append(i["question"])
py_answer.append(i["answer"])
py_id.append(i["id"])
return render_template("list.html", data=zip(py_ques,py_answer,py_id))
if request.method == "POST" and "deleted" in request.form:
id = request.form.get("deleted")
db.execute("DELETE FROM questions WHERE id=?", id)
flash("question deleted")
# rearange ids after deleting a question
db.execute("UPDATE questions SET id = id - 1 WHERE id > ?", id)
return redirect("/")
else :
data = db.execute("SELECT * FROM questions")
item = []
answer = []
index=[]
for x in data:
item.append(x["question"])
answer.append(x["answer"])
index.append(x["id"])
return render_template("list.html", data=zip(item,answer,index))
and list.html will:
{% extends "layout.html" %}
{% block title %}
LIST
{% endblock %}
{% block main %}
<form action = "/list" method="post">
<div class="nestedGrid">
<div class="language">
<h2>Languages</h2>
<button class="list-item" name="language" value="All">ALL</button> <br>
<button class="list-item" name="language" value="python">PYTHON <i class="fab fa-python"></i> </button> <br>
<button class="list-item" name="language" value="C">C </button><br>
<button class="list-item" name="language" value="javaScript">JS <i class="fab fa-js"></i></button><br>
<button class="list-item" name="language" value="java">JAVA <i class="fab fa-java"></i></button><br>
</div>
<div class="question">
<h2>Questions</h2>
<ul class="list">
{% for i, j, z in data %}
<li class="list-item accordion" name="question_deleted" value="{{ i }}">{{ i }}
<span class="tooltiptext">Show answer</span>
</li>
<li class="list-item panel" value="{{ j }}">{{ j }}</li>
<button class="list-item" name="deleted" value="{{ z }}"><i class="fa fa-trash" ></i></button>
{% endfor %}
</ul>
</div>
</div>
</form>
{% endblock %}
I hope this help
**views.py**
[if request.method == "POST":
from_date = request.POST.get("from_date")
print(from_date)
to_date = request.POST.get("to_date")
print(to_date)
get_date_from_dates = Scrapper.objects.all().filter(created_at=from_date, updated_at=to_date)
print(len(get_date_from_dates))
page = request.GET.get('page', 1)
paginator = Paginator(get_date_from_dates, 5)
global users
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
else:
user_list = Scrapper.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(user_list, 5)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
return render(request, "home.html", { 'users': users })
return render(request, "home.html", {'users': users})][1]
**home.html**
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<body>
<style>
h2 {text-align: center;}
</style>
<h1>Facilgo Completed Jobs</h1>
<form action="" method="post">
{% csrf_token %}
<label for="from_date">From Date:</label>
<input type="date" id="from_date" name="from_date">
<label for="to_date">To Date:</label>
<input type="date" id="to_date" name="to_date">
<input type="submit"><br>
</form>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Summary Details</h2>
<table id="bootstrapdatatable" class="table table-striped table-bordered" width="100%">
<thead>
<tr>
<th>user_registration_source_id</th>
<th>user_type</th>
<th>user_id</th>
<th>source</th>
<th>source_url</th>
<th>created at</th>
<th>updated at</th>
</tr>
</thead>
<tbody>
{% for stud in users %}
{% csrf_token %}
<tr>
<td>{{stud.user_registration_source_id}}</td>
<td>{{stud.user_type}}</td>
<td>{{stud.user_id}}</td>
<td>{{stud.source}}</td>
<td>{{stud.source_url}}</td>
<td>{{stud.created_at}}</td>
<td>{{stud.updated_at}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if users.has_other_pages %}
<ul class="pagination">
{% if users.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% if user.number|add:'-4' > 1 %}
<li>…</li>
{% endif %}
{% for i in users.paginator.page_range %}
{% if users.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% elif i > users.number|add:'-5' and i < users.number|add:'5' %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if users.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
</div>
</div>
</body>
</html>
Webpage
When I post my from date and to date it would check the "created at" and "updated at" field in table and able to view only the datas of particular date. I have written the post request and get the from date and to date from the form. Is there any solution after posting data only get the values of particular dates in table. But at the opening the webpage it should show all datas in table
Output:
Output Image
I think its better approach to use a certain time period if not chosen by the user. for example one month range.
from datetime import date as dt
from dateutil.relativedelta import relativedelta
if request.method == "POST":
if "from_date" and "to_date" in request.POST:
from_date = request.POST.get("from_date")
to_date = request.POST.get("to_date")
else:
from_date = dt.today()
to_date = today + relativedelta(months=+1)
and then filter with this dates.
I have this edit or update form in which I want to display only the image name in the form for a better user experience so that the user could know which image he has uploaded while creating the data.
I am storing the image name in the model as well,but i want to display the image name inside the image field.
forms.py
class MenuCategoryForm(forms.ModelForm):
image = forms.ImageField(allow_empty_file=True, required=False)
class Meta:
model = MenuCategory
fields = ['name', 'description', 'menu_options']
view
def menu_category_update(request, id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid():
if request.FILES['image']:
image = request.FILES['image']
image_url = upload_image(image, 'menu_category', image.name)
obj = form.save(commit=False)
obj.image_url = image_url
form.save()
else:
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(instance=item)
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
Template
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %} {{ form|crispy }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
Well in other to get the name of the image in your form you will be better off in using a form initial like so:
def menu_category_update(request,id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid:
obj = form.save(commit=False)
# obj.username = request.user
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(
initial={'image':item.image,
'name':item.name,
'description':iteem.description,
})# this are the fields that we want to show in the form
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
In your form html you will apply the form initial to the field that you want to show in your form, by doing something like this: form.initial.name As i have illustrated below :
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %}
<label> Image name </label>
{{form.initial.name}}
<label> Description </label>
{{ form.initial.description }}
<label> Image </label>
{{ form.initial.image }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
Now I want to send the json data to html, I just display the dictionary data(json), How to display the value of dictionary in the html.
The python code is:
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
img_file = request.files['img_file']
if img_file and allowed_file(img_file.filename):
filename = secure_filename(img_file.filename)
img_file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
raw_img_url = './static/asset/uploads/' + filename
result_img_url = './static/asset/output/Line/' + filename
ratio = check_banner(filename)
result_dict = {'result': ratio}
return render_template("upload.html", result_img_url=result_img_url, result=json.dumps(result_dict))
else:
return ''' ok</p> '''
else:
return redirect(url_for('upload'))
The html code:
{% extends "base.html" %}
{% block content %}
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" id="img_file" name="img_file" class="col-sm-4">
<input type="submit" value="check" class="btn">
</form>
<p>
{% if result_img_url %}
<img src="{{ result_img_url }}" width='400' height='350'>
{% endif %}
</p>
<ul>
<li>{{result}}</li>
</ul>
{% endblock %}
But the result html is, but I just want to show the value of result :
If you want to pass only one parameter in result, you may change result_dict = {'result': ratio} to result = ratio.
It will show only the result in the page:
I have a problem with if/else condition into my template.
I have a simple form and confirmation button. User should input text in this form, then should press button and only after that, user will see other part of page.
This is my template code:
{% extends "home/base.html" %}
{% load staticfiles %}
{{% block body %}
<h1 align="center">Analyzed text</h1>
<form class="form" action="analyze" method="post">
<div id="form">
<dd><textarea id="textarea" name="q" rows=10 cols=55 placeholder=" Input your text in japanese here ..."></textarea>
<dd><input class="myButton" type="submit" value="Analyze">
</div>
</form>
<div class=page>
{% if 'q' != None %}
{% include "kanji_analyzer/show_results.html" %}
{% endif %}
</div>
{% endblock %}}
views.py
from django.shortcuts import render_to_response
from kanji_analyzer.logic_part.kanji_analyzer import KanjiesText
def start_kanji(request):
return render_to_response('kanji_analyzer/main.html')
def show_entries():
global analyzed_text
global list_of_percents
global list_of_find_kanjies
return render_to_response('show_entries.html', {'analyzed_text': analyzed_text, 'list_of_percents': list_of_percents,
'list_of_find_kanjies': list_of_find_kanjies,})
def send_text(request):
if 'q' in request.POST:
q = request.POST['q']
a = KanjiesText(request.POST['q'])
a.remove_spaces_from_text()
list_of_percents = a.take_percent_count()
list_of_find_kanjies = a.list_find_kanjies()
for i in range(0,5):
if len(list_of_find_kanjies[i]) == 0:
list_of_find_kanjies[i] = ''
return render_to_response('kanji_analyzer/main.html', {'q': q, 'list_of_percents': list_of_percents,
'list_of_find_kanjies': list_of_find_kanjies,})
else:
q = "your form is empty"
return render_to_response('kanji_analyzer/main.html', {'q': q},)
This block if/else doesn't work. 'q' - value with user's text