CSS failing to load on app engine python/jinja2 guestbook tutorial - python

Couldn't find anything on Stack Overflow. I've made sure that all my code and file structure is exactly verbatim from the tutorial here: https://developers.google.com/appengine/docs/python/gettingstartedpython27/staticfiles
My site: nathanwjclark.appspot.com
The error I get: http://i.imgur.com/oH70Jd7.png
How can I get my CSS to load correctly?
App.yaml:
application: nathanwjclark
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /stylesheets
static_dir: stylesheets
- url: /.*
script: guestbook.application
libraries:
- name: webapp2
version: latest
- name: jinja2
version: latest
index.yaml:
indexes:
- kind: Greeting
ancestor: yes
properties:
- name: date
direction: desc
index.html:
<!DOCTYPE html>
{% autoescape true %}
<html>
<head> <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /> </head> <body>
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author.nickname() }}</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content }}</blockquote>
{% endfor %}
<form action="/sign?guestbook_name={{ guestbook_name }}" 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="{{ guestbook_name }}" name="guestbook_name">
<input type="submit" value="switch">
</form>
{{ url_linktext }}
</body>
</html>
{% endautoescape %}
guestbook.py:
# [START imports]
import os
import urllib
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
# [END imports]
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 single 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)
# [START main_page]
class MainPage(webapp2.RequestHandler):
def get(self):
guestbook_name = self.request.get('guestbook_name',
DEFAULT_GUESTBOOK_NAME)
greetings_query = Greeting.query(
ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
greetings = greetings_query.fetch(10)
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'
template_values = {
'greetings': greetings,
'guestbook_name': urllib.quote_plus(guestbook_name),
'url': url,
'url_linktext': url_linktext,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
# [END main_page]
class Guestbook(webapp2.RequestHandler):
def post(self):
# We set the same parent key on the 'Greeting' to ensure each Greeting
# is in the same entity group. Queries across the single entity group
# will be consistent. However, the write rate to a single entity group
# 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)

You mistakenly saved it as main.css.txt and it is served at:
http://nathanwjclark.appspot.com/stylesheets/main.css.txt

Related

Ancestor Query not displaying results

I'm having trouble getting my ancestor queries to display the links associated with Tom's photos that are stored in the datastore. Nothing is displayed from the datastore even though there are several links in the datastore. Any assistance will be appreciated. Thanks in advance.
main.py
import webapp2
import jinja2
import os
from google.appengine.ext import db
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class MainPage(webapp2.RequestHandler):
def get(self):
tom = Person(key_name='Tom')
wedding_photo = Photo(parent=tom)
wedding_photo.image_url='http://pinterest.com/pin/200691727117011230/'
wedding_photo.put()
baby_photo = Photo(parent=tom)
baby_photo.image_url='http://pinterest.com/pin/518828819542052681/'
baby_photo.put()
dance_photo = Photo(parent=tom)
dance_photo.image_url='http://pinterest.com/pin/257197828689352707/'
dance_photo.put()
dog_photo = Photo()
dog_photo.image_url='http://pinterest.com/pin/279575089339614779/'
dog_photo.put()
photo_query = Photo.all()
photo_query.ancestor(tom)
message = "Photos"
template_values = {
'message': message,
'photo_query': photo_query,
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class PhotoStore(webapp2.RequestHandler):
def post(self):
photo = Photo()
photo.image_url = self.request.get('image_url')
photo.put()
self.redirect('/')
class Person(db.Model):
name = db.StringProperty()
class Photo(db.Model):
image_url = db.StringProperty()
app = webapp2.WSGIApplication([('/', MainPage),
('/new_photo',PhotoStore)], debug=True)
index.html
<html>
<body>
<form action="/new_photo" method="post">
<label for="photo">Photo</label>
<div><textarea name="image_url" rows="1" cols="60" id="image_url"></textarea></div>
<input type="submit" value="Submit">
</form>
<hr></hr>
<div><b>{{ message }}</b></div>
<b>{% for p in photo_query.run(limit=5): %}</b>
<div>{{ p }}</div>
<b>{% endfor %}</b>
</body>
</html>
What do you see if you open the generated html source? I assume that the code {{ p }} just shows string representation of the Photo objects, which results in showing strings like <__main__.Photo object at 0xfcbd9ef0> that is interpreted as HTML tag and doesn't show in the rendered HTML.

My first Google App Engine/Python app

I am trying to write my first GAE/Python application that does the following three things:
Displays a form where the user can enter details about themself (index.html)
Stores the submitted form data in the datastore
Retrieves all data from datastore and displays all results above the form (index.html)
However, I'm getting the following error
line 15, in MainPage 'people' : people NameError: name 'people' is not
defined
Any advice on how to resolve this and get my app working will be appreciated!
main.py
import webapp2
import jinja2
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class MainPage(webapp2.RequestHandler):
def get(self):
people_query = Person.all()
people = people_query.fetch(10)
template_values = {
'people': people
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
# retrieve the submitted form data and store in datastore
class PeopleStore(webapp2.RequestHandler):
def post(self):
person = Person()
person.first_name = self.request.get('first_name')
person.last_name = self.request.get('last_name')
person.city = self.request.get('city')
person.birth_year = self.request.get('birth_year')
person.birth_year = self.request.get('height')
person.put()
# models a person class
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
city = db.StringProperty()
birth_year = db.IntegerProperty()
height = db.IntegerProperty()
app = webapp2.WSGIApplication([('/', MainPage),
('/new_person')], debug=True)
index.html
<html>
<body>
{% for person in people %}
{% if person %}
<b>{{ person.first_name }}</b>
<b>{{ person.last_name }}</b>
<b>{{ person.city }}</b>
<b>{{ person.birth_year }}</b>
<b>{{ person.height }}</b>
<hr></hr>
{% else %}
No people found
{% endfor %}
<form action="/new_person" method="post">
<div><textarea name="first_name" rows="3" cols="60"></textarea></div>
<div><textarea name="last_name" rows="3" cols="60"></textarea></div>
<div><textarea name="city" rows="3" cols="60"></textarea></div>
<div><textarea name="birth_year" rows="3" cols="60"></textarea></div>
<div><textarea name="height" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Submit"></div>
</form>
</body>
</html>
app.yaml
application: some_name
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
EDIT 1
*main.py*
import webapp2
import jinja2
import os
from google.appengine.ext import db
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class MainPage(webapp2.RequestHandler):
def get(self):
people_query = Person.all()
people = people_query.fetch(10)
template_values = {
'people': people
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class PeopleStore(webapp2.RequestHandler):
def post(self):
person = Person()
person.first_name = self.request.get('first_name')
person.last_name = self.request.get('last_name')
person.city = self.request.get('city')
person.birth_year = self.request.get('birth_year')
person.height = self.request.get('height')
person.put()
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
city = db.StringProperty()
birth_year = db.IntegerProperty()
height = db.IntegerProperty()
app = webapp2.WSGIApplication([('/', MainPage),
('/new_person')], debug=True)
EDIT 2
*main.py*
The following edit fixed this error
AttributeError: 'str' object has no attribute 'get_match_routes'
app = webapp2.WSGIApplication([('/', MainPage),('/new_person',PeopleStore)], debug=True)
Ok great, the form displays in the browser, but when I submit the data, I get this error:
BadValueError: Property birth_year must be an int or long, not a
unicode
EDIT 3
main.py
person.birth_year = int(self.request.get('birth_year'))
person.height = int(self.request.get('height'))
resolved this error:
badvalueerror property must be an int or long, not a unicode
Ok, good so far. The data stores in the data store. However, my page comes up blank...
You have an indentation problem. Lines 3 and onwards of your get method should be indented at the same level as the first two lines. Otherwise, they are not part of the method, but the class definition itself, and will be executed when the class is defined - at which point there is no variable people in scope.
In your app.yaml it doesnt like the underscore
#application: some_name
application: somename
There are some more issues with blocks not being closed etc which you need to work through yourself

unable to get redirect work in google app Engine

I am beginner in Google App engine, and trying to go through Google App HelloWorld app. redirect url does not work while using templates.
self.redirect('/?'+urllib.urlencode({'guestbook_name':guestbook_name}))
It redirects but should show exact url in urlbar like
http://localhost:8080/?guestbook_name=some_name
whereas it displays like
http://localhost:8080/?guestbook_name=
class MainPage(webapp2.RequestHandler):
def get(self):
guestbook_name=self.request.get('guestbook_name')
greetings_query = Greeting.all().ancestor(
guestbook_key(guestbook_name)).order('-date')
greetings = greetings_query.fetch(10)
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'
template_values = {
'greetings': greetings,
'url': url,
'url_linktext': url_linktext,
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class Guestbook(webapp2.RequestHandler):
def post(self):
guestbook_name = self.request.get('guestbook_name')
greeting = Greeting(parent=guestbook_key(guestbook_name))
if users.get_current_user():
greeting.author = users.get_current_user().nickname()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/?' + urllib.urlencode({'guestbook_name': guestbook_name}))
Index.html file looks like
<html>
<body>
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author }}</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
{{ url_linktext }}
</body>
</html>
Seems your guestbook_name is '' (empty string)
In your index.html there is no input that sets the guestbook name. For an empty key, webapp2 returns an empty string for self.request.get('key_name') instead of None as you might expect. You can see this by looking at the datastore, all your stored greetings will have an empty guestbook_name.
To get the guestbook_name set your template values in the get method to
template_values = {
'greetings': greetings,
'guestbook_name': guestbook_name,
'url': url,
'url_linktext': url_linktext,
}
and in your index.html
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="hidden" name="guestbook_name" value="{{guestbook_name}}"></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
That will add the guestbook_name to data you send in the POST, so you will be able to use it in your handler.
I encounter a similar problem while trying gae, the official site https://developers.google.com/appengine/docs/python/gettingstartedpython27/templates has changed the related code just like Anthony metioned in his post.
But here are some problems too:
In the template_values variable in class MainPage, guestbook_name was encoded by urllib.urlencode which will fail since this function takes a dict or a tuple as a variable
rather than a string, urllib.quote_plus should be used instead.
Two forms in index.html shares the same encoded variable guestbook_name, which is not pretty if your language is non-English, in which case some %2F like strings will appears in the content, so, my solution is send a extra non encoded guestbook_name for the second form.

Internal Server Error - Google App Server (Property Content Required)

I keep receiving an internal server error - 'BadValueError: Property content is required. It seems to happen when I pass blog_table into the template to render. Here's the code:
main.py:
import os
import webapp2
import jinja2
from google.appengine.ext import db
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__),'templates')), 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 Blog(db.Model):
subject = db.StringProperty(required = True)
content = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
class MainPage(Handler):
def render_front(self, subject="", content="", error=""):
blog_table = db.GqlQuery("SELECT * FROM Blog ORDER BY created DESC")
self.render("blog.html",subject = subject,content = content,error = error,blog_table = blog_table)
def get(self):
self.render_front()
def post(self):
subject = self.request.get("subject")
content = self.request.get("content")
if subject and content:
b = Blog(subject = subject, content = content)
b.put()
self.redirect("/")
else:
error = "we need both a subject and some content"
self.render_front(subject,content,error)
app = webapp2.WSGIApplication([('/', MainPage)],debug=True)
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Blog</title>
</head>
<body>
<h1>Blog</h1>
<form method="post">
<label>
<div>Subject</div>
<input type="text" name="subject" value="{{subject}}">
</label>
<label>
<div>Content</div>
<textarea name="content" value="{{content}}"></textarea>
</label>
<div class="error">{{error}}</div>
<input type="submit">
</form>
<hr>
{% for post in blog_table %}
<div class="post">
<div class="subject">{{post.subject}}</div>
<pre class="content">{{post.content}}</pre>
</div>
{% endfor %}
</body>
</html>
To see the error go to http://udacity-cs253-a31.appspot.com/
Thanks.
This is just a guess - changed your Blog model and added the Content attribute recently.
There's some old instances of the Blog model in your datastore that have no Content. If you try to load those, your code fails. If you load a Blog instance with Content, everything is fine.
You have to go through your datastore and ensure all instances of your Blog have Content.

Invalid Block Tag i=0, in Django

I was going through Appengine's Getting Started guide for python, while reading up templates,I modified the code(which is a simple guestbook) to include simple numbering next to the guestbook entries.
In index.html i added the (what I thought would be) relevant code.
index.html (I have added {%i=0%} on line 3,{%i+=1%} on line 5, and {{i}} on line 7, the rest is from the guide):
<html>
<body>
{%i=0%}
{% for greeting in greetings %}
{%i+=1%}
{% if greeting.author %}
<b>{{i}}:{{ greeting.author.nickname }}</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
{{ url_linktext }}
</body>
</html>
I got the following error
TemplateSyntaxError: Invalid block
tag: 'i=0'
I read up Django's help on templates, which says that
The Django template system provides
tags which function similarly to some
programming constructs – an if tag for
boolean tests, a for tag for looping,
etc. – but these are not simply
executed as the corresponding Python
code, and the template system will not
execute arbitrary Python expressions.
So I guess, that performing calculations is not what the templating system is for.
tl;dr
Can anyone tell me how to number my entries or use the "counter - increment" construct using Django templates?
I don't thing this code is necessary, but to complete the picture,
Unchanged helloworld.py code:
import os
from google.appengine.ext.webapp import template
import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp.RequestHandler):
def get(self):
greetings_query = Greeting.all().order('-date')
greetings = greetings_query.fetch(10)
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'
template_values = {
'greetings': greetings,
'url': url,
'url_linktext': url_linktext,
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/')
application = webapp.WSGIApplication(
[('/', MainPage),
('/sign', Guestbook)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
From http://www.djangobook.com/en/beta/chapter04/
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
It depends on what you need it for. If you need the actual count, you can use a for loop in the template: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
Then you can use forloop.counter or forloop.counter0 to check the index.
If you just want to display a list of numbers you can use a html ordered list.
Django's template engine is for design only, and you want to keep calculations out of it. If you need to do something with your data at the template layer you can write a custom tag/filter.

Categories

Resources