How to keep query parameters during pagination with webhelpers.paginate - python

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)

Related

How to fill Django database on view buttonclick

I'm just learning Django, so my question might seem not worth attention, but i spent some time googling and havnt found an answer.
I have two models and a function to fill it
urls.py
url(r'^upd/$', update_database, name="upd")
views.py
def update_database(request):
grabdata()
def grabdata():
url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_day.geojson"
weburl = urllib.request.urlopen(url)
if (weburl.getcode() == 200):
data = json.loads(weburl.read())
EarthQuakes.objects.all().delete()
LastGetSession.objects.all().delete()
lastsession = LastGetSession(hand=data["metadata"]["title"])
lastsession.save()
for i in data["features"]:
place = i["properties"]["place"]
place = str.split(",")
place = place[-1]
time = i["properties"]["time"]
mag = i["properties"]["mag"]
rept = i["properties"]["felt"]
if rept is None:
rept = 1
longitude = 0
latitude = 0
earthquake = EarthQuakes(place=place, time=time,
mag=mag, rept=rept,
longitude=longitude, latitude=latitude)
earthquake.save()
template
<a id="update_button" class="btn btn-info btn-lg" href="{% url 'upd' %}" >Update_database</a>
But i didn't get how to execute it from a view.
Or I assume there is a way to call a conroller function that calls the model function or something like that
It returns the "The view earthquake.views.update_database didn't return an HttpResponse object. It returned None instead."
It feels like there is one missing piece or the pazzle
On Your views.py
def my_view(request):
grabdata()
return HttpResponse('Done')
in urls.py add a new url
url(r'^my-view/$', views.my_view,name='my_view')
in your template
Update

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?

Retrieving Submitted Greetings in the Tutorial

I'm working though the GAE Tutorial and I'm getting the following error.
File "/Users/cparrish/bin/guestbook/guestbook.py", line 62, in get
for greeting in greetings:
NameError: global name 'greetings' is not defined
So I think the problem is here somewhere.
greetings_query = Greeting.query(
ancestor = guestbook_key(guestbook_name)).order(-Greeting.date)
greeetings = greetings_query.fetch(10)
for greeting in greetings:
if greeting.author:
self.response.write(
'<b>%s</b> wrote:' % greeting.author.nickname())
Which are lines 58 - 66
So I'm wondering if anyone else can see what I'm apparently missing here.
Full code base below.
import cgi
import urllib
from google.appengine.api import users
from google.appengine.ext import ndb
import webapp2
MAIN_PAGE_FOOTER_TEMPLATE = """\
<form action="/sign?%s" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
<hr>
<form>Guestbook name:
<input value="%s" name="guestbook_name">
<input type="submit" value="switch">
</from>
%s
</body>
</html>
"""
DEFAULT_GUESTBOOK_NAME = 'default_guestbook'
# We set a parent key on the 'Greetings' to ensure that they are all in the same
# entity group. Queries across the signle entity group will be consistent.
# However, the write rate should be limited to -1/second.
def guestbook_key(guestbook_name="DEFAULT_GUESTBOOK_NAME"):
""" Constructs a Datastore key for a Guestbook entity with guestbook_name. """
return ndb.Key('Guestbook', guestbook_name)
class Greeting(ndb.Model):
"""Models an individual Guestbook entry with author, content, and date. """
author = ndb.UserProperty()
content = ndb.StringProperty( indexed = False )
date = ndb.DateTimeProperty( auto_now_add = True )
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write('<html><body>')
guestbook_name = self.request.get('guestbook_name', DEFAULT_GUESTBOOK_NAME)
# Ancestor Queries, as shown here, are strongly consisten with the High
# Replication Datastore. Queries that span entity groups are eventually
# consisten. If we omitted the ancestor from this query there would be
# a slight chance that Greetings that had just been written would not
# show up in a query.
greetings_query = Greeting.query(
ancestor = guestbook_key(guestbook_name)).order(-Greeting.date)
greeetings = greetings_query.fetch(10)
for greeting in greetings:
if greeting.author:
self.response.write(
'<b>%s</b> wrote:' % greeting.author.nickname())
else:
self.response.write('An anonymous person wrote:')
self.response.write('<blockquote>%s</blockquote' %
cgi.escape(greeting.content))
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
# Write the submission form and the footer of the page
sign_query_parms = urllib.urlencode({'guestbook_name': guestbook_name})
self.response.write(MAIN_PAGE_FOOTER_TEMPLATE % (sign_query_parms, cgi.escape(guestbook_name), url, url_linktext))
class Guestbook(webapp2.RequestHandler):
def post(self):
# We set the same parent key on the 'Greeting' to ensure each getting
# is in the same entity group. Queries across the single entity group
# will be consistent. However, the write reate to a sing entity groupo
# should be limited to ~1/second.
guestbook_name = self.request.get('guestbook_name',
DEFAULT_GUESTBOOK_NAME)
greeting = Greeting(parent=guestbook_key(guestbook_name))
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
query_params = {'guestbook_name': guestbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', Guestbook),
], debug=True)
There are three e's in your assignment of greeetings.
greeetings = greetings_query.fetch(10)
for greeting in greetings:
One of these es is not like the others, one of these es just doesn't belong...

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)

Categories

Resources