MOBI BOOT CAMP CORP. logoLearning Buddy
  • SIGN IN
  • Introduction
  • Namespace and Scope
  • The Class
  • Context Managers
  • Inheritance
  • Modules and Packages
  • Virtual Environment
  • Flask
  • Handling Forms with Flask-WTF
  • Jinja
  • Structuring a Flask App
  • Intro to Datastore
  • Intro to AppEngine
  • Flask on App Engine
  • Dash
  • Deploying a Dash App
  • MS Sql Server on Docker

Flask on Google's App Engine

You can deploy your Flask app on Google's App Engine environment. In this short lesson you will learn how to get that done.

Define app.yaml file

Go to the root folder of your Flask project and create an app.yaml file. This file contains all the configuration information of your app engine project and is the project's deployment descriptor. Here is an example app.yaml file:

runtime: python39  # or any other supported version

handlers:
  - url: /static
    static_dir: static
  - url: /.*
    script: auto

Security Best Practices: Handling Secrets

A critical rule in web development is never hardcode secret information (like API keys, database passwords, or your Flask SECRET_KEY) directly in your code.

Why is hardcoding bad?

  • Security Risk: If you share your code or check it into version control (like Git), your secrets are exposed.
  • Inflexible: You have to change your code to switch between development and production environments.

The Solution: Environment Variables

The standard solution is to store secrets in environment variables. Your application can then read these variables from the operating system at runtime.

For example, to set your Flask SECRET_KEY (which is required for things like Flask-WTF), you would:

  1. Set the variable in your terminal (before running your app):
    export SECRET_KEY='some-very-secret-and-random-string'
    
  2. Access it in your code (using Python's os module):
    import os
    app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
    

This is the same principle used for the GOOGLE_APPLICATION_CREDENTIALS file path, which should also be set as an environment variable.

Example CRUD Application with Datastore

Below is an expanded example that demonstrates full CRUD (Create, Read, Delete) functionality.

The Python Code (main.py)

This code adds a root route / to list all comments and a /delete route to remove a comment.

import os
import datetime
from flask import Flask, render_template, request, redirect, url_for
from google.cloud import datastore

app = Flask(__name__)
# Set the secret key from an environment variable
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-secret-key-for-dev')

datastore_client = datastore.Client()

def get_all_comments():
    """Returns a list of all comments, ordered by date."""
    query = datastore_client.query(kind='comment')
    query.order = ['-date']
    comments = list(query.fetch())
    return comments

@app.route('/')
def root():
    comments = get_all_comments()
    return render_template('index.html', comments=comments)

@app.route('/submit', methods=['POST'])
def submit_form():
    name = request.form['name']
    email = request.form['email']
    comment_text = request.form['comment_text']

    entity = datastore.Entity(key=datastore_client.key('comment'))
    entity.update({
        'name': name,
        'email': email,
        'comment_text': comment_text,
        'date': datetime.datetime.utcnow()
    })

    datastore_client.put(entity)
    return redirect(url_for('root'))

@app.route('/delete/<int:comment_id>')
def delete_comment(comment_id):
    key = datastore_client.key('comment', comment_id)
    datastore_client.delete(key)
    return redirect(url_for('root'))

if __name__ == "__main__":
    app.run(debug=True)

The Templates

You will need a new index.html to list the comments and a form.

templates/index.html

<!doctype html>
<html>
<head>
    <title>Comment Wall</title>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <h1>Leave a Comment</h1>
    <form method="post" action="{{ url_for('submit_form') }}">
        <label for="name">Name:</label><br>
        <input type="text" name="name"><br><br>
        
        <label for="email">Email:</label><br>
        <input type="email" name="email"><br><br>
        
        <label for="comment_text">Comment:</label><br>
        <textarea name="comment_text" rows="4" cols="50"></textarea><br><br>
        
        <input type="submit" value="Submit">
    </form>

    <hr>

    <h2>Comments</h2>
    {% for comment in comments %}
      <div class="comment">
        <p>
          <strong>{{ comment['name'] }}</strong> ({{ comment['email'] }})
          <span class="date">{{ comment['date'].strftime('%Y-%m-%d %H:%M') }}</span>
        </p>
        <p>{{ comment['comment_text'] }}</p>
        <a href="{{ url_for('delete_comment', comment_id=comment.key.id) }}">Delete</a>
      </div>
    {% else %}
      <p>No comments yet. Be the first!</p>
    {% endfor %}
</body>
</html>

This new example provides a much more complete and realistic view of how a web application interacts with a database.

Privacy Policy | Terms & Conditions