HTML, Python, beginner. Trying to reference a variable from the post function - python

If the post function finds an error, I want it to communicate with the Get function so I can add the error to the main page.
How can this be done without templates?
Here is the code and also here is the solution video to the problem:
https://classroom.udacity.com/courses/cs253/lessons/48756009/concepts/485326480923#
import re
import cgi
import webapp2
# html boilerplate for the top of every page
page_header = """
<!DOCTYPE html>
<html>
<head>
<title>User-Signup</title>
</head>
<body>
<h1>Signup</h1>
"""
# html boilerplate for the bottom of every page
page_footer = """
</body>
</html>
"""
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
return username and USER_RE.match(username)
PASS_RE = re.compile(r'^[\S]+#[\S]+\.[\S]+$')
def valid_password(password):
return password and PASS_RE.match(password)
EMAIL_RE = re.compile(r'^[\S]+#[\S]+\.[\S]+$')
def valid_email(email):
return not email or EMAIL_RE.match(email)
class MainHandler(webapp2.RequestHandler):
def get(self):
add_username = """
<form action="/" method="post">
<label>
Username <input type="text" name="user_name" value = ""/>
</label>
</form>
"""
add_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = ""/>
</label>
</form>
"""
validate_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = ""/>
</label>
</form>
"""
# error = self.request.get("error")
# if error:
# error_esc = cgi.escape(error, quote=True)
# error_element = '<p class="error">' + error_esc + '</p>'
# else:
error_element = ''
password_error = ''
content = page_header + add_username + error_element + add_password + password_error + page_footer
self.response.write(content)
def post(self):
error_element = ''
have_error = False
user_name = self.request.get("user_name")
password = self.request.get("password")
params = dict("")
if not valid_username(user_name):
error_element = "thats not a valid username"
have_error = True
if not valid_password(password):
password_error = "thats not a valid password"
have_error = True
add_username = """
<form method="post">
<label>
Username <input type="text" name="user_name" value = "{0}"/>
</label>
</form>
""".format(user_name)
add_password = """
<form method="post">
<label>
Password <input type="password" name ="password" value = "{0}"/>
</label>
</form>
""".format(password)
validate_password = """
<form action="/" method="post">
<label>
Password <input type="password" name ="password" value = "{0}"/>
</label>
</form>
""".format(password_error)
content = page_header + add_username + error_element + add_password + password_error + page_footer
self.response.write(content)
Basically I need to be able to reference a variable from the Post function in the Get function. I am not allowed to use templates.
What I have tried:
I tried using a redirect with an error.. However this doesnt seem to be the way its done in the video.
Please help me.

That video you linked is behind a login page, but it sounds like you want to redirect to the url for MainHandler.get(), and encode the error or error code as a request parameter on the url. That would look like this:
# in your post():
def post(self):
# your code here...
if have_error:
self.redirect(url + '?error=Your_Error_Here')
else:
self.response.write(content)
# in your get():
def get(self):
error = self.request.get('error', None)
if error is not None:
# handle your error here
else:
# no error to handle
You normally have two options when you want an http POST handler to forward information to an http GET handler:
As shown above, redirect to the appropriate url with the information encoded on the url (that is the ?error=Your_Error_Here part). I have often seen that used for error alerts and also confirmation messages if a form is posted successfully (think green checkmark on the screen after you hit "save")
Instead of sending the response from the post handler, you could actually call the get() handler from the post handler and respond with whatever response object comes out of that. In general, I would not recommend that.

Related

Button to save data from a result to a data table; user token required error

I'm trying to add a button that takes data from a search results page and adds it to a data table. For example the first search result displays properly and I want the Favorites Button to save the data for the logged in user.
I keep getting the "message": "Token is Missing!" from the helper.py.
Fairly new to all this so I know I'm not using the best methods but at this point would just like to get this to work somewhat.
I'm guessing this is due to the #token_required. But I'm not sure how to fix this.
This is the route.
#api.route('/movies', methods = ['POST'])
#token_required
def save_movie(current_user_token):
title = request.json['title']
tmdb_id = request.json['tmdb_id']
user_token = current_user_token.token
print(f"User Token: {current_user_token.token}")
movie = SaveMovie(title, tmdb_id, user_token=user_token)
db.session.add(movie)
db.session.commit()
response = movie_schema.dump(movie)
return jsonify(response)
and this is the form I'm using
<form action="/api/movies" method="POST">
<input type="hidden" name="title" value="{{ results.0.title }}"/>
<input type="hidden" name="tmdb_id" value="{{ results.0.id }}"/>
<input type="hidden" name="x-access-token" value="Bearer {{ current_user.token }}"/>
<button name ="submit" class="btn btn-primary" type="submit">Favorite</button>
</form>
This is the Model
class Movie:
"""
Movie class to define Movie Objects
"""
def __init__(self,id,title,overview,poster):
self.id = id
self.title = title
self.overview = overview
self.poster = f"https://image.tmdb.org/t/p/w500/{poster}"
And these are the functions
def search_movie(query):
data = requests.get(f"{BASEURL}/search/movie?api_key={API_KEY}&language=en-US&query={query}&page=1&include_adult=false").json()
if data['results']:
search_data = process_results(data['results'])
return search_data
def process_results(movie_list):
movie_results = []
for movie_item in movie_list:
id = movie_item.get('id')
title = movie_item.get('original_title')
overview = movie_item.get('overview')
poster = movie_item.get('poster_path')
if poster:
movie_object = Movie(id, title, overview, poster)
movie_results.append(movie_object)
return movie_results
I've attempted to add the token in the form to see if that would help but that didn't work and I'm not sure if maybe I need a #login-required for the search results but that would not be ideal. Would creating another function as a go between fix this?

Flask Error Not Found URL On server custom Form System

Hey im making a program in flask that lets users fill out a form and then it will email that form to a specific email. It was working perfectly fine before but for some reason now it is not. Here is my code:
#app.route('/application', methods=['POST', 'GET'])
def application():
if request.method == 'POST':
name = request.form["name"]
github = request.form["github"]
age = request.form["age"]
location = request.form["location"]
email = request.form["email"]
discord = request.form["discord"]
return redirect(f"/final/{name}/{github}/{age}/{location}/{email}/{discord}/")
#app.route('/final/<name>/<github>/<age>/<location>/<email>/<discord>/', methods=['GET','POST'])
def final(name, github, age, location, email, discord):
mail= Mail(app)
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'prodatacollectors#gmail.com'
app.config['MAIL_PASSWORD'] = '*******'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
b = Markup(f"Name: {name}\r\nGithub: {github}\r\nAge: {age}\r\nlocation: {location}\r\nemail: {email}\r\ndiscord: {discord}")
msg = Message(f'Application {name}', sender = 'prodatacollectors#gmail.com', recipients = [email])
msg.body = b
mail.send(msg)
return render_template("final.html" )
HTML TEMPLATE
<form action="/application" method="POST">
<p><input type = "text" name="name" placeholder="First And Last Name" /></p>
<br><br>
<p><input type = "text" name="github" placeholder="GitHub Profile Link" /></p>
<br><br>
<p><input type = "text" name="age" placeholder="Age" /></p>
<br><br>
<p><input type = "text" name="location" placeholder="State/Country" /></p>
<br><br>
<p><input type = "text" name="email" placeholder="Email" /></p>
<br><br>
<p><input type = "text" name="discord" placeholder="Discord username and tag(if you have one)" /></p>
<p><input type="submit" value="Submit" /></p>
</form>
I get no errors all it says is that the the requested url wasnt found on the server
So i found an answer. So flask doesnt allow specifc links such as https://github.com/codingdudepy to be returned as a redirect url. Nor does it allow things like #, or domains like .com for some reason. When i removed these things it worked perfectly.

Why is my form trying to submit to the wrong endpoint?

I have a python script and a mongoDB instance.
With flask I now want to list all the items of my database on a webpage and use a second webpage to trigger the script to add an other item.
But everytime I click "submit" on the "/add" page, I get a "Method not allowed" and I can see, that it tries to submit it to "/" instead of "/add" ..
script.py
from flask import Flask, render_template, request
import requests, json, sys, getopt, smtplib
from os import system, name
from pathlib import Path
from pymongo import MongoClient
client = MongoClient(port = 27017)
db = client.amazonProducts
allitems = []
allMyItems = []
for document in db.items.find():
allitems.append(document["name"])
def addItem():
for dbWishList in db.wishlist.find():
url = dbWishList["wishlist"]
items = json.loads(requests.get(url).text)
if items:
for item in items:
itemName = str(item["name"])
itemPrice = item["new-price"]
itemUrl = str(item['link'])
if itemPrice:
itemPrice = str(itemPrice[26: ])
itemPrice = str(itemPrice[: itemPrice.find("<")])
itemPriceF = str(itemPrice.replace(".", ""))
itemPriceF = str(itemPriceF.replace("€", ""))
itemPriceF = str(itemPriceF.replace("\xa0", ""))
itemPriceF = str(itemPriceF.replace(",", ".")).replace("\xf6", "")
itemPriceFi = float(itemPriceF)
itemUrl = itemUrl[: itemUrl.find("?coliid")]
itemNameF = itemName.replace('"', '"')
itemNameFi = itemNameF.replace("&amp;", "&")
itemNameFi = itemNameFi.replace("ü", "ue").replace("ö", "oe").replace("ä", "ae").replace(" ", " ").replace("–", "-")
amazonItem = {
'name': itemNameFi,
'url': itemUrl,
'price': itemPriceFi,
'maxPrice': 0
}
db.items.insert_one(amazonItem)
for document in db.items.find():
allMyItems.append(document["name"])
return allMyItems
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template("index.html", len = len(allitems), allitems = allitems)
app.run(use_reloader = True, debug = True)
app.config["DEBUG"] = True
#app.route("/add", methods = ["GET", "POST"])
def secPage():
errors = ""
if request.method == "POST":
global testingVar
testingVar = None
try:
testingVar = string(request.form["testingVar"])
except:
errors += "<p>{!r} is not a string.</p>\n".format(request.form["testingVar"])
if testingVar is not None:
addItem()
return render_template("secIndex.html", len = len(allMyItems), allMyItems = allMyItems)
return '''
<html>
<body>
{errors}
<p>What you wanna do?:</p>
<form method="post" action=".">
<p><input name="testingVar" /></p>
<p><input type="submit" value="Do magic" /></p>
</form>
</body>
</html>
'''.format(errors=errors)
index.html
<!DOCTYPE html>
<html>
<head>
<title>For loop in Flask</title>
</head>
<body>
<ul>
<!-- For loop logic of jinja template -->
{%for i in range(0, len)%}
<li>{{allitems[i]}}</li>
{%endfor%}
</ul>
</body>
</html>
secIndex.html
<!DOCTYPE html>
<html>
<head>
<title>For loop in Flask</title>
</head>
<body>
<!-- For loop logic of jinja template -->
<form method="post" action=".">
<p><input name="testingVar" /></p>
<p><input type="submit" value="Do magic" /></p>
</form>
</body>
</html>
The items are built like:
amazonItem = {
'name': itemNameFi,
'url': itemUrl,
'price': itemPriceFi,
'maxPrice': 0
}
Can anyone here follow me and tell me where my mistake might be?
In your form definition you have:
<form method="post" action=".">
The action attribute needs to have the endpoint you want to send the post request to. In your case, you want
<form method="post" action="/add">
If you omit the action attribute, it will submit the post request to the current page, so if you are viewing your form from /add, you can just use
<form method="post">

Django CSRF verification failed even after adding csrf_token tag inside the form html

I'm working on a project using Python(2.7) and Django(1.10) in which I need submit the login form but it returns an error on submission.
Note: I have searched a lot of questions tried various answers but in
most cases the {% csrf_token %} is missing from the <form> HTML
but in my case, I'm using this also, that's why don't mark this
question duplicated, please!
Here's what I have tried:
from form.html:
<form class="fields-signup" action="{% url 'mainlogin' %}" method="post">
{% csrf_token %}
<h1 class="text-center">Sign In</h1>
<div class="form-group">
<input class="user-name form-control" type="text" name="username" placeholder="User name">
</div>
<div class="form-group">
<input class="password form-control" type="password" placeholder="Password" name="password">
</div>
<input type="submit" class="btn siteBtn" value="Sign In">
<!-- <a href="#" class="btn siteBtn" >Sign Up</a>
<p class="text-center">Don’t Have an account? Signup</p> -->
<!--popup-forget-password-->
<div class="col-sm-12">
<button type='button' class="forget-password-btn" data-toggle="modal" data-target="#popUpWindow">Forgot Password</button>
<!--forget-password-end-->
<div class="col-sm-12 register">
<a class="register-driver-btn" data-toggle="modal" data-target="#popUpWindow_register">Register Driver?</a>
</div>
</div>
</form>
from urls.py:
url(r'^$', views.home, name="home"),
from views.py:
if request.method == "GET":
try:
temp = get_template('login.html')
result = temp.render(Context({'context': RequestContext(request)}))
return HttpResponse(result)
more from views.py:
if request.method == "POST":
username = request.POST['username']
# email = request.POST['email']
password = request.POST['password']
try:
#obj = User_table.objects.get(user_name=username, emailid=email)
obj = User_table.objects.get(user_name=username)
if obj:
print('got user obj')
verify_password = ''
try:
verify_password = handler.verify(password, obj.password)
except Exception as e:
print(e)
if verify_password is True:
request.session['user_id'] = obj.id
request.session['user_type'] = obj.user_type
user_name = obj.first_name + ' ' + obj.last_name
request.session['user_name'] = user_name
if not obj.approval_status:
return HttpResponse('Your account is not confirmed by administration.')
obj.is_active = True
obj.login_try = 0
obj.save()
return redirect(home)
else:
try:
# obj = User_table.objects.get(user_name=username, emailid=email)
obj = User_table.objects.get(user_name=username)
if obj:
s = obj.login_try
s = s + 1
obj.login_try = int(s)
if int(obj.login_try) >= 3:
obj.login_try = 3
obj.save()
if int(obj.login_try) == 3:
id = obj.id
key = get_random_string(length=10)
reset_link = 'It seems you forgot password or someone is trying to login you account. This is your password reset link please do not share this with other ' + settings.EMAIL_URL + 'reset_password/' + str(
id) + ' key is : ' + str(key)
send_mail('Reset link', reset_link, settings.EMAIL_HOST_USER, [obj.emailid, ])
obj.password = str(key)
obj.save()
return HttpResponse(
'It seems you forgot password or someone is trying to login you account. Password Reset link has been sent to your email id')
except Exception as e:
print(e)
pass
return redirect(mainlogin)
except Exception as e:
print('error is : ', e)
return HttpResponse('An error has occurred.')
Also, I have included the csrf middleware in my settings.py.
what can be wrong here?
Thanks in advance!
Your problem is here:
if request.method == "GET":
try:
temp = get_template('login.html')
result = temp.render(Context({'context': RequestContext(request)}))
return HttpResponse(result)
Docs about CSRF
In the corresponding view functions, ensure that RequestContext is
used to render the response so that {% csrf_token %} will work
properly. If you’re using the render() function, generic views, or
contrib apps, you are covered already since these all use
RequestContext.
I'm not exactly sure why it's happening, maybe something wrong with context processors configuration, one of them adds csrf_token to context dictionary.
For more debugging see RequestContext section. But using builtin render() function will solve your problem as it'll handle context for you.
from django.shortcuts import render
if request.method == "GET":
...
return render(request, 'login.html')

How do I pass url parameter to form value?

The form has this hidden field
<input type="hidden" name="dir_type" value="tshirt">
url parameters are
/dir?type=tshirt
/dir?type=books
/dir?type=posters
and so on.
Now I hard coded value="tshirts" but how do I get parameter for the relevant page?
I found several pages like this dealing with similar topics but I did not understand how this is done.
Thanks for your help.
UPDATE
The answer by systempuntoout works perfectly but I decided to solve the problem without using templates. And for anyone who has a similar question, passing the url parameter to the form like this works well:
<form name="submit_form" action="/directorysubmithandler" method="post" onSubmit="return validate_form()">
title: <input type="text" name="title" size=50><br />
url: <input type="text" name="url" size=50><br />
<input type="hidden" name="dir_type" value="%s")>
<input type="submit" value="submit">
</form>""" % self.request.get("type"))
a. pass the type value to the view:
class Directory(webapp.RequestHandler):
def get(self):
....
merchandise_type = self.request.get("type", "")
items = Item.all()
items.filter("type =", merchandise_type)
path = os.path.join(os.path.dirname(__file__), 'dir_details.html')
self.response.out.write(template.render(path,{'type':merchandise_type}))
b. add the type value to the hidden field:
<input type="hidden" name="dir_type" value="{{ type }}">
c. get the dir_type value in your post handler:
class DirectorySubmitHandler(webapp.RequestHandler):
def post(self):
user = users.get_current_user()
merchandise_type = self.request.get("dir_type", "")
dir_type = merchandise_type
if user:
item = Item()
item.title = self.request.get("title")
item.url = self.request.get("url")
item.type = self.request.get("dir_type")
item.user_who_liked_this_item = user
item.put()
self.redirect("/dir?type=%s" %
self.request.get("dir_type"))
else:
self.redirect(users.create_login_url(self.request.uri))

Categories

Resources