Best way to redirect to referring page - python

I have a question similar to my previous question.
In the same app I have the VoteHandler that adds +1 when users click on the up arrow and then redirects to the same page.
Now that I added the url parameters to the pages and urls look like this
/dir?type=tshirt
I need to be able to redirect to the correct page.
And as mentioned here by Nick Johnson referrer is not a good way of redirecting.
I would appreciate help about how to fix VoteHandler so that it redirects to the correct page.
Thanks!
class VoteHandler(webapp.RequestHandler):
def get(self, id):
id = int(id)
item = Item.get_by_id(id)
user = users.get_current_user()
if user:
greeting = ("%s (<a href='%s'>sign out</a>)" %
(user.nickname(), users.create_logout_url(self.request.uri)))
#--check if user voted on this item before--#
query = SiteUser.all()
query.filter("liked_items =", (str(item.key().id())))
already_voted = query.get()
if already_voted:
self.redirect("/onevote")
else:
query = SiteUser.all()
query.filter("site_user =", users.get_current_user())
data = query.get()
data.total_votes += 1
data.liked_items = str(item.key().id())
data.site_user = users.get_current_user()
db.put(data)
item.points += 1
item.put()
if self.request.referrer == 'http://localhost:8083//newest':
self.redirect('/newest')
elif self.request.referrer == 'http://localhost:8083/hot':
self.redirect('/hot')
#How do I fix this line to get the correct url parameter?
elif self.request.referrer == 'http://localhost:8083/dir?type=tshirt':
self.redirect('/dir/tshirt')
else:
self.redirect("/")
else:
greeting = ("<a href='%s'>Sign in with your Google account or register</a>." %
cgi.escape(users.create_login_url(self.request.uri)))
UPDATE
The answer by systempuntoout works great but I had to change the vote link in Directory from
/vote/%s
to
/vote/%s?type=%s
so that I could get the merchandise_type in VoteHandler:
self.response.out.write("<ol>")
for item in items:
self.response.out.write("""<li>
^ %s <span id='Small'>(%s)</span><br />
<div id='Small'>
%s points %s by %s |
</div>
</li><br /> """ %
(str(item.key().id()), merchandise_type, item.url, item.title, urlparse(item.url).netloc,
item.points, item.date.strftime("%B %d, %Y %I:%M%p"), item.user_who_liked_this_item, str(item.key().id()), str(item.key().id())))
self.response.out.write("</ol>")

I would use the type parameter in this way:
class VoteHandler(webapp.RequestHandler):
def get(self, id):
id = int(id)
item = Item.get_by_id(id)
merchandise_type = self.request.get("type", "")
..
self.redirect('/%s' % merchandise_type)

Related

How to post query data from a python file to a flask endroute?

I am trying to post some query data that does some simple calculations based off of the users responses to the flashcard questions. I have those queries written in a stats.py file, and I want to retrieve them in the front end of my react.js application. My plan was to post the data to a flask end route and then use axios to get it in the front end. I have easily managed to post the users response data from the front end (react.js) to the flask end route with out any problems. The problem Im running into now is I don't know how to "trigger" the post request. When accessing the endpoint url in a browser, it performs a get request. When posting the user response data, the post request was triggered by whichever answer they clicked on or whenever they clicked submit. I found that part pretty easy to do in react.js but I'm not sure how to do it in python.
here is what my stats.py file looks like, this is where I want to post the query data from:
from typing import Any
from main import Db
import requests
import json
d = Db()
api_url = 'http://127.0.0.1:5000/stats'
def get_total_percent_correct(user_id):
correct = d.db_query('SELECT COUNT(*) FROM cards.responses WHERE guess = answer AND user_id = \'%s\'' % user_id)
total = d.db_query('SELECT COUNT(*) FROM cards.responses WHERE user = \'%s\'' % user_id)
return float(correct/total)
def get_percent_correct_for_flashcard(user_id,flashcard_id):
total = d.db_query('SELECT COUNT(*) FROM cards.responses WHERE user = \'%s\' AND WHERE flashcard_id = \'%s\'' % (user_id, flashcard_id))
correct = d.db_query('SELECT COUNT(*) FROM cards.cards WHERE flashcard_id = \'%s\' AND WHERE guess = answer AND WHERE user_id = \'%s\'' % (flashcard_id, user_id))
return float(correct/total)
def get_stats_for_flashcard(user_id, flashcard_id):
attempts = d.db_query('SELECT COUNT(*) FROM cards.responses WHERE user = \'%s\' AND WHERE flashcard_id = \'%s\'' % (user_id, flashcard_id))
correct = d.db_query('SELECT COUNT(*) FROM cards.cards WHERE flashcard_id = \'%s\' AND WHERE guess = answer AND WHERE user_id = \'%s\'' % (flashcard_id, user_id))
missed = attempts - correct
return (attempts, correct, missed)
def get_most_missed_flashcard(user_id):
questions = d.db_query('SELECT DISTINCT(flashcard_id) FROM cards.responses WHERE user = \'%s\'' % user_id)
holder = []
for i in questions:
holder.append(get_percent_correct_for_flashcard(user_id, i))
return min(holder)
create_row_data = {'accuracy': get_total_percent_correct}
print(create_row_data)
r = requests.post(url=api_url, json=create_row_data)
print(r.status_code, r.reason, r.text)
and here is some code from my "main.py" file which contains the end route where I want to post the data to:
#app.route('/stats', methods=['GET', 'POST', 'OPTIONS'])
def request_data_stats():
if request.method == 'GET':
return make_response('Get Request')
if request.method == 'POST':
data = request.get_json()
userstats = data['accuracy']
print(userstats)
return userstats
I appreciate any help! thanks for your time!

unable to edit mongodb document in flask

I'm working on a project using flask and pymongo where I have a movies collection and an instance of my movies collection is like :
movie = {"title":"Hobbit" , "year":"2013"}
I have an html jinja 2 page where I submit a form and I can change the title or the year of the movie . It is not required to change both of them .
My html template :
<h1> Select a field in the movie to update </h1>
<form action = "{{url_for('execute_movie_update')}}" method = "post">
<label="update-title">Change the title</label>
<input type = "text" id="new-title" name = "new-title" >
<label="update-year"> Change year of publish </label>
<input type = "text" id = "new-year" name = "new-year">
<label="update-plot"> Change plot of movie </label>
<input type = "text" id = "new-plot" name = "new-plot">
<button type = "submit">Submit changes</button>
</form>
If I use my flask endpoint which I will include below to change both the title and the year of the movie I have in my session the update is succesful . However if I change only one field
(ex. if I change the title only the year I have is set to " " instead of being the orginal year )
I have my flask endpoint here . It updates a specific movie I have stored in a session :
#app.route('/executemovieupdate' , methods = ['GET', 'POST'])
def execute_movie_update():
if 'Email' in session and 'User' in session:
email = session['Email']
user = session['User']
if user == 'Admin':
if 'Movie' in session and 'Movie_year' in session and 'Movie_plot' in session:
movie = session['Movie']
year = session['Movie_year']
plot = session['Movie_plot']
tainia = movies.find_one({'title':movie , "year":year}) #the movie that I want to update
if request.method == 'POST':
new_title = request.form.get('new-title') #get the fields I submitted in html
new_year = request.form.get('new-year')
if new_title!=None: #if I submit only title year is set to " "
print("update the title")
movies.update_one({"title":movie , "year":year} , {"$set":{"title":new_title} } )
session['Movie'] = new_title
movie = session['Movie']
print(session)
if new_year != None: #if i submit both title and year the program works
print("update the year")
movies.update_one({"title":movie , "year":year} , {"$set": {"year":new_year}})
session['Movie_year']=new_year
year = session['Movie_year']
print(session)
return ''' movie has been updated '''
else:
return render_template('movie-update.html' , movie = tainia)
else:
return redirect(url_for('admin.html'))
else:
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
I would appreciate your help in guiding me to solve this issue . Thank you in advance.
EDIT: It seems that the problem lies in my if statements as I always enter both of them even if an item is not submitted (ex. I did not submit a title )
SOLVED :
by changing title if statement to : if new_title: and year statement to if new_year:

redirecting to a variable href from python

I'm writing a wiki for a Udacity assignment and want to create an "Edit" button in the navbar. Basically the functionality I'm looking for is when you hit Edit you are redirected to an edit page with the current content displayed in the edit box. When you save that page the content is updated on the original page.
I believe my problem is in the html which is as follows:
<body>
<div class="navbar">
{% if not user %}
Signup|Login
{% else %}
Edit|Logout
{% endif %}
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
The relevant python code is:
class WikiPage(Handler):
def get(self, wiki_url):
page = None
ver = self.request.get("v")
user = self.user
print("***** WikiPage(Handler) wiki_url = %s, ver = %r, user = %s" % (wiki_url, ver, user))
if ver:
ver = int(ver)
page = db.GqlQuery("SELECT * FROM Wiki WHERE url = :url AND version = :ver ORDER BY created DESC", url=wiki_url, ver=ver).get()
if not page:
self.redirect("%s" % wiki_url)
else:
page = db.GqlQuery("SELECT * FROM Wiki WHERE url = :url ORDER BY created DESC LIMIT 1", url = wiki_url).get()
print("*** No versions *** wiki_url=%s page = %r" % (wiki_url, page))
if not page:
self.redirect("/_edit%s" % wiki_url)
if page:
id = page.key().id()
thisPage = Wiki.get_by_id(int(id))
print("*** WikiPage(Handler) *** wiki_url = %s page = %r" % (wiki_url, page))
if user:
self.render('show_page.html', content=thisPage.content, url=wiki_url)
else:
self.redirect("/login")
What's happening now is I get redirected to /_edit/_edit regardless of which page I'm trying to edit.
Any suggestions would be greatly appreciated.
Adding the EditPage handler class:
class EditPage(Handler):
def render_editwiki(self, user="", title="", content="", error=""):
self.render("edit_page.html", user=user, title=title, content=content, error=error)
def get(self, wiki_url):
v = self.request.get('v')
user = self.user
if user:
if v:
v = int(v)
thisWiki = db.GqlQuery("SELECT * FROM Wiki WHERE url = :url AND version = :ver ORDER BY created DESC", url=wiki_rul, ver=v).get()
if not thisWiki:
self.redirect("/wiki/_edit%s" % wiki_url)
else:
thisWiki = db.GqlQuery("SELECT * FROM Wiki WHERE url = :url ORDER BY created DESC LIMIT 1", url=wiki_url).get()
if not thisWiki:
self.render_editwiki(user, wiki_url)
if thisWiki:
id = thisWiki.key().id()
w = Wiki.get_by_id(int(id))
self.render_editwiki(user, w.url, w.content)
else:
self.redirect("/wiki/signup")
def post(self, wiki_url):
content = self.request.get("content")
user = self.user
if user:
if content:
thisWiki = db.GqlQuery("SELECT * FROM Wiki where url = :url ORDER BY created DESC LIMIT 1", url=wiki_url).get()
if thisWiki:
id = thisWiki.key().id()
previous = Wiki.get_by_id(int(id))
current = previous.version + 1
w = Wiki(url=wiki_url, content=content, version=current)
w.put()
else:
w = Wiki(url=wiki_url, content=content,version=1)
w.put()
self.redirect('%s' % str(wiki_url))
else:
error = "No Content"
self.render("edit_page.html", content=content, error=error)
else:
self.redirect("/wiki/signup")
Have you already written a url case for the edit urls? It seems like you are being redirected to /_edit/_edit because wiki_url is /_edit. I'm guessing this is what's happening:
you visit a regular page (wiki_url = ?)
you click the edit url
you visit the edit url, but there is no page (wiki_url = '/_edit')
you are redirected to the edit url (of the edit page), which is /_edit/_edit.
Does this make sense?

Python PRAW Wrapper, Logic Problems

What I'm aiming to do is to get the top submission from Reddit, append it to an array and then get the second top submission, third, fourth, etc. I'm using place_holder to get the next submission, which works the first time but then just loops through getting the same, second, submission over and over again.
The current output is
Post 1
Post 2
Post 2
etc
When I want the output to be
Post 1
Post 2
Post 3
Post 4
etc
Here's my code:
import praw, time
r = praw.Reddit(user_agent='ADNPost')
already_done = []
while True:
for submission in r.get_top(limit=1):
id = submission.id
title = submission.title
url = submission.short_link
save_state = (id)
if id not in already_done:
already_done.append(submission.id)
post = title + " | " + url
print post
print save_state
if id in already_done:
for submission in r.get_front_page(limit=1, place_holder=submission.id):
id = submission.id
title = submission.title
url = submission.short_link
print title, url
save_state = (id)
already_done.append(submission.id)
time.sleep(2)
you forgot a time.sleep to comply with reddit policy
I replaced already_done with a set for efficiency
the basic idea is to getting new submission while the submission was already done
import praw, time
r = praw.Reddit(user_agent='ADNPost')
already_done = set()
while True:
l = r.get_top(limit=1)
submission = next(l,None)
if not submission:
continue
while submission.id in already_done:
submission=next(r.get_front_page(limit=1, params={'after':submission.fullname}),None)
if not submission:
break
if submission:
id = submission.id
title = submission.title
url = submission.short_link
print (title, url)
save_state = (id)
already_done.add(submission.id)
time.sleep(2)
EDIT: tested the place_holder is not what you want (the "t3_" is a constant which looks working
EDIT 2: replaced "t3_"+submission.id by submission.fullname according to #bboe proposition

How to keep query parameters during pagination with webhelpers.paginate

I look an example of paginating from http://rapidprototype.ch/bg2docs/tg2pagination.html for my Turbogears 2 project and it works great but, I have a problem regarding my query parameters when I change the page I'm looking.
This is what I have in my controller when listing.
def list(self, page=1, **kw):
q = ""
if kw.has_key('q'):
log.debug("searching %s" % kw)
q = kw['q']
if kw.has_key('all'):
q = ""
products = DBSession.query(model.Product).filter(
or_(model.Product.name.like('%%%s%%' % q),
model.Product.description.like('%%%s%%' % q),
model.Product.model.like('%%%s%%' % q),
model.Product.code.like('%%%s%%' % q))).all()
def get_link(product):
return Markup("""%s""" % (product.id, product.id))
product_fields = [
(Markup("""Id"""), get_link),
(u'Name', 'name'),
(u'Model', 'model'),
(u'Code', 'code'),
(u'Description', 'description')]
product_grid = MyDataGrid(fields = product_fields)
currentPage = paginate.Page(products, page, items_per_page=50)
return dict(currentPage=currentPage,
title=u'Products List', item=u'product', items=u'products',
data=currentPage.items,
grid=product_grid,
page=u'Search %s results' % q,
q=q,
hits=len(products))
This is the html template fragment
<h1>List of ${items}</h1>
<form action="list" method="get">
<input name="q" type="text" value="${value_of('q', default='')}"/>
<input type="submit" value="Search"/> <input type="submit" name="all" value="All"/>
</form>
${hits} ${items} found
<p class="pagelist">${currentPage.pager(format='$link_first ~3~ $link_last')}</p>
<div>
${grid(data)}
</div>
<p>Add a ${item}</p>
The searches works fine resulting in links like this '/list?q=cable' but when I click some of the paginating pages "1,2...8,9" turns to '/list?page=2'
How do I add my previous query parameter or any other parameters to the link?
After experimenting on the shell for a while I think I found a solution.
There's a kwargs dictionary defined in currentPage (after being assigned from paginate.Page), so I made some experiments sending parameters and it worked. This is how.
currentPage = paginate.Page(products, page, items_per_page=50)
currentPage.kwargs['q'] = q
return dict(currentPage=currentPage,
title=u'Products List', item=u'product', items=u'products',
data=currentPage.items,
grid=product_grid,
page=u'Search %s results' % q,
q=q,
hits=len(products))
now I get this kind of links: '/list?q=cable&page=2' still wondering if it is the best solution or the best practice
you should use syntax like:
currentPage.kwargs['q'] = q
currentPage = paginate.Page(
products,
page,
items_per_page=50,
q = q
)
you can update request params, like this snippets.
def paginate(self, items, items_per_page=20):
"""https://bitbucket.org/bbangert/webhelpers/src/acfb17881c1c/webhelpers/paginate.py"""
current_page = self.request.GET.get('page') or 1
def page_url(page):
params = self.request.params.copy()
params['page'] = page
return self.request.current_route_url(_query=params)
return Page(collection=items, page=current_page, items_per_page=items_per_page, url=page_url)

Categories

Resources