Django - When button is clicked I want to change the dictionary content - python

On my html page I have a button, and a number being displayed. I want the number to increase by 1 every time the button is pressed. This is the code that I have so far, but for some it doesn't work.
mypage.html
<form method='get' action='#'>
<input type="submit" value="add" name="add"/>
</form>
<h1>{{ p }}</h1>
views.py
p = 1
def mypage(request):
global p
my_dictionary = {
"p" : p,
}
if request.GET.get('add'):
p = p+1
my_dictionary = {
"p" : p,
}
return render(request, "mypage.html", my_dictionary)

On every request a new instance of the python script is run which would result in your global variable not being retained. You should store the count in a database and recall the value on every request. There are options other than a database but the basic idea of needing some sort of persistent storage still exists.
Alternatively, you can have the requester keep track of the count and provide the current count in the request. You would then add one to the value provided in the request. This would require some additional code on the front end to maintain the count, and even then, if the user closes the browser the count will be reset.
As dm03514 pointed out, you can can also use sessions like so:
if 'p' in request.session:
request.session['p'] = request.session['p'] + 1
else:
request.session['p'] = 1

The p value needs to be kept track of across requests.
2 possibilities are
resend the data every request
store the data in a session and just make increment /decrement requests
Should the variable be shared between all users? Or just the current user?

It should work if there is a single instance of django running (although it is not the recommended approach like other's have suggested).
It didn't appear to work is because you used action='#', and the browser refused to resubmit the form when your URL already ends with #. Instead you can use the following template:
<form method='get' action='.'>
<input type="submit" value="add" name="add"/>
</form>
<h1>{{ p }}</h1>

Related

how to change the value of the array when the user types a new value in reached form

i am working on my recommendation system,it works fine but
when the user searches for a book ,it gives title and image of the books,but when the user type some other title with reloading the file i ,it gives the correct book title but it loads the image of the pervious
searched book
here is my search route, which get book's title and its image
#app.route('/search',methods=['GET','POST'])
def search():
choice = request.args.get('search')
# removing all the characters except alphabets and numbers.
# passing the choice to the recommend() function
# passing the choice to the recommend() function
books = recommend(choice)
image=get_image()
# if rocommendation is a string and not list then it is else part of the
# recommend() function.
if type(books) == type('string'):
return render_template('read.html', book=books,image=image,s="oppps")
else:
return render_template('read.html', book=books,image=image)
here is my code to get the image, where i have defined img list gobally
for i in indices.flatten():
img.append(data[data.index == i]
['Image'].values[0])
return book_list
I can't understand why it gives the previous searched book's image,while it should display the current searched title image (But it works fine when i rerun the py file again)
here is my searched form
{% block body %}
<form action="{{url_for('search')}}" , class="navbar-form" role="search" ,method="POST">
<input type="text" placeholder="Search Books" class="search mb-3" name="search">
<button class="search-btn">Search</button>
</form>
{% endblock %}
can u pls help me out with this
Thanks you in Advance
I think you got some logic error in your code, but from posted piece it is not clear what exactly is your issue.
For example, how did you connect that data: title of the book and it's image:
books = recommend(choice) // here you get the book(s), based on **choice** variable
image=get_image() // but what did you based on when picking the image(s) from the list
I think more code would clarify this problem.

Python Flask / HTML - what is the proper way of displaying an output after HTML form submission?

I am very new to web-development (first project) and have started playing around in Flask. The other day I made a very simple temperature converter which I was running on my local host. The page had a form input to type a value, two radio buttons with Fahrenheit and Celsius to define the system of the value, then a convert button. Here is a screenshot:
Here is my Flask code ("main.py"):
from flask import Flask, render_template
from flask import request, redirect
import temperature, convert, determine_system
app = Flask(__name__)
#app.route('/')
def html():
return render_template('index.html')
#app.route('/convert', methods = ['POST'])
def convert():
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
if __name__ == "__main__":
app.run()
As you can see, the first function called "html()" initially renders the "index.html" file and the function "convert()" is executed upon clicking the "Convert" button. There are a few other functions that I have in other .py files in the directory that convert the number to the new system.
Here is the body of my "index.html" code:
<body>
<div id="banner">
<h1>Temperature Converter</h1>
<p class="lead">Use this tool to convert temperature between measurement systems</p>
</div>
<form action="/convert" method="post" target="dummyframe">
<input type="text" name="temperature"></input>
<input type="radio" name="system" value="Fahrenheit">Fahrenheit</input>
<input type="radio" name="system" value="Celsius">Celsius</input>
<br>
<br>
<input type="submit" value="Convert"></input>
</form>
</body>
</html>
To display the converted temperature on the webpage, I currently have another HTML file called "convert.html" in my templates directory that is an exact copy of the "index.html" file, except it includes the following three lines of code in the body after the :
div id="output"></div>
<p class="output-statement">{{ temp }}° {{ system }} is equal to {{ new_temp }}° {{ destination_system }}</p>
</div>
In my Flask file ("main.py), I instruct the "convert()" function to render the "convert.html" template which includes the output statement in the code above:
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
This then results in the following (notice the new web address):
I suspect that my way of outputting the converted temperature by redirecting to a new HTML file and web address (http://127.0.0.1:5000/convert) is not efficient or even the correct way of showing accomplishing this. What is the proper way to output something like this? Is there something I can add to the "index.html" file that would allow me to get rid of the "convert.html" file completely? If so, what would I change the last line of the "convert()" function in my Flask ("main.py") file to?
Thank you in advance and any links with more information on this concept are very appreciated!
Yes there is a more efficient solution where you do not need the convert.html:
This is what you will want in your main route. (note: I suggest renaming your route function to something like "index" or "temp" other than "html")
#app.route('/', methods=["GET","POST"])
def html():
output = ""
if request.method == "POST":
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
output = f"{ temp}° { system } is equal to { new_temp }° { destination_system }"
return render_template('index.html', output=output)
Make sure to import request. using: from flask import request
and in your index.html you will now have:
<div id="output"></div>
<p class="output-statement">{{output}}</p>
</div>
And make sure to change form action to action="#" or action=""

HTML input of type time in flask - how to autocomplete minutes/seconds if missing

I'm using a form with a submit button that is processed through Flask in order to add a new task (a row) in a SQLite database called tasks.
Here is the HTML <div/> container with the respective block content for the Flask part:
<div class="container">
{% block content %}
<form name="task_form" method="post" action="">
{{ form.csrf_token }}
<input type="text" name="task_title" placeholder="Title..."/>
<input type="text" name="task_description" placeholder="Description..."/>
<input type="date" name="task_date_due" placeholder="Due date..."/>
<input type="time" name="task_clock_due" placeholder="Due date (clock)..." step="1"/>
<input type="submit" name="task_submit" value="Add task"/>
</form>
{% endblock %}
</div>
On the Python side I have the following function that processes the GET and POST requests for the specific page:
#app.route('/db', methods=['GET', 'POST'])
def db():
# Create form
form = TaskForm(request.form)
# Initialize DB connection
init_db_conn()
# Handle POST request
if request.method == 'POST':
# Get form data
title = request.form['task_title']
description = request.form['task_description']
date = request.form['task_date_due']
time = request.form['task_clock_due']
if title != '' and description != '' and date != '' and time != '':
str_dtime = date + ' ' + time
db_conn = get_db_conn()
create_task(db, title, description, str_dtime)
elif request.method == 'GET':
pass
db_conn = get_db_conn()
cur = db_conn.cursor()
cur.execute('SELECT * FROM tasks')
tasks = cur.fetchall()
tmp = render_template('db.html', form=form, tasks=tasks)
return tmp
I'm new to Flask, my HTML skills are pretty rusty so I might be missing something but whenever I submit the data from my form through the page, I haven't entered the full time stamp (I use separate date and time inputs to allow using the calendar popup and time formatted field; can be done in a better way but for now it's what it is), I get empty string.
Example:
If I have entered 08:00:-- PM I will get empty string
If I have entered 08:--:-- PM I will get empty string.
What I was expecting is to get an autocompletion of the minutes/seconds as long as the hour has been selected.
Example:
If I have entered 08:00:-- PM I will get 08:00:00 PM (internally depending on the format I have picked on the Python side it will be converted to 20:00:00)
If I have entered 08:--:-- PM I will get 08:00:00 PM (internally depending on the format I have picked on the Python side it will be converted to 20:00:00)
Is there an easy way to fix this behaviour or do I have to create a custom input field? I can probably add a default value or just the current time as value to prevent this but it just goes around the issue. In case the user deletes the default value to enter another one and forgets to fill all the info, the problem will occur again.
I don't think you can get it to auto-complete the missing values in the HTML, but you could always set the default to 00:00:00 for example, then if they only change the hour the seconds and minutes are still at zero. They could still delete the 0's but you could get around this using a validator which won't let them enter an invalid time:
<input type="time" name="task_clock_due" placeholder="Due date (clock)..." step="1", value="00:00:00"/>
<span class="validity"></span>

How to pass value from python to html form using flask/jinja

So I first create an array of all folders in a specific directory, I then pass that to my html file.
def test_yt_vid():
mylist = os.listdir(WD+r"static/"+YOUTUBE_FOLDER)
full_path = (WD+YOUTUBE_FOLDER)
return dict(mylist=mylist, full_path=full_path)
Next I look through that array to find what file has been selected.
<select name=list id="videolist" method="GET" action="/">
{% for mylist in mylist %}
<option value= "{{mylist}}" SELECTED>{{mylist}}</option>"
{% endfor %}
</select>
Next I use JS to get the specific value into a variable
$('#videolist').change(function () {
//console.log($("#videolist").val());
var fileInput = $("#videolist").val())};
So The problem is here, I'm not sure how I would go about passing that value into the following jinja code
<video id="videotesting1" class="video" width="300" height="240" autoplay loop controls="true">
<source src="{{url_for('static',filename='videoTest/' + 'testVid.mp4')}}" type="video/mp4">
</video >
I'm trying to replace 'testVid.mp4' with the variable fileInput from the JS, I tried using $("#videotesting1").attr("src","{{url_for('static',filename='videoTest/'" + fileInput +")}}");'
But no luck so far.
This is different to "How do you change video src using jQuery?" because I am trying to pass a jinja variable to HTML using js.
You have some wrong closed quotes. Take a look at filename, where you set 'videoTest/' plus some variable value (e.g x), which results in 'videoTest/'x. Do you notice it? The single quote closed after videoTest should appear after the variable fileInput. The correct way would be:
$("#videotesting1").attr("src","{{url_for('static',filename='videoTest/" + fileInput + "')}}");
When you modify the src, has by inspect element the src changed, but the desired video isn't being played? If so, try:
$("#videotesting1").load()
Take a look at what load does # JQuery docs.
Figure out the problem, the file name has to go outside the jinja code because it doesnt get rendered by jinja for some reason when the event happens.
$("#videotesting1").attr("src","{{url_for('static',filename='videoTest/')}}" + fileInput);

Extending Jinja's {% trans %} to use JavaScript variables

I'd like to extend the behaviour of trans by rendering variables not as as values from the context, but instead as html (without using the context). My aim is to be able to populate those variables on the client through JavaScript.
Jinja as it seems doesn't allow for a great deal of customisation of this kind or I'm just unable to find the right hooks.
Here's what I'd like to achieve:
{% etrans name=username %}
My name is {{ name }}
{% endetrans %}
This should render to:
My name is <span id='#username'></span>
Of course, I could just use the normal {% trans %} directive and pass my html code to template.render(html_code_params), but that would require to have them defined in the template and the rendering code which I'd like to avoid.
Here's what I got so far (not much) which allows for a new etrans tag and the ability to use whatever goodies InternationalizationExtension has to offer.
from jinja2.ext import InternationalizationExtension
from jinja2.runtime import concat
class JavaScriptVariableExtension(InternationalizationExtension):
tagname = 'etrans'
tags = set([tagname])
def _parse_block(self, parser, allow_pluralize):
"""Parse until the next block tag with a given name.
Copy from InternationalizationExtension, as this uses hardcoded
`name:endtrans` instead of relying on tag name
"""
referenced = []
buf = []
while 1:
if parser.stream.current.type == 'data':
buf.append(parser.stream.current.value.replace('%', '%%'))
next(parser.stream)
elif parser.stream.current.type == 'variable_begin':
next(parser.stream)
name = parser.stream.expect('name').value
referenced.append(name)
buf.append('%%(%s)s' % name)
parser.stream.expect('variable_end')
elif parser.stream.current.type == 'block_begin':
next(parser.stream)
# can't use hardcoded "endtrans"
# if parser.stream.current.test('name:endtrans'):
if parser.stream.current.test('name:end%s' % self.tagname):
break
elif parser.stream.current.test('name:pluralize'):
if allow_pluralize:
break
parser.fail('a translatable section can have only one '
'pluralize section')
parser.fail('control structures in translatable sections are '
'not allowed')
elif parser.stream.eos:
parser.fail('unclosed translation block')
else:
assert False, 'internal parser error'
return referenced, concat(buf)
i18n_extended = JavaScriptVariableExtension
I don't mind overloading more methods (although the reason for above one should perhaps fixed upstream).
Stepping through the code is quite an interesting adventure. However, I hit a snag and am interested if anyone can give some advice.
The problem I see is that during the compilation, the function context.resolve() gets baked into the compiled code. jinja2.jinja2.compiler.CodeGenerator doesn't really allow any different handling here (correct me if I'm wrong). Ideally, I would define another node (for the variable) and this node would handle the way it's dealt with during compilation, but I don't see how this is possible. I might be too focussed on this as a solution, so perhaps someone can provide alternatives.
As suggested by #Garrett's comment, a much easier solution is to pass in a function to the template renderer that interpolates the variables. In my case, my target client-side framework is Angular, but this also works for any JS variables that you want to use within a {% trans %} environment. Here are the building blocks:
def text_to_javascript(string):
# modify as needed...
return "<span>{{ %s }}</span>" % string
def render():
tmpl = jinja_env.get_template(template_filename)
return tmpl.render({'js': text_to_javascript})
And this how I make use of it in the template file:
{% trans username=js('user.name') %}
My name is {{ username }}
{% endtrans %}
In the Angular controller, the variable user is bound to the $scope like so:
$scope.user = {'name': 'Bugs Bunny'}

Categories