Skip to content

Commit

Permalink
simple app with SQL
Browse files Browse the repository at this point in the history
  • Loading branch information
ramuta committed Oct 14, 2019
1 parent 13e5b42 commit f9759d2
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -1,3 +1,7 @@
localhost.sqlite
*.sqlite
*.db

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -36,7 +36,7 @@ If you'll use Datastore or Firestore, you'll need to install one of these (or bo
- **[simple-app-datastore-tests](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/simple-app-datastore-tests)**: Flask app with Datastore and tests (pytest).
- **[simple-app-firestore](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/simple-app-firestore)**: Flask app with the Firestore database.
- **[simple-app-firestore-tests](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/simple-app-firestore-tests)**: Flask app with Firestore + tests.
- **simple-app-sql**
- **[simple-app-sql](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/simple-app-sql)**: A simple Flask app with an SQL database (localhost: SQLite; Google Cloud: PostgreSQL).
- **simple-app-sql-tests**
- **[structured-app-firestore](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/structured-app-firestore)**: A structured Flask app with Firestore + tests. Gives you an idea how to structure your web app.
- **[structured-app-ndb](https://github.com/smartninja/gae-2nd-gen-examples/tree/master/structured-app-ndb)**: An example using the new ndb library for Python 3 GAE runtime.
Expand Down
2 changes: 1 addition & 1 deletion simple-app-firestore/templates/index.html
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple GAE app with Datastore example</title>
<title>Simple GAE app with Firestore example</title>

<link rel="stylesheet" href="/static/css/style.css">
</head>
Expand Down
25 changes: 25 additions & 0 deletions simple-app-sql/.gcloudignore
@@ -0,0 +1,25 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore

# Python pycache:
__pycache__/
# Ignored by the build system
/setup.cfg

# custom
env.yaml
WEB-INF/
.pytest_cache/
venv/
129 changes: 129 additions & 0 deletions simple-app-sql/.gitignore
@@ -0,0 +1,129 @@
# Datastore Emulator
WEB-INF/
env.yaml
localhost.sqlite

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
43 changes: 43 additions & 0 deletions simple-app-sql/README.md
@@ -0,0 +1,43 @@
# Simple GAE app with an SQL database

A simple 2nd generation GAE web app made with Python 3 and Flask using an SQL database.

## Preview

![](static/img/preview.png)

## Requirements

Install the necessary libraries using this command:

pip install -r requirements.txt

Using a virtual environment is strongly encouraged!

## Run the web app

> Assuming you use the PyCharm IDE.
Right-click on `run.py` and select `Run 'run'`. Your web app will now be accessible via `localhost:8080`.

Every time you'll change a Python file, your web app will auto-reload. But it won't auto-reload on non-Python files
changes. In that case just make a minor edit (like adding a space) in some Python file to force auto-reload.

## Shut down the web app

To **shut down** the web app click the **red square icon** below the reload button.

## Deployment to GAE

See [these instructions](https://github.com/smartninja/gae-2nd-gen-examples#deployment-to-google-app-engine).

## Useful links

- [Using Cloud SQL on GAE with Python 3](https://cloud.google.com/appengine/docs/standard/python3/using-cloud-sql)

## Issues

Please [create a new issue](https://github.com/smartninja/gae-2nd-gen-examples/issues/new) in case there's some bug or
something should be improved.

Happy to receive pull requests, too! :)
7 changes: 7 additions & 0 deletions simple-app-sql/app.yaml
@@ -0,0 +1,7 @@
runtime: python37

handlers:
- url: /static
static_dir: static
- url: /.*
script: auto
53 changes: 53 additions & 0 deletions simple-app-sql/main.py
@@ -0,0 +1,53 @@
import os
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# determine the database URL
db_user = os.environ.get('CLOUD_SQL_USERNAME')
db_password = os.environ.get('CLOUD_SQL_PASSWORD')
db_name = os.environ.get('CLOUD_SQL_DATABASE_NAME')
db_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME')

if db_user and db_password and db_name and db_connection_name: # if on google cloud, connect to PostgreSQL
sqla_db_uri = f"postgresql://{db_user}:{db_password}@/{db_name}?host=/cloudsql/{db_connection_name}"
else: # if on localhost, use SQLite
sqla_db_uri = "sqlite:///localhost.sqlite"

app.config['SQLALCHEMY_DATABASE_URI'] = sqla_db_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.Text, nullable=False)

def __repr__(self):
return '<Message %r>' % self.title


# create all tables in the database
db.create_all()


@app.route("/", methods=["GET", "POST"])
def index():
# get all messages from the db
messages = db.session.query(Message).all()

if request.method == "POST":
# create a new message
message = Message(text=request.form.get("message"))
db.session.add(message)
db.session.commit()

return render_template("index.html", messages=messages)


if __name__ == '__main__':
if os.getenv('GAE_ENV', '').startswith('standard'):
app.run() # production
else:
app.run(port=8080, host="localhost") # localhost
2 changes: 2 additions & 0 deletions simple-app-sql/requirements.txt
@@ -0,0 +1,2 @@
Flask
Flask-SQLAlchemy
9 changes: 9 additions & 0 deletions simple-app-sql/run.py
@@ -0,0 +1,9 @@
import os

main_command = "export FLASK_APP=main.py && flask run --host localhost --port 8080 --reload"

# Run the main command, which is either the web app, or pytest
run_main_command = os.popen(main_command)

# Print process output in the Terminal
print(run_main_command.read())
3 changes: 3 additions & 0 deletions simple-app-sql/static/css/style.css
@@ -0,0 +1,3 @@
.red {
color: red;
}
Binary file added simple-app-sql/static/img/preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions simple-app-sql/templates/index.html
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple GAE app with SQL example</title>

<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<h1>Simple GAE app with SQL example</h1>

<p>
Enter your message:

<form method="post" action="/">
<input type="text" name="message">
<button type="submit">Submit</button>
</form>
</p>

{% for item in messages %}
<p>{{ item.text }} <small><em>(message ID: {{item.id}})</em></small></p>
{% endfor %}

</body>
</html>

0 comments on commit f9759d2

Please sign in to comment.