DEV Community

stellagress
stellagress

Posted on

Backend Server Up and Running with Python, Flask, and SQLAlchemy

Setting up the skeleton of a backend program might be confusing and tricky. In this guide, we'll clarify how to accomplish it by combining simple yet powerful tools — Python (version 3.8 for this demo), Flask, and SQLAlchemy in VS Code. After following the steps, you'll be able to create a GET API.

Step 1 - Environment Setup

a) Create a folder — recommended name 'server' — to represent the backend server part.

b) Inside the 'server' folder, create 'app.py,' 'models.py,' and 'seed.py' as a common structure for organizing your application code.

c) In the terminal, create and run a virtual environment to manage dependencies for your project by executing:

=> pipenv install & pipenv shell 
Enter fullscreen mode Exit fullscreen mode

d) Initialize the migration environment:

=> cd server
=> flask db init
Enter fullscreen mode Exit fullscreen mode

Step 2 - Adding Basic Information to app.py, models.py, and seed.py

a) models.py – This file is typically used to define the data models for your application, such as database tables (columns and relationships) when you're using an Object-Relational Mapping (ORM) library like SQLAlchemy. In this file, we should include following setup info:

# Import the SQLAlchemy extension for Flask
from flask_sqlalchemy import SQLAlchemy
# Import the MetaData class from SQLAlchemy to configure naming conventions
from sqlalchemy import MetaData

# Define a custom naming convention for foreign keys
metadata = MetaData(naming_convention={
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
})

# Initialize SQLAlchemy with the custom naming convention
db = SQLAlchemy(metadata=metadata)
Enter fullscreen mode Exit fullscreen mode

Also, we should include the columns with the desired attributes and relationship. In this case, one restaurant has multiple menus, and all menus belong to one restaurant, establishing a one to many relationship, continuing our models.py would look like this:

# Define the Restaurant model
class Restaurant(db.Model):
    # Define the name of the database table associated with this model
    __tablename__ = 'restaurants'

    # Define the 'id' column as an Integer primary key
    # This column is used to uniquely identify each restaurant
    id = db.Column(db.Integer, primary_key=True)

    # Define the 'name' column as a String with a maximum length of 255
    #characters
    # This column stores the name of the restaurant and is required
    # (nullable=False)
    name = db.Column(db.String(255), nullable=False)

    # Define a one-to-many relationship with the 'Menu' model
    # This 'menus' relationship establishes that each restaurant
    # can have multiple menus
    # The 'backref' parameter creates a reverse relationship in
    # the 'Menu' model
    menus = db.relationship('Menu', backref='restaurant')
# Constructor method for the Restaurant model
# Initializes a new Restaurant instance with a name
def __init__(self, name):
    # Assigns the provided 'name' to the 'name' attribute of the
    # Restaurant
    self.name = name


# Define the Menu model
class Menu(db.Model):
    # Define the name of the database table associated with this model
    __tablename__ = 'menus'

    # Define the 'id' column as an Integer primary key
    # This column is used to uniquely identify each menu
    id = db.Column(db.Integer, primary_key=True)

    # Define the 'name' column as a String
    # This column stores the name of the menu and is required
    name = db.Column(db.String, nullable=False)

    # Define as many columns as needed, for example, 'description'
    # of a food/drink in the menu
    description = db.Column(db.String, nullable=True)

    # Define the 'restaurant_id' column as an Integer foreign key
    # This column establishes a relationship with the 'id' column
    # of the 'Restaurant' model
    # It stores the ID of the restaurant to which this menu belongs
    restaurant_id = db.Column(db.Integer, db.ForeignKey('restaurants.id'), 
nullable=False)

    # Constructor method for the Menu model
    # Initializes a new Menu instance with a name and a restaurant ID
    def __init__(self, name, restaurant_id):
        # Assigns the provided 'name' to the 'name' attribute of the Menu
        self.name = name
        # Assigns the provided 'restaurant_id' to the 'restaurant_id'
        # attribute of the Menu
        self.restaurant_id = restaurant_id

Enter fullscreen mode Exit fullscreen mode

b) app.py: This is often the main entry point of a Flask application. It's where you create your Flask app instance, define routes, and configure the application to use the SQLAlchemy instance created in 'models.py'. Below is an example of what 'app.py' might look like:

from flask import Flask, jsonify
from models import db, Restaurant, Menu  # Import your SQLAlchemy models

app = Flask(__name__)

#Using SQLite for this example, but replace 'sqlite:///app.db’ with 
#the actual URL of your database engine such as PostgreSQL, MySQL,
#MongoDB, Microsoft SQL Server, etc… 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

# Initialize SQLAlchemy with the Flask app
db.init_app(app)

# Define routes and views here

# Example route to retrieve a list of menus
@app.route('/menus', methods=['GET'])
def get_menus():
    # Query the database to retrieve a list of menus
    menus = Menu.query.all()

    # Convert the menu objects to a JSON response
    menu_list = []
    for menu in menus:
        menu_list.append({
            'id': menu.id,
            'name': menu.name
'description': menu.description
        })

    # Return the JSON response containing the list of menus 
    # JSON response is commonly used and accepted by the client
    # (front end); however, a response might be sent in other 
    #formats such as XML or HTML, depending on how your data is
    # being handles in the front end as well
    return jsonify(menu_list)

if __name__ == '__main__':
    # This block ensures that the Flask application is only run when 
    #this script is executed as the main program,
    #and not when it's imported as a module in another script. 
    #Also, you can indicate port used – usually a 5 thousand 
    #number for server side. 
    app.run(port=5555, debug=True)`

Enter fullscreen mode Exit fullscreen mode

c) seed.py: This file may be used to populate your database with initial data, often referred to as "seeding" the database. It's not a standard Flask file, but it's a common practice among developers to create such a file especially for testing and debugging purposes. Seeding allows you to pre-fill your database with data for testing and development.

# Import necessary modules and the Flask app 
from app import app, db
# Import your SQLAlchemy models
from models import Restaurant, Menu

# Initialize the Flask app and SQLAlchemy within the app context
with app.app_context():
    # Create database tables if they don't exist
    db.create_all()

# Specify used engine
engine = create_engine('sqlite:///data.db')

# Delete seeded info, if needed:
print("Clearing db")
Menu.query.delete()
Restaurant.query.delete()

    # Seed the database with restaurant and menu data
    restaurants = [
        Restaurant(name="Restaurant A"),
        Restaurant(name="Restaurant B"),
        Restaurant(name="Restaurant C"),
    ]

    menus = [
        Menu(name="Menu 1", restaurant=restaurants[0]),
        Menu(name="Menu 2", restaurant=restaurants[0]),
        Menu(name="Menu 3", restaurant=restaurants[1]),
        Menu(name="Menu 4", restaurant=restaurants[2]),
        Menu(name="Menu 5", restaurant=restaurants[2]),
        Menu(name="Menu 6", restaurant=restaurants[2]),
        Menu(name="Menu 7", restaurant=restaurants[2]),
        Menu(name="Menu 8", restaurant=restaurants[2]),
        Menu(name="Menu 9", restaurant=restaurants[2]),
        Menu(name="Menu 10", restaurant=restaurants[2]),
    ]

    # Add the restaurant and menu data to the session
    for restaurant in restaurants:
        db.session.add(restaurant)

    for menu in menus:
        db.session.add(menu)

    # Commit the changes to the database
    db.session.commit()

# Print a success message
print("Database seeded successfully!")

Enter fullscreen mode Exit fullscreen mode

Step 3 - Running Your Application

To run your Flask application and populate the database with seed data, execute the following commands in your terminal inside server directory:

=> flask db upgrade
=> python seed.py
Enter fullscreen mode Exit fullscreen mode

Whenever the structure in 'models.py' is changed, run:

flask db revision --autogenerate -m'<your message>'
Enter fullscreen mode Exit fullscreen mode

Lastly, in order to start server, we run:

=>  python app.py
Enter fullscreen mode Exit fullscreen mode

Time to play! You can test your server using a tool like Postman by making GET requests to your defined routes in this example: as established in app.py as our route.

Top comments (0)