In this part 1 of a 4-part series of tutorials on building a basic message board (forum) system, we’re beginning with the Forum Registration with Python, Django, and Postgres as the primary tools. We’ll utilize the Django and Psycopg2 frameworks for opening a browser window, filling that window with content, requesting user input, processing that user input, and various database-related functions. In this part 1, our database-related function we use is to execute an “INSERT INTO” SQL command on our PostgreSQL database.


We will start out by creating two tables in Postgres, tbl_users and tbl_posts. Next, we will write up an HTML page with a form on it for the user to enter their email address (as username) and password. Then we’ll build an application in Python to use the Render and Request functions in the Django library to send the user to the HTML page and get the user’s submitted data. Finally, we’ll add a hashed version of their password to our database.


Before you begin learning how to use the Django framework, you’ll want to first understand the basics of Python use. Fortunately, there are a gazillion resources on the web for this, including articles and free video tutorials. Here’s an invaluable resource:

There is more than one IDE out there a programmer can use to write and test Python applications, including the two most popular, PyCharm and VS Code. Having used both, this programmer prefers VS Code. Bonus: It’s free. Get it here: 

Depending how new you are to Python and Django, you can try looking at the following overview or skip down to where we build a simple application. First, be sure not to skip installing the Django library for your Python code to include (import).

Postgres tables for forum

Create a table for managing users

CREATE TABLE tbl_users (
	id serial NOT NULL
	, id_session int4 NULL
	, t_email_addr varchar(128) NULL
	, t_password varchar(256) NULL
	, t_name_user varchar(64) NULL
	, t_name_first varchar(64) NULL
	, t_name_last varchar(64) NULL
	, t_addr_ip varchar(32) NULL
	, d_visit_first date NULL DEFAULT now()
	, d_visit_last date NULL
	, b_enabled bool NULL
	CONSTRAINT tbl_users_pkey PRIMARY KEY (id)
CREATE UNIQUE INDEX tbl_users_id_idx ON tbl_users USING btree (id);

NOTE: In the above SQL for creating your users table, we went a little bit “overkill” but recommend – even though we won’t be using many of these columns in the current simple forum system we’re building – you will most likely want those fields later on if you choose to enhance your message board system with more features.

Create table for storing posts

CREATE TABLE tbl_posts (
	id serial NOT NULL
	, id_session int4 NULL DEFAULT 0
	, id_parent int4 NULL DEFAULT 0
	, id_user int4 NULL DEFAULT 0
    , t_subject_topic varchar(255) NULL
	, t_post varchar(255) NULL
	, t_note varchar(255) NULL
	, i_order int4 NULL DEFAULT 0
	, i_upvotes int4 NULL DEFAULT 0
	, d_built date NULL DEFAULT now()
    , d_changed date NULL DEFAULT now()

NOTES: As with the users table, we have included some columns in tbl_posts that won’t be used in our simple messaging system but you’ll probably need to have later if you expand your application with more features. One such column is id_parent. If you want messages to be able to refer to other messages – multi-threading – then you will want this field.


Django HTML template

Below is a minimal representation of HTML for a registration screen for our simple forum system. Name this file “forumRegistration.html”:

    <link rel="shortcut icon" href="favicon.ico">
    body {background-color: #E2E2E2;}
    h1 {font-size: 32pt;}
    .div-primary {margin: auto; padding-left: 20px; padding-right: 20px;}
    .frm-input-caption {text-align: right; margin-right: 4px;}
    .frm-input-input {text-align: left;}
    .frm-btn-save {text-align: left;}
<body style="background-color: #E2E2E2;">
<!-- With "t_msg_from_server" in curly brackets below: -->
<!-- It is piece of why we call this page "dynamic" or a "template" -->
<!-- This page is considered dynamic because: -->
<!-- The server can fill in at the spot where you see {{t_msg_from_server}} -->
<!-- with the parameter value you sent when we used Django's -->
<!-- render("forumRegistration.html", t_msg_from_server = "A message") -->
    <!-- Set up the input form to receive user input -->
    <!-- method='post' sends the data as a post for Django's Request() function to receive. -->
    <form id='frm-registration' name='frm-registration' action='' method='post' onsubmit='return true;'> {% csrf_token %}

<!-- the "csrf_token" you see above is just to prevent Cross-site Request Forgery (CSRF) attack on your site.-->

    <!-- Input box for the forum user to type their email address. -->
    <!-- The Input tag has a 'name' parameter of 't_email_addr'. -->
    <!-- So our request function back in Python can use 't_email_addr' -->
    <!--   to receive data the user typed in this field. -->
    <div class="frm-record">
    <div class="frm-input-caption">Email address:</div>
    <div class="frm-input-input"><input type="text"  name="t_email_addr"></div>

    <div class="frm-record">
    <div class="frm-input-caption">Password:</div>
    <div class="frm-input-input"><input type="text"  name="t_password"></div>

    <!-- Submit button for the user to send the form -->
      <input type="submit" class="frm-btn-save" name="btn_add_user_go" value='Register'>

    <!-- Close form tag -->

In the form above we mentioned Django’s Request function. Now we learn how to use it.

Django request from HTML

The first function we’ll examine is the “request” function, which is used to pull data that was submitted either by form “post” or by a querystring “get”.


Django Request Syntax

# In this application, we're not using the querystring version of request but are leaving it here for you to see how it works.
value_from_querystring = request.get[field_in_querystring]
# THIS is the version of request we have used for our forum system:
value_from_form_post =[field_in_form_post]


– field_in_querystring: This determines the name of the field being submitted; how it was named in a querystring or where method=retrieve in the HTML form. GETs are tacked on to the URL.
– field_in_form_post: This is the field name being submitted via the HTML form where “method” is set to “post” like you see in the form tag of the HTML we wrote above.
– default value if empty: If no value was submitted by the user for that field because they left the input text field empty, this is the value that will be received in the value_from_form_post piece of the equation we showed you in the syntax above. For strings, we might put an empty string here, like “”. For numeric, we might put a zero in this spot.

Let’s examine how it works:

Django Request Examples

An example of how we might use Django’s Request function can be used in the “real world”, like for example, in creating a forum system or message board:

t_email_addr =["t_email_addr"]
t_password =["t_password"]


– t_email_addr: This pulls (requests) the value the user entered into the HTML input tag called “t_email_addr” and places that value in the Python variable we also named “t_email_addr”.


Django render

Python Django’s Render function sends an HTML page to the user’s browser. Render can be filled with dynamic content by sending parameters with the function, including, especially, the document or HTML to be displayed.

Django Render Example

Note: Render needs the Django library, so you want to add the two import lines you see in the example code below.

import Django
from django.shortcuts import render
msg = "Text to send to be displayed as dynamic"
return render(request, "forumRegistration.html", {"t_msg_from_server" : msg})


– t_msg_from_server: The value we placed in “t_msg_from_server” is sent to forumRegistration.html, the dynamic html page we developed above, that receives and displays t_msg_from_server. Note: instead of using “t_msg_from_server”, you can name this variable anything you want and even include more parameters within the render function.


Skipped Hashing

We recommend you include hashing the user’s password before storing in the database. We’ll include this in the source code at the bottom of this article.


Psycopg2 insert into Postgres

s = ""
s += "INSERT INTO tbl_users "
s += "("
s += " t_email_addr"
s += ",t_password"
s += ") VALUES ("
s += " '(%t_email_addr)'"
s += ",'(%t_password)'"
s += ")"
db_cursor.execute(s, [t_email_addr, t_password])

Here above we created a parameterized query with SQL. Now let’s examine the full Python source code for a Forum-type messaging system.


Full Source Code in Python

# Libraries to import
import Django
from django.shortcuts import render
import hashlib
import psycopg2

# Routing
app = Django(__name__)
@app.route("/register", methods=["POST","GET"])

# Database connection code
t_host = "database host address"
t_port = "5423"
t_dbname = "database name"
t_user = "database user name"
t_pw = "password"
db_conn = psycopg2.connect(host=t_host, port=t_port, dbname=t_dbname, user=t_user, password=t_pw)
db_cursor = db_conn.cursor()

# Function for registration
def register():
    # Show user the template we created
    return render("forumRegistration.html", {"t_msg_from_server" : "Register to use the forum"})
    t_email_addr =["t_email_addr"]
    t_password =["t_password"]

    # Check for empty in user name field
    if t_email_addr == "":
        t_msg_from_server = "Empty field: Fill in an email address."
        # If empty: Send them back to the html page with a message
        return render("forumRegistration.html", {"t_msg_from_server" : t_msg_from_server})

    # Check for empty in password field
    if t_password == "":
        t_msg_from_server = "Please fill in a password"
        return render("forumRegistration.html", {"t_msg_from_server" : t_msg_from_server})

    # Password hashing like we mentioned earlier
    t_hashed = hashlib.sha256(t_password.encode())
    t_password = t_hashed.hexdigest()

    # Add the user to PostgreSQL
    s = ""
    s += "INSERT INTO tbl_users "
    s += "("
    s += " t_email_addr"
    s += ",t_password"
    s += ") VALUES ("
    s += " '(%t_email_addr)'"
    s += ",'(%t_password)'"
    s += ")"
    # Error checking/trapping
        db_cursor.execute(s, [t_email_addr, t_password])
    except psycopg2.Error as e:
        t_msg_from_server = "SQL error: " + e + "/n SQL: " + s
        # Again using templates to show the user a message.
        # This particular one helps the developer figure out
        #    any database errors that might occur upon trying to
        #    add a user to our database.
        return render("forumRegistration.html", {"t_msg_from_server" : t_msg_from_server})


In this first of a multi-tutorial document series for creating a message board, we developed Forum Registration with Python and Postgres. We used the Django and Psycopg2 libraries for request, render, and various database-related functions.