django html: copy form input data and display in another page - html

I am trying to develop a delivery service web where users can input pickup and delivery address in the form and get the price online. if the price is fine, the user can click "place order" button which will navigate into another new page for user to fill in additional information, and importantly the previously input piackup and delivery addresses and the price will need to automatically shown somewhere in the new page.
I am new to django and html, and I have tried to created a simpler page serving the same purpose. Now I could do the first part of form filling, and the backend calculate based on the user input and return the calculation result (e.g. price). Now, I am wondering how to do the "navigation to another new page which will display the two input values and calculation result"
Main html:
<html>
<body>
<form method="POST" hx-post="{% url 'blog:post_list' %}" hx-target="#num_1" hx-target="#num_2" hx-target="#result">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="" placeholder="Enter value" />
</div>
<br />
<div id="num_1">{{ num_1 }}</div>
<br />
<div id="num_2">{{ num_2 }}</div>
<br />
<div id="result">{{ result }}</div>
<br>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/htmx.org#1.6.1"></script>
</body>
</html>
Child html:
<div>
<label>first_number:</label>
<span id="num_1"> {{ num_1 }} </span>
</div>
<div>
<label>second_number:</label>
<span id="num_2"> {{ num_2 }} </span>
</div>
<div>
<label>calculation_result:</label>
<span id="result"> {{ result }} </span>
</div>
view.py:
def post_list(request):
result = ""
num1 = ""
num2 = ""
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
if request.headers.get('Hx-Request') == 'true':
# return only the result to be replaced
# return HttpResponse(str(result))
return render(request, 'blog/post_list_snippet.html', {'num_1': num1,'num_2': num2,'result': result})
else:
return render(request, 'blog/post_list.html', {'num_1': num1,'num_2': num2,'result': result})

Related

HTML form with post method sent get request

I had a form which used post method. However, after I clicked sumbmit, only get request was sent. Can I please know why?
<form action="/review_page/{{yelp_id}}" method=post>
<label for="review-score">Your overall rating of this restaurant</label>
<select name="score" id="review-score">
{% for num in range(1,6) %}
<option value="{{ num }}">{{ num }}</option>
{% endfor %}
</select>
<div>
<label for="review-title">Title of your review</label><br>
<input type="text" name="title" id="review-title">
</div>
<div>
<label for="reviewText">Your review</label>
<div>
<textarea name="review" id="reviewText" data-minlen="100" data-maxlen="20000"
placeholder="Tell people about your experience"></textarea>
</div>
</div>
<input type="submit" value="Submit Your Review">
</form>
Please also find my routes below.
#app.route("/review_page/<yelp_id>", methods=["POST"])
def save_user_review(yelp_id):
"""Save user review into database"""
user_id = session.get("user_id")
print(user_id)
if user_id is None:
flash("Please log in to leave a review")
return redirect(f"/review_page/{yelp_id}")
else:
user = User.query.get(session["user_id"])
title = request.form.get("title")
score = int(request.form.get("score"))
review = request.form.get("review")
yelp_id = yelp_id
rating = crud.create_rating_without_pic(user, title, score, review, yelp_id)
db.session.add(rating)
db.session.commit()
return redirect(f"/rest_details/{yelp_id}")
Maybe is it.
You have this
<form action="/review_page/{{yelp_id}}" method=post>
And probably you should have this
<form action="/review_page/{{yelp_id}}" method="post">

Online waiting: django submit form and display result in same page

I have an emergent task to make a web page which allow user to input some data and the backend do some calculation and the result needs to be displayed in the same page just below the input field (like air ticket online price check).
I am new to django and html. below is my first test web page of a simple online calculator to try to figure out how to make such web service.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching/trying for answers and solutions for several days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)
I would suggest taking a look at htmx.org which makes this really simple without having to write any actual JS.
For your example:
(1) You add the htmx JS (which is only about 10k) to your HTML, and use hx-post and hx-target to trigger the ajax calls on your form. With these the form will fire an AJAX request, and the hx-target tells htmx to take the response (which you want to be only the result of your calculation) and put it in the div without refreshing the whole page.
See docs for more details on this.
Note also I gave an id to the div containing the result.
You will need to replace hx-post="{% url 'blog:post_list' %}" with the correct name to your view (which we don't know as you didn't post your urls.py).
<html>
<body>
<form method="POST" hx-post="{% url 'blog:post_list' %}" hx-target="#result">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div id="result">{{ result }}</div>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/htmx.org#1.6.1"></script>
</body>
</html>
(2) In your view then you determine if the request is an AJAX request from htmx by checking the headers, in which case you want to only return the result. There are easier or elegant ways to do this (eg. check django-htmx, but just to keep it simple:
from django.http.response import HttpResponse
from django.shortcuts import render
# Create your views here.
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
if request.headers.get('Hx-Request') == 'true':
# return only the result to be replaced
return HttpResponse(str(result))
else:
return render(request, 'blog/post_list.html', {'result': result})

django: html submit form and display result in smae page without jumping/rereshing into new page

I am new to django and html. below is my first test web page of a simple online calculator.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching for answers for 5 days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)

Fetch preventing rendering template in the controller

I'm working on a project for a class and I have starter code that I am editing. they way its supposed to work is that when the user creates a venue it goes to the home page with a message saying venue x has been listed. Once I add the post request in the new_venue.html it does nothing after I click the submit button nothing happens, but I know its doing something because the app.py prints the name that signed up.
Below is Code from the new_venue.html.
I added the script section and the post request
{% extends 'layouts/main.html' %}
{% block title %}New Venue{% endblock %}
{% block content %}
<div class="form-wrapper">
<form id="venueInfo" method="post" class="form">
<h3 class="form-heading">List a new venue <i class="fa fa-home pull-right"></i></h3>
<div class="form-group">
<label for="name">Name</label>
{{ form.name(id='name', class_ = 'form-control', autofocus = true) }}
</div>
<div class="form-group">
<label>City & State</label>
<div class="form-inline">
<div id='city' class="form-group">
{{ form.city(class_ = 'form-control', placeholder='City', autofocus = true) }}
</div>
<div id='state' class="form-group">
{{ form.state(class_ = 'form-control', placeholder='State', autofocus = true) }}
</div>
</div>
</div>
<div id='address' class="form-group">
<label for="address">Address</label>
{{ form.address(class_ = 'form-control', autofocus = true) }}
</div>
<div id='phone_num' class="form-group">
<label for="phone">Phone</label>
{{ form.phone(class_ = 'form-control', placeholder='xxx-xxx-xxxx', autofocus = true) }}
</div>
<div id="genres" class="form-group">
<label for="genres">Genres</label>
<small>Ctrl+Click to select multiple</small>
{{ form.genres(class_ = 'form-control', autofocus = true) }}
</div>
<div id="fb_link" class="form-group">
<label for="genres">Facebook Link</label>
{{ form.facebook_link(class_ = 'form-control', placeholder='http://', autofocus = true) }}
</div>
<input type="submit" value="Create Venue" class="btn btn-primary btn-lg btn-block">
</form>
<script type="text/javascript">
document.getElementById("venueInfo").onsubmit=function(e){
e.preventDefault();
fetch('/venues/create',{
method:'POST',
body:JSON.stringify({
'name': document.getElementById('name').value,
'city': document.getElementById('city').value,
'state': document.getElementById('state').value,
'address': document.getElementById('address').value,
'phone_num': document.getElementById('phone_num').value,
'genres': document.getElementById('genres').value,
'fb_link': document.getElementById('fb_link').value,
}),
headers: {'Content-type': 'application/json'}
})
.then(function(){
})
}
</script>
</div>
{% endblock %}
below is the code from app.py
#app.route('/venues/create', methods=['GET'])
def create_venue_form():
form = VenueForm()
return render_template('forms/new_venue.html', form=form)
#app.route('/venues/create', methods=['POST'])
def create_venue_submission():
name = request.get_json()['name']
print(name)
flash('Venue ' + request.form['name'] + ' was successfully listed!')
return render_template('pages/home.html')
flash messages work with redirection, refer to https://flask.palletsprojects.com/en/1.1.x/patterns/flashing/#simple-flashing
so instead rendering the template, return redirection object to the home page:
#app.route('/venues/create', methods=['POST'])
def create_venue_submission():
# name = request.get_json()['name']
name = request.values.get('name')
print(name)
flash('Venue ' + request.form['name'] + ' was successfully listed!')
# return render_template('pages/home.html')
return redirect(url_for('home')) # -- HERE --
Update
i think you are doing things the wrong way, you don't need the javascript to submit the form data via ajax post since ajax is used to update the page without reloading it (btw you didn't put any logic in .then(function(){}) callback to show up the message), but after submitting the form you want to redirect the user to the home page with a flash message so the ajax approach you are using is the wrong approach, just remove or comment the javascript code block and add the action to the form
<form id="venueInfo" method="post" action="{{ url_for('create_venue_submission') }}" class="form">
...
and in your function create_venue_submission() you should change
name = request.get_json()['name']
to
name = request.values.get('name')
# other fields
name = request.values.get('name')
city = request.values.get('city')
state = request.values.get('state')
address = request.values.get('address')
phone_num = request.values.get('phone_num')
genres = request.values.get('genres')
fb_link = request.values.get('fb_link')
see this wiki https://stackoverflow.com/a/16664376/12368419
If you are submitting your form via ajax, you will need to redirect in the success portion of the ajax call. Also, keep in mind that flash will not work via ajax. You will need to use the standard form post.
$.ajax({
'url': 'post_url',
success: function(msg){
//read the msg here and determine if success or not then redirect
}
})
This will not work when doing an ajax form post:
return redirect(url_for('index'))
If you use the standard (pseudo code) without posting via ajax, it will redirect:
<form method=post action=route>
<input type=submit>
</form>

Passing variable through response object in Flask framework

I need to pass a variable along with response object while complete signup process and display the success message on the same page. I tried so many ways but I couldn't find any idea how to do that. Please look at this scenario and help me out.
#app.route('/signup', methods=['POST', 'GET'])
def signup():
message = ''
email = ''
password = ''
resp = app.make_response(render_template('signup.html'))
if request.method == 'POST':
import datetime
email = request.form['emailInput']
password = request.form['pswdInput']
if len(password) < 3:
message = Markup("<p style='color:red;'> Password Length Should Be More Than 3 Character </p> ")
return render_template('signup.html', message = message)
expire_date = datetime.datetime.now()
expire_date = expire_date + datetime.timedelta(hours=1)
resp.set_cookie('userEmail', email, expires=expire_date)
resp.set_cookie('userPassword', password, expires=expire_date)
message = Markup("<h1> Registration successfull! </h1>")
resp.headers.set('message', message)
return resp
return render_template('signup.html', message = message)
HTML :
<div class="container">
Home
<form id="signup" method="POST" action="{{url_for('signup')}}">
<div class="header">
<h3>Sign Up</h3>
<p>You want to fill out this form</p>
</div>
<div class="sep"></div>
<div class="">
<input type="email" name="emailInput" placeholder="e-mail" autofocus />
<input type="password" name="pswdInput" placeholder="Password" />
<div class="">
<input name="joinCheck" name="joinCheck" value="1" type="checkbox" /><label class="terms">I accept the terms of use</label>
</div>
<input type="submit" id="submitBtn" value="Submit">SIGN UP FOR INVITE NOW</a>
</div>
<div>
{{message}}
</div>
</form>
</div>
resp = app.make_response(render_template('signup.html'))
This is missing your message keyword. Change it to:
resp = app.make_response(render_template('signup.html', message=message))
You need to move this code down also, because to it, it sees the message variable directly above as the empty string and assigns that to its keyword. I would place it right above your resp.set_cookie() code.
Finally, move this:
message = Markup("<h1> Registration successfull! </h1>")
Above the app.make_response() code you just moved. Your message variable needs to be set before the response code is initialized.
Just a small tip: I would change message = " " to message = None. Otherwise, in the compiled HTML, it just looks like there's an empty div. This won't be too detrimental in this small case, but I'd definitely make it a rule of thumb in future, larger projects. Then, in your HTML:
{% if message %}
<div>
{{message}}
</div>
{% endif %}
Cheers.