redirecting to a variable href from python - 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?

Related

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:

Django unable to read variable specified in form action

Can anyone help me with the below? I'm reading 'how to tango with django' project and stuck here.
I want a html form to revert back to a view function(add_page).
<h1>Add a Page</h1>
{% if category %}
<form id="category_form" method="post" action="/rango/category/{{category.slug}}/add_page/">
{% endif %}
This is my url map
urlpatterns = patterns('',
url(r'^$',views.index, name = 'index'),
url(r'^about/$',views.about, name = 'about'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$',views.category,name = 'category'),
url(r'^add_category/$', views.add_category, name = 'add_category'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$',views.add_page, name ='add_page'),
)
and my veiws.add_page function
def add_page(request,category_name_slug):
try:
cat = Category.objects.get(slug = category_name_slug)
except :
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit = False)
page.category = cat
page.views = 0
page.save()
return redirect('/rango')
else:
print (form.errors)
else:
form = PageForm()
context_dict = {'form':form,'category':cat}
return render(request, 'rango/add_page.html',context_dict)
the submit button doesnt seem to be taking to post data to the requested url. Please let me know where i am going wrong?
If you want to redirect to the same page
you should probably call
return redirect('add_page', category_name_slug=page.category)
or maybe use something like
return redirect(request.build_absolute_uri())
in the POST section of your code.
request methods
redirect() options
EDIT: To clarify the 'return redirect('rango/')' is not pointing to anything in the url mapping in the question.

GAE - Error: "The method POST is not allowed for this resource"

I'm trying to understand how to edit or update a model. I have tried several scenarios which sometimes give an error message: 405 Method Not Allowed - The method POST is not allowed for this resource. Below is my code:
The Python Models:
import os
import webapp2
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext.webapp import template
class MessageModel(db.Model):
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class Message(webapp2.RequestHandler):
def get(self):
doRender(self,'message.htm')
def post(self):
m = MessageModel()
m.content = self.request.get('content')
m.put()
self.redirect('/view')
class View(webapp2.RequestHandler):
def get(self):
que = db.Query(MessageModel)
messageview_list = que.fetch(999)
doRender(self,
'view.htm',
{'messageview_list': messageview_list })
class Edit(webapp2.RequestHandler):
def get(self):
doRender(self,'edit.htm')
def post(self):
updated_content = self.request.get('content')
content_query = db.GqlQuery("SELECT * "
"FROM MessageModel "
"ORDER BY date DESC LIMIT 1")
messageview_list = content_query.fetch(1)
m = MessageModel()
m.content = self.request.get(updated_content)
m.put()
doRender(self,
'edit.htm',
{'messageview_list': messageview_list })
class Main(webapp2.RequestHandler):
def get(self):
doRender(self,'index.htm')
def doRender(handler, tname = 'index.htm', values = { }):
temp = os.path.join(
os.path.dirname(__file__),
'templates/' + tname)
if not os.path.isfile(temp):
return False
newval = dict(values)
newval['path'] = handler.request.path
outstr = template.render(temp, newval)
handler.response.out.write(outstr)
return True
app = webapp2.WSGIApplication([('/', Main),
('/message', Message),
('/view', View),
('/edit', Edit)],
debug=True)
The HTML Form:
{% for messageview in messageview_list %}
<form method="post" action="/edit">
<p>
<textarea name="message" rows="3" cols="60" MAXLENGTH=60>
{{ messageview.content }}</textarea>
<br>
<input type="submit" value="Update"/>
</p>
</form>
{% ifnotequal error None %}
<p>
{{ error }}
</p>
{% endifnotequal %}
{% endfor %}
I am assuming the indentation is due to copy/paste, but make sure that the post() and get() functions are actually indented inside of your class.
In your form, you have <textarea name="message" rows="3" cols="60" MAXLENGTH=60>, but in your def post() you use updated_content = self.request.get('content'), which is looking for the content keyword in the request. Also, your edit doesn't look like it is doing what you want it to do. In order to edit an entity, the basic outline of the process is 1.) Retrieve the entity (so do as you do, query using some parameter); 2.) Modify the properties of the entity however you want; and 3.) put() the entity back in the datastore.
From your code, it looks like you are retrieving the last entity entered into the datastore, but then creating a new model instead of editing that one (assuming that is what you want to do - not quite sure if that is accurate :) ). If you are looking to modify the entity that is returned, this should work:
def post(self):
updated_content = self.request.get('message')
content_query = db.GqlQuery("SELECT * "
"FROM MessageModel "
"ORDER BY date DESC LIMIT 1")
# Your query will always return just one entity (due to the LIMIT),
# but you can use get() here instead of fetch(1)
latest_model = content_query.get()
# Update the model's content property
latest_model.content = updated_content
latest_model.put()
# Assuming you want to output that model, you'd output it now
doRender(self,
'edit.htm',
{'messageview_list': latest_model })

Best way to redirect to referring page

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)

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