Displaying Python database on Flask web server - database

I'm working on a project that requires that I create a create a database, import data into it, and display it on a FLASK local server. I've created the database, but I'm confused as to what I need to do in order to display its tables on the server. I have it set up to display information via HTML through render_template and believe I've established a connection via config.py, but I'm not sure where to go from here. I've read the following guides, but I don't quite understand them. If anybody could assist, I would appreciate it.
http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/
http://flask-sqlalchemy.pocoo.org/2.3/config/
Below are the relevant files in the project root.
/project
config.py
database_insert.py
server.py
/app
/templates
index.html
__init__.py
models.py
routes.py
config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = 'you-will-never-guess'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////project/app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
init.py
from flask import Flask, request, render_template
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from app import routes, models
models.py
from app import db
class Lot(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(64), index=True)
spots = db.relationship('Spot', backref='author', lazy='dynamic')
def __repr__(self):
return '<Lot {}>'.format(self.username)
class Spot(db.Model):
id = db.Column(db.Integer, primary_key=True)
availability = db.Column(db.String(140))
spot_num = db.Column(db.String(140))
lot_id = db.Column(db.Integer, db.ForeignKey('lot.id'))
def __repr__(self):
return '<Spot {}>'.format(self.body)
routes.py
from app import app
from flask import Flask, request, render_template
#app.route('/')
#app.route('/index')
def index():
lot_details = {
'id': 'TEST_ID', #placeholder for testing purposes
'title': 'TEST_TITLE' #placeholder for testing purposes
}
return render_template('index.html', lot=lot_details)
index.html
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<p>Hello, World!</p>
<p>{{lot.id}}</p>
<p>{{lot.title}}</p>
</body>

At first, define helper method in your Spot model class.
class Spot(db.Model):
id = db.Column(db.Integer, primary_key=True)
availability = db.Column(db.String(140))
spot_num = db.Column(db.String(140))
lot_id = db.Column(db.Integer, db.ForeignKey('lot.id'))
def __repr__(self):
return '<Spot {}>'.format(self.body)
def dump(self):
return dict(id=self.id, title=self.title)
Then, in your flask route, you may query:
#app.route('/')
#app.route('/index')
def index():
lot_details = Lot.query.first().dump() # query first item
return render_template('index.html', lot=lot_details)

Related

typeerror in sqlalchemy

I am unable to create a database as every time from app import db it states cannot import name db from app.And if I do some changes it shows TypeError: Additional arguments should be named _, got 'deafult'. What should i try other than sqlalchemy as there is an import error as well for pylint.
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy()
class ToDo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(), nullable=False)
date_created = db.Column(db.DateTime, deafult=datetime.utcnow)
def __rep__(self):
return'<Task %r>' % self.id
#app.route("/")
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run()

GAE upload image then dynamically serve the image

I'm trying to make a simple app on GAE that allows a user to enter a url to an image and a name. The app then uploads this image to the Datastore along with its name.
After the upload the page self redirects and then should send the image back to the client and display it on their machine.
After running all I get is a Server error. Since I am new to GAE please could someone tell me if my code is at least correct.
I can't see what is wrong with my code. (I have checked for correct indentation and whitespace). Below is the code:
The python:
import jinja2 # html template libary
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
import urllib
import urllib2
import webapp2
from google.appengine.ext import db
from google.appengine.api import urlfetch
class Default_tiles(db.Model):
name = db.StringProperty()
image = db.BlobProperty(default=None)
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
class Upload(webapp2.RequestHandler):
def post(self):
# get information from form post upload
image_url = self.request.get('image_url')
image_name = self.request.get('image_name')
# create database entry for uploaded image
default_tile = Default_tiles()
default_tile.name = image_name
default_tile.image = db.Blob(urlfetch.Fetch(image_url).content)
default_tile.put()
self.redirect('/?' + urllib.urlencode({'image_name': image_name}))
class Get_default_tile(webapp.RequestHandler):
def get(self):
name = self.request.get('image_name')
default_tile = get_default_tile(name)
self.response.headers['Content-Type'] = "image/png"
self.response.out.write(default_tile.image)
def get_default_tile(name):
result = db.GqlQuery("SELECT * FROM Default_tiles WHERE name = :1 LIMIT 1", name).fetch(1)
if (len(result) > 0):
return result[0]
else:
return None
app = webapp2.WSGIApplication([('/', MainPage),
('/upload', Upload),
('/default_tile_img', Get_default_tile)],
debug=True)
The HTML:
<html>
<head>
<link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
</head>
<body>
<form action="/upload" method="post">
<div>
<p>Name: </p>
<input name="image_name">
</div>
<div>
<p>URL: </p>
<input name="image_url">
</div>
<div><input type="submit" value="Upload Image"></div>
</form>
<img src="default_tile_img?{{ image_name }}">
</body>
</html>
Any help at all will be so much appreciated. Thanks you!
UPDATE
Thanks to Greg, I know know how to view error logs. As Greg said I was missing a comma, I have updated the code above.
The app now runs, but when I upload an image, no image shows on return. I get the following message in the log:
File "/Users/jamiefearon/Desktop/Development/My Programs/GAE Fully functional website with css, javascript and images/mywebsite.py", line 53, in get
default_tile = self.get_default_tile(name)
TypeError: get_default_tile() takes exactly 1 argument (2 given)
I only passed one argument to get_default_tile() why does it complain that I passed two?
You're missing a comma after ('/upload', Upload) in the WSGIApplication setup.
use this python code
import jinja2 # html template libary
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
import urllib
import urllib2
import webapp2
from google.appengine.ext import db
from google.appengine.api import urlfetch
class Default_tiles(db.Model):
name = db.StringProperty()
image = db.BlobProperty(default=None)
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
class Upload(webapp2.RequestHandler):
def post(self):
# get information from form post upload
image_url = self.request.get('image_url')
image_name = self.request.get('image_name')
# create database entry for uploaded image
default_tile = Default_tiles()
default_tile.name = image_name
default_tile.image = db.Blob(urlfetch.Fetch(image_url).content)
default_tile.put()
self.redirect('/?' + urllib.urlencode({'image_name': image_name}))
class Get_default_tile(webapp2.RequestHandler):
def get_default_tile(self, name):
result = db.GqlQuery("SELECT * FROM Default_tiles WHERE name = :1 LIMIT 1", name).fetch(1)
if (len(result) > 0):
return result[0]
else:
return None
def get(self):
name = self.request.get('image_name')
default_tile = self.get_default_tile(name)
self.response.headers['Content-Type'] = "image/png"
self.response.out.write(default_tile)
app = webapp2.WSGIApplication([('/', MainPage),
('/upload', Upload),
('/default_tile_img', Get_default_tile)],
debug=True)

Integrating Chat with (webapp2 + python 2.7 + Jinja2)

I'm trying to add chat to my site and am integrating some code with my existing code. The chat app works fine on its own when it's all set up in the original main.app file. But when I try to move that same code to a handlers.py file and then setup up routes in routes.py I get errors saying template variables are undefined. Are the two different codes conflicting in the way they render templates? They seem to be using webapp2 differently, i.e. my code renders templates like this:
self.render_template('secure_zone.html', **params)
And the chat app like this:
self.response.out.write(render("main.html",
username=username,
usernameerror=usernameerror,
channel=channelname,
channelerror=channelerror))
Are both acceptable?
Here's my handlers.py file:
Routes are setup in routes.py and added in main.py
"""
import httpagentparser
from boilerplate import models
from boilerplate.lib.basehandler import BaseHandler
from boilerplate.lib.basehandler import user_required
class SecureRequestHandler(BaseHandler):
"""
Only accessible to users that are logged in
"""
#user_required
def get(self, **kwargs):
user_session = self.user
user_session_object = self.auth.store.get_session(self.request)
user_info = models.User.get_by_id(long( self.user_id ))
user_info_object = self.auth.store.user_model.get_by_auth_token(
user_session['user_id'], user_session['token'])
try:
params = {
"user_session" : user_session,
"user_session_object" : user_session_object,
"user_info" : user_info,
"user_info_object" : user_info_object,
"userinfo_logout-url" : self.auth_config['logout_url'],
}
return self.render_template('secure_zone.html', **params)
except (AttributeError, KeyError), e:
return "Secure zone error:" + " %s." % e
Here's the main.py file for the chat app:
import os
import hashlib
import urllib
import logging
import re
import json
import webapp2
import jinja2
from google.appengine.api import channel as channel_api # 'channel' is kind of ambiguous in context
from google.appengine.ext import db
from google.appengine.api import memcache
# This section will eventually get moved to a Handler class
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):
'''Returns a string of the rendered template'''
t = jinja_env.get_template(template)
return t.render(params)
def render(template, **kw):
'''Render using the template and parameters'''
return(render_str(template, **kw))
# End Handler
class Main(webapp2.RequestHandler):
def get(self):
'''Show connection page'''
return self.render_template("main.html", channel="#udacity")
def post(self):
'''Displays chat UI'''
username = self.request.get('username')
channelname = self.request.get('channel')
usernameerror = ""
if not username:
usernameerror="Please enter a username"
elif not re.compile(r'^[a-zA-Z0-9_-]{3,20}$').match(username):
usernameerror = "Username must consist of 3-20 alphanumeric characters."
elif get_user(username):
usernameerror="Username already in use"
channelerror = ""
if channelname and not re.compile(r'^#[\w]{3,20}$').match(channelname):
channelerror="Channel must consist of 3-20 alpha_numeric characters and start with a #"
if len(usernameerror+channelerror) > 0:
self.response.out.write(render("main.html",
username=username,
usernameerror=usernameerror,
channel=channelname,
channelerror=channelerror))
app = webapp2.WSGIApplication([
('/', Main),
('/communication', Communication),
('/_ah/channel/connected/?', Connect),
('/_ah/channel/disconnected/?', Disconnect)
], debug=True)
The specific error you posted in the comments "Error: 'Main' object has no attribute 'render_template'" is because in your Main handler, you try to return self.render_template. You should be just calling the function like this:
render_template("main.html", channel="#udacity")
Please note that I did not check the rest of your code, so if you run into any other issues, please post the specific errors you get.
It is because your webapp2.RequestHandler do not have the corresponding function "render_template"
you can use a BaseHandler with render_template function added to achieve the template rendering
from google.appengine.ext.webapp import template
class BaseHandler(webapp2.RequestHandler):
def render_template(self, filename, **template_args):
path = os.path.join(os.path.dirname(__file__), 'templates', filename)
self.response.write(template.render(path, template_args))
class Main(BaseHandler):
def get(self):
'''Show connection page'''
return self.render_template("main.html", channel="#udacity")
ref: http://blog.notdot.net/2011/11/Migrating-to-Python-2-7-part-2-Webapp-and-templates
I just started using webapp2 + python 2.7 + Jinja2 few days, and that is the same problem I encountered.
Hope this solution can help you ;)

User Accounts with (Python 2.7 + Webapp2 + Google App Engine + Jinja + NDB + WTForms)

I have been racking my brain for weeks trying to get this authentication module to work under the webapp2 framework using Jinja, NDB and WTForms. I've looked online everywhere and have reached my breaking point and need to reach out to somebody for help. I've been following this tutorial (which is pretty thorough but I think leaves out some important details, especially for a newbie like me):
User Accounts with Webapp2 + Google App Engine
As far as I know I have everything setup correctly but I continually get a 404 - resources can not be found. What could I be doing wrong? Here is my code...
handlers.py:
import webapp2
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
from google.appengine.api import users
from webapp2_extras import sessions, auth # we'll use auth later on
from webapp2_extras.auth import InvalidAuthIdError
from webapp2_extras.auth import InvalidPasswordError
from wtforms import Form, TextField, PasswordField, validators
from webapp2_extras.appengine.users import login_required
def jinja2_factory(app):
j = jinja2.Jinja2(app)
j.environment.filters.update({
# Set filters. (http://tinyurl.com/jinja2-factory)
# ...
})
j.environment.globals.update({
# Set global variables.
'uri_for': webapp2.uri_for,
# ...
})
return j
def login_required(handler):
def check_login(self, *args, **kwargs):
if not self.user:
return self.redirect_to('login')
else:
return handler(self, *args, **kwargs)
return check_login
class UserAwareHandler(webapp2.RequestHandler):
def dispatch(self):
try:
super(UserAwareHandler, self).dispatch()
finally:
# Save the session after each request
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session_store(self):
return sessions.get_store(request=self.request)
#webapp2.cached_property
def session(self):
return self.session_store.get_session(backend="datastore")
#webapp2.cached_property
def auth(self):
return auth.get_auth(request=self.request)
#webapp2.cached_property
def user(self):
user = self.auth.get_user_by_session()
return user
#webapp2.cached_property
def user_model(self):
user_model, timestamp = self.auth.store.user_model.get_by_auth_token(
self.user['user_id'],
self.user['token']) if self.user else (None, None)
return user_model
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)
def render_response(self, _template, **context):
ctx = {'user': self.user_model}
ctx.update(context)
rv = self.jinja2.render_template(_template, **ctx)
self.response.write(rv)
class SignupForm(Form):
email = TextField('Email',
[validators.Required(),
validators.Email()])
password = PasswordField('Password',
[validators.Required(),
validators.EqualTo('confirm_password',
message="Passwords must match.")])
password_confirm = PasswordField('Confirm Password',
[validators.Required()])
class SignupHandler(UserAwareHandler):
#Serves up a signup form, creates new users
def get(self):
self.render_response("templates/signup.html", form=SignupForm())
def post(self):
form = SignupForm(self.request.POST)
error = None
if form.validate():
success, info = self.auth.store.user_model.create_user(
"auth:" + form.email.data,
unique_properties=['email'],
email= form.password.data,
password_raw= form.password.data)
if success:
self.auth.get_user_by_password("auth:"+form.email.data,
form.password.data)
return self.redirect_to("index")
else:
error = "That email is already in use." if 'email'\
in user else "Something has gone horrible wrong."
self.render_response("templates/signup.html", form=form, error=error)
class LoginForm(Form):
email = TextField('Email',
[validators.Required(), validators.Email()])
password = PasswordField('Password',
[validators.Required()])
class LoginHandler(UserAwareHandler):
def get(self):
self.render_response("templates/index.html", form=LoginForm())
def post(self):
form = LoginForm(self.request.POST)
error = None
if form.validate():
try:
self.auth.get_user_by_password(
"auth:"+form.email.data,
form.password.data)
return self.redirect_to('secure')
except (auth.InvalidAuthIdError, auth.InvalidPasswordError):
error = "Invalid Email / Password"
self.render_response("templates/login.html", form=form, error=error)
class LogoutHandler(UserAwareHandler):
#Destroy the user session and return them to the login screen.
#login_required
def get(self):
self.auth.unset_session()
self.redirect_to('login')
class IndexHandler(UserAwareHandler):
def get(self):
ctx = {
'title1': "ALAZA",
'title2': "HOA",
'slogan': "A communication tool for the Alazan HOA.",
'message1': """
<p>The whole idea here is to show how to set up a simple static web site
on Google App Engine. I want to create an easy way to host your modest web
site on App Engine. My approach is dead simple. All I use is some boilerplate
code almost anyone can follow. You can have multiple pages and use template
variable features that are part of App Engine's WebApp Framework. Most modest
web sites don't do much more than this. Your certainly free to expand on what
you find here.</p>""",
}
self.render_response('templates/index.html', **ctx)
main.py:
import webapp2
import config
import routes
import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb
import webapp2_extras.appengine.auth.models as auth_models
class AwesomeUser(auth_models.User):
email = ndb.StringProperty()
webapp2_config = {}
webapp2_config['webapp2_extras.sessions'] = {
'secret_key': 'othello',}
webapp2_config['webapp2_extras.auth'] = {
'user_model': AwesomeUser,}
app = webapp2.WSGIApplication(config=config.webapp2_config)
routes.add_routes(app)
routes.py:
import handlers
import webapp2
from webapp2_extras.routes import RedirectRoute
# Using redirect route instead of simple routes since it supports strict_slash
# Simple route: http://webapp-improved.appspot.com/guide/routing.html#simple-routes
# RedirectRoute: http://webapp-improved.appspot.com/api/webapp2_extras/routes.html#webapp2_extras.routes.RedirectRoute
_routes = [
RedirectRoute('templates/login.html', handlers.LoginHandler, name='login'),
RedirectRoute('/templates/logout.html', handlers.LogoutHandler, name='logout'),
RedirectRoute('/templates/index.html', handlers.IndexHandler, name='index'),
RedirectRoute('/templates/signup.html', handlers.SignupHandler, name='signup'),]
def get_routes():
return _routes
def add_routes(app):
if app.debug:
secure_scheme = 'http'
for r in _routes:
app.router.add(r)
app.yaml:
application: alazan-hoa
version: main
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /js
static_dir: js
- url: /images
static_dir: images
- url: /css
static_dir: css
- url: /.*
script: main.app
libraries:
- name: webapp2
version: "2.5.1"
- name: jinja2
version: "2.6"
builtins:
- appstats: on
In your routes.py file, in the RedirectRoute you specify html files, while you should specify paths that are mapped to handler methods and inside them render the html templates.
For example, in your routes.py file you should have something like this:
_routes = [
RedirectRoute('/login', handlers.LoginHandler, name='login'),
RedirectRoute('/logout', handlers.LogoutHandler, name='logout'),
RedirectRoute('/index', handlers.IndexHandler, name='index'),
RedirectRoute('/signup', handlers.SignupHandler, name='signup')
]
You can take a look at Google App Engine Boilerplate for an introduction to Google App Engine development and best practices around it.
Hope this helps!

Cannot print data from database using the new version

I am using the latest version of web.py.
I am trying to print data from the database to a webpage.
The code i use is the following
import web
from google.appengine.ext import db
from models import *
urls = (
'/', 'index',
)
render = web.template.render('templates', base='base')
class index:
def GET(self):
votes = db.GqlQuery("SELECT * FROM votes")
return render.index(votes)
app = web.application(urls, globals())
main = app.cgirun()
the template is the following
$def with(votes)
$for vote in votes:
<li>$vote.status</li>
and i am getting this when i run it
[<models.votes object at 0x0000000004525F28>]
Is this a bug with the new version cause in previous version it works.
I forgot to say that i am compiling my templates as stated here.
It works on my machine, running the latest web.py 0.36 with this code:
main.py
import web
from google.appengine.ext import db
class Votes(db.Model):
status = db.StringProperty()
urls = (
'/', 'Index',
)
render = web.template.render('templates', base='base')
class Index:
def GET(self):
vote = Votes()
vote.status ="foo"
vote.put()
votes = db.GqlQuery("SELECT * FROM Votes")
return render.index(votes)
app = web.application(urls, globals())
main = app.cgirun()
templates/index.html
$def with(votes)
$for vote in votes:
<li>$vote.status</li>
templates/base.html
$def with (content)
<html>
<head>
</head>
<body>
$:content
</body>
</html>
this is the result:
foo
I don't use web.py; but maybe it doesn't support generators/iterables in the templates as expected. Try fetching the results first by changing your line to:
votes = db.GqlQuery("SELECT * FROM votes").fetch(100)

Resources