Creating hyperlinks in Google App Engine using Jinja2 template - python

I'm trying to scrape links from a RSS page from Quora, which I have been successful in doing so. However, I want those links to appear as hyperlinks in my application, instead of simply appearing as plain text.
Here's the application so far:
http://deploymentapp.appspot.com/
Here's the main python code:
import os
import webapp2
import jinja2
from google.appengine.ext import db
import urllib2
import re
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class MainPage(Handler):
def get(self):
content = urllib2.urlopen('http://www.quora.com/Python-programming-language-1/rss').read()
allTitles = re.compile('<title>(.*?)</title>')
allLinks = re.compile('<link>(.*?)</link>')
list = re.findall(allTitles,content)
linklist = re.findall(allLinks,content)
self.render('frontrss.html', list = list, linklist = linklist)
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
here's the HTML source code:
<h1>Quora Live Feed</h1><br><br><br>
{% extends "rssbase.html" %}
{% block content %}
{% for e in range(1, 19) %}
{{ (list[e]) }} <br>
{{ (linklist[e]) }}
<br><br>
{% endfor %}
{% endblock %}
So basically, I don't know how to make the links appear as hyperlinks when scraped from an outside source code in Jinja2 template.

This is just basic HTML: you put the link inside the href attribute of an a tag:
{{ list[e] }}

Related

redirect not working, have to refresh page every time

I am attempted to redirect in the post method every time i hit submit (which adds more "art" to the database) but I have to refresh afterwards to get the new entry to show up instead. I have included my main.py code and the html below. How can I fix this so I don't have to manually refresh after every submission. (this is from the udacity web development course).
import os
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir),
autoescape = True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class Art(db.Model):
title = db.StringProperty(required = True)
art = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
class MainPage(Handler):
def render_front(self, title="", art="", error=""):
arts = db.GqlQuery("select * from Art order by created desc")
self.render("front.html", title = title, art = art, error = error, arts = arts)
def get(self):
self.render_front()
def post(self):
title = self.request.get("title")
art = self.request.get("art")
if title and art:
a = Art(title=title, art=art)
a.put()
self.redirect("/")
else:
error = "we need both a title and some artwork!"
self.render_front(error=error, title=title,art=art)
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
html:
<form method="post">
<label>
<div>title</div>
<input type="text" name="title" value="{{title}}">
</label>
<label>
<div>art</div>
<textarea name="art">{{art}}</textarea>
<label>
<div class="error">{{error}}</div>
<input type="submit">
</form>
<hr>
{% for art in arts %}
<div class="art">
<div class="art-title">{{art.title}}</div>
<pre class="art-body">{{art.art}}</pre>
</div>
{% endfor %}
</body>
Your redirect is working fine. The reason the new entity doesn't show up is because of eventual consistency with the GAE datastore. When you put an entity, it can take a little time before it is available to be queried.
There are workarounds, but they depend on the particular application. For example, you can store a list of keys since getting by key will always work or you could use memcache.

Flask-Babel Multiple Language URL Routing

I am creating a multi-language site (EN and FR) and I need it to toggle back and forth on click if the user so chooses. I am using Flask-Babel and the translations and toggle are working correctly on click, however, I need the URLs to be translated as well. I have currently wrapped my URL routes like so, with both the English and French URLs:
#main.route('/accueil')
#main.route('/home')
def index():
return render('index.html', {})
#main.route('/a-propos-de-nous')
#main.route('/about-us')
def about():
return render('about.html', {})
The rest of the code that is grabbing the language and toggling is as follows:
app = Flask(__name__, static_folder=settings.STATIC_ROOT)
main = Blueprint('main', __name__, url_prefix='/language/<lang_code>')
#app.url_defaults
def set_language_code(endpoint, values):
if 'lang_code' in values or not session['lang_code']:
return
if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
values['lang_code'] = session['lang_code']
#app.url_value_preprocessor
def get_lang_code(endpoint, values):
if values is not None:
session['lang_code'] = values.pop('lang_code', None)
#app.before_request
def ensure_lang_support():
lang_code = session['lang_code']
if lang_code and lang_code not in app.config['SUPPORTED_LANGUAGES'].keys():
return abort(404)
#babel.localeselector
def get_locale():
if session.get('lang_code') is None:
session['lang_code'] = request.accept_languages.best_match(app.config['SUPPORTED_LANGUAGES'].keys())
return session['lang_code']
The template looks like this where the user clicks on the link to change languages:
{% if session['lang_code']=='en' %}
{% set new_lang_code='fr' %}
{% else %}
{% set new_lang_code='en' %}
{% endif %}
<li>{{ _('Fr') }}</li>
As I have little experience with Python/Flask...I am struggling with the best way to switch to the translated URL. How would I go about doing this? Any information would be appreciated. Thanks in advance.
I have found a solution! I had to add endpoints to the URL routes like so:
#main.route('accueil', endpoint="index_fr")
#main.route('home', endpoint="index_en")
def index():
return render('index.html', {})
#main.route('a-propos-de-nous', endpoint="about_fr")
#main.route('about-us', endpoint="about_en")
def about():
return render('about.html', {})
This allowed me to use Babel to translate the URL endpoints like it did for the rest of the text, and grab the correct URL ending along with the language code from the session. The toggle works like this now:
{% if session['lang_code']=='en' %}
{% set new_lang_code='fr' %}
{% else %}
{% set new_lang_code='en' %}
{% endif %}
<li>{{ _('Fr') }}</li>

Google App Engine: Retrieving data from database

I am trying to build a simple blog application to use the skills that I learned from Udacity so far. However, I am having trouble retrieving data from the database and displaying it for the user. Now, my blog has a permalink which displays the post that was just being submitted by the user, and also the main blog page which will display the latest 10 posts in descending order. But when I submit a post, the post is stored in the database successfully, and I am being redirected to a permalink. However, all I get is a blank page instead of the post that I just submitted.
Also, when I go back to my main blog page, I see this instead of all the posts being submitted by the user:
Here's the main python code:
import os
import re
import webapp2
import jinja2
from string import letters
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
def render_str(template, **params):
t = jinja_env.get_template(template)
return t.render(params)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
return render_str(template, **params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
def render_post(response, post):
response.out.write('<b>' + post.subject + '</b><br>')
response.out.write(post.content)
def post_key(name = "dad"):
return db.Key.from_path('blog', name)
class Blogger(db.Model):
name = db.StringProperty()
content = db.TextProperty()
created = db.DateTimeProperty(auto_now_add = True)
def render(self):
self._render_text = self.content.replace('\n', '<br>')
return render_str("post.html", p = self)
class MainPage(Handler):
def get(self):
self.response.write("Visit our blog")
class BlogHandler(Handler):
def get(self):
posts = db.GqlQuery("SELECT * FROM Blogger order by created desc")
self.render("frontblog.html", posts = posts)
class SubmitHandler(Handler):
def get(self):
self.render("temp.html")
def post(self):
name = self.request.get("name")
content = self.request.get("content")
if name and content:
a = Blogger(parent = post_key(), name = name, content = content)
a.put()
self.redirect('/blog/%s' % str(a.key().id()))
else:
error = "Fill in both the columns!"
self.render("temp.html", name = name, content = content, error = error)
class DisplayPost(Handler):
def get(self, post_id):
post_id = self.request.get("post_id")
if post_id:
po = Blogger.get_by_id(int(post_id), parent = post_key())
if po:
self.render("perma.html", po = po)
self.response.write("No")
app = webapp2.WSGIApplication([('/', MainPage),
('/blog', BlogHandler),
('/blog/submit', SubmitHandler),
(r'/blog/<post_id:([0-9]+)>', DisplayPost)], debug=True)
Here's the HTML code for the base of all the HTML pages:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="/static/main.css" />
<title>CS 253 Blog</title>
</head>
<body>
<a href="/blog" class="main-title">
CS 253 Blog
</a>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
Here's the HTML code for the permalink page:
{% extends "base.html" %}
{% block content %}
{{po.render() | safe}}
{% endblock %}
HTML code for the front of the blog:
{% extends "base.html" %}
{% block content %}
{% for p in posts %}
{{ p.render() | safe }}
<br><br>
{% endfor %}
{% endblock %}
I have been struggling with this for over two days now. I see no bugs in the logs either. What seems to be the problem?
EDIT:
Edited the source code based on the answers below. However, I still get a 404 error.
You are creating your Blogger entity with a parent key that you are not specifying when you are trying to retrieve your post in your DisplayPost.
An entity's key is composed of multiple parts. It's Kind ("Blogger"), it's ID (int(post_id)), and also it's ancestor, or parent.
Because you create your entity with:
a = Blogger(parent = post_key(), name = name, content = content)
You need to specify the same parent when calling get_by_id() (see the get_by_id() docs).
Your solution will be to change
po = Blogger.get_by_id(int(post_id))
to
po = Blogger.get_by_id(int(post_id), parent=post_key())
Later, if you change the name of the blog (looking at the code for post_key()), then you'll need to carry that as an argument to the post display mechanism. (You might use a subdomain as the 'name' of the blog for example).
Here is the previous answer that addressed issues with the regex URL mapping:
In your WSGIApplication definition, you have ('/blog/([0-9]+)', DisplayPost)], debug=True).
You are missing the r before the url string to identify the string as a regular expression:
(r'/blog/([0-9]+), ....
You also have the option to be more verbose with parameter naming:
(r'/blog/<post_id:([0-9]+)>, ....
Reference: http://webapp-improved.appspot.com/guide/routing.html

Django Template Page Outputting Nothing

Can someone help me figure out why my Django template pages won't render anything?
I'm using Python Requests (http://docs.python-requests.org/en/latest/) to retrieve JSON data from the external urls. I decode the data by using .json(). This works as I would expect when executing this from command line, but when it does nothing in the view.
When I run the server, the page is blank. It has no title, no 'testing' printed, nothing.
My Template:
<html>
<head><title>Offer List</title></head>
<body>
<p>Testing</p>
{% load dictparser %}
{% for offers in network1_offers %}
{% autoescape off %}
<div>
<p>name: {{ offers|lookup:"name" }}</p>
<p>pay: {{ offers|lookup:"payout" }}</p>
<p>description: {{ offers|lookup:"description" }}</p>
</div>
{% empty %}
<li>Sorry, no surveys available.</li>
{% endautoescape %}
{% endfor %}
</body>
</html>
My View:
class OffersList(View):
template_name="generic_app/offers.html"
def load_offers(request):
"""
import example network offers.
"""
user = request.user
user_agent = request.META['HTTP_USER_AGENT']
amparams = {'user_subid':user.sub_id, 'useragent':user_agent, 'user_ip':user.ip_address}
examplenetwork = requests.get('http://example.com/api-get.php?pubid=00000&key=000000000000&mode=offers&incent=1', data=amparams)
exampleoffers= examplenetwork.json()
"""
import example network 2 offers.
"""
clparams = {'subid':user.sub_id, 'ua':user_agent, 'geoip':user.ip_address}
examplenetwork2 = requests.get('http://www.examplenetwork2.com/blahblah', data=clparams)
exampleoffers2 = examplenetwork2.json()
render(request, 'generic_app/offers.html', {'network1_offers':exampleoffers, 'network2_offers':exampleoffers2})
The url:
url(r'^dashboard/offers$', OffersList.as_view(), name="offers"),
You're seeing this because you haven't defined how to get to the load_offers() method in your view, currently your load_offers() method is just a method floating around in your class.
Using the base class View comes with it's methods that you need to implement, for example
class OfferView(View):
template_name = "generic_app/offers.html"
def get(self, request, *args, **kwargs):
return load_offers(request)
or much better change this to a TemplateView(because that's what it really is).
class OfferView(TemplateView):
template_name = "generic_app/offers.html"
def get_context_data(self, **kwargs):
context = super(OfferView, self).get_context_data(**kwargs)
context['offers'] = load_offers(self.request)
return context

How to render placeholders from a django-cms custom templatetag?

I've made a simple template tag to list child pages in a django-cms site.
It's working fine except for the fact that I have not been able to render the child pages placeholders in the template tag itself.
The following is my code for the template tag.
subpages.py
from cms.models import Page
from cms.utils.page_resolver import get_page_from_path
from django import template
register = template.Library()
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
return {'subpages':subpages}
subpages.html
{% load cms_tags menu_tags placeholder_tags %}
<ul>
{% for item in subpages %}
<li>{{ item.get_title }}
{% render_placeholder subtitle %}
</li>
{% endfor %}
</ul>
I've tried some alternatives to *render_placeholder* but without luck.
How would be the correct way to get the placeholder rendered?
This is only a (untested) suggestion, but try passing the context along to the template:
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
context.update({'subpages':subpages})
return context

Categories