Form handling, databases, and ReplAuth in Flask

Continuing the discussion from F-Flask? app route? app.run? What… What yuu need 2 know about flask and Python Flask Jinja Templating:

In order to make an actual Flask app with users, data, and other stuff, you need to use forms (you can use the fetch API but that’s super advanced), and databases. This will show you how to do it.

Databases

If you’ve used Python before, you’ve probably heard of ReplDB. In a text-based (console) Repl, each database is unique to each user and cannot be shared without using a ReplDB proxy.

However, in a website Repl, the ReplDB is the same database for every user using the website. This means that you can save content and have interactions between users using the database.

The best way to set up a database if you have data per user is to create a key in the database (or in a dictionary in the database) for each user in your app. Here’s an example.

from replit import db, ...
from flask import Flask, request, ...

# db["users"] is set to either the value of db["users"] if it exists or a new empty dict
db["users"] = db.get("users", {})
@app.route("/signup", methods=["GET", "POST"])
def signup():
  if request.method = "GET":
    ...
  elif request.method = "POST":
    db["users"][request.form["username"]] = {...}

The above example uses form handling techniques to set a key in the db["users"] dict.

Users and ReplAuth

Well, now, how do we authenticate the users? The answer: we don’t. We use a special tool called ReplAuth to help us. If you’ve used HTML/CSS/JS before, you might know about ReplAuth. Does this screen seem familiar?

There are two ways of using ReplAuth in Flask: replit.web, or a JavaScript script.

Method 1: replit.web

The first way to do ReplAuth is using replit.web. Here’s how:

from replit import web, ...
from flask import Flask, ...

app = Flask(...)

@app.route(...)
@web.authenticated # This is how we specify that a user must be logged in to access this page.
def my_page():
  return f"You are logged in as {web.auth.name}"

web.auth.name specifies the username of the currently .logged in user.
@web.authenticated is a decorator that specifies that a user must be logged in to access the page.

Method 2: Client-side script

There is a script that adds ReplAuth functionality to your webpage and allows you to access ReplAuth data from the server side using HTTP headers.

You can import the script by adding this <script> tag in your HTML:

<script src="https://replit.com/public/js/repl-auth.js"></script>

This will add a button to your page asking the user to login with replit. It is good for customizable login pages.

ReplAuth HTTP Headers

Here is a list of the available HTTP headers for ReplAuth:
Note: These headers will only be available if the user is logged in

  • X-Replit-User-Name: The username of the logged-in user.
  • X-Replit-User-Id: The ID of the logged-in user.
  • X-Replit-User-Bio: The bio of the logged-in user.
  • X-Replit-User-Roles: A list of the roles belonging to the logged-in user.
  • X-Replit-User-Profile-Image: The URL of the PFP of the logged-in user.
  • X-Replit-User-Teams: A list of the teams the logged-in user is in.
  • X-Replit-User-Url: The URL of the logged-in user’s Replit profile.

Form handling

Now for the last one: form handling! Form handling is how we send user data from the client to the server using a form.

Here’s a simple example of using a form:

from flask import Flask, request, render_template
...

app = Flask(__name__)

@app.route('/', methods=["GET"])
def my_form():
 return render_template("form.html")

@app.route('/', methods=["POST"])
def process_form():
  form = request.form
  ...

And in templates/form.html:

<!DOCTYPE html>
<html>
  <head>...</head>
  <body>
    <form method="post">
       ...
       <button type="submit">Submit Form</button>
    </form>
  </body>
</html>

When the user clicks the Submit Form button, the form will be submitted and the data inputted by the user will be sent to the server.

After the data is sent to the server, it is available in the request.form dictionary.

Example: Using ReplAuth, ReplDB, and Flask form handling for an app that allows you to put a message in a database.

main.py:

from flask import Flask, request, render_template
from replit import db, web

if "messages" not in db.keys():
  db["messages"] = []

app = Flask(__name__)

@app.route('/', methods=["GET"])
@web.authenticated
def my_form():
  return render_template("form.html")

@app.route('/', methods=["POST"])
@web.authenticated
def handle_form():
  db["messages"].append({
    "user": web.auth.name,
    "message": request.form["message"]
  })

templates/form.html:

<!DOCTYPE html>
<html>
  <head>
     <title>Messages</title>
  </head>
  <body>
     <form method="post">
        <textarea name="message"></textarea>
        <button type="submit">Submit Form</button>
     </form>
  </body>
</html>
2 Likes

Better method:

# db["users"] is set to either the value of db["users"] if it exists or a new empty dict
db["users"] = db.get("users", {})
1 Like