article

Saturday, January 28, 2023

FastAPI CRUD (Create, Read, Update and Delete) with sqlalchemy Jinja2 Template

FastAPI CRUD (Create, Read, Update and Delete) with sqlalchemy Jinja2 Template

Install Fastapi

https://github.com/tiangolo/fastapi

pip install fastapi
C:\fastAPI\myapp>pip install fastapi
C:\fastAPI\myapp>pip install "uvicorn[standard]"

Install sqlalchemy jinja2
pip install python-multipart sqlalchemy jinja2
C:\fastAPI\myapp>pip install python-multipart sqlalchemy jinja2

Create main.py
crud/main.py
 
#crud/main.py
from fastapi import FastAPI, Request, Depends, Form, status
from fastapi.templating import Jinja2Templates
import models
from database import engine, sessionlocal
from sqlalchemy.orm import Session
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles

models.Base.metadata.create_all(bind=engine)

templates = Jinja2Templates(directory="templates")

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")

def get_db():
    db = sessionlocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/")
async def home(request: Request, db: Session = Depends(get_db)):
    users = db.query(models.User).order_by(models.User.id.desc())
    return templates.TemplateResponse("index.html", {"request": request, "users": users})

@app.post("/add")
async def add(request: Request, name: str = Form(...), position: str = Form(...), office: str = Form(...), db: Session = Depends(get_db)):
    print(name)
    print(position)
    print(office)
    users = models.User(name=name, position=position, office=office)
    db.add(users)
    db.commit()
    return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)

@app.get("/addnew")
async def addnew(request: Request):
    return templates.TemplateResponse("addnew.html", {"request": request})

@app.get("/edit/{user_id}")
async def edit(request: Request, user_id: int, db: Session = Depends(get_db)):
    user = db.query(models.User).filter(models.User.id == user_id).first()
    return templates.TemplateResponse("edit.html", {"request": request, "user": user})

@app.post("/update/{user_id}")
async def update(request: Request, user_id: int, name: str = Form(...), position: str = Form(...), office: str = Form(...), db: Session = Depends(get_db)):
    users = db.query(models.User).filter(models.User.id == user_id).first()
    users.name = name
    users.position = position
    users.office = office
    db.commit()
    return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)

@app.get("/delete/{user_id}")
async def delete(request: Request, user_id: int, db: Session = Depends(get_db)):
    users = db.query(models.User).filter(models.User.id == user_id).first()
    db.delete(users)
    db.commit()
    return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)
crud/database.py
 
#crud/database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

DB_URL = 'sqlite:///fastapidb.sqlite3'

engine = create_engine(DB_URL, connect_args={'check_same_thread': False})
sessionlocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
crud/models.py
 
#crud/models.py
from sqlalchemy import Column, Integer, String
from database import Base

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(150))
    position = Column(String(150))
    office = Column(String(150))

    def __repr__(self):
        return '<User %r>' % (self.id)
make templates inside the templates directory

Bootstrap 5
https://getbootstrap.com/docs/5.0/getting-started/introduction/
https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css
crud/templates/base.html
//crud/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FastAPI CRUD (Create, Read, Update and Delete) with sqlalchemy Jinja2 Template - Cairocoders</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}">
</head>
<body>
<div class="container">
    <h1 class="page-header text-center">FastAPI CRUD (Create, Read, Update and Delete) with sqlalchemy Jinja2 Template</h1>
    {% block content %}
        
    {% endblock content %}
</div>
</body>
</html>	
crud/templates/index.html
//crud/templates/index.html
{% extends 'base.html' %}

{% block content %}
<div class="row">
	<div class="col-12">
		<a href="addnew/" class="btn btn-primary">Add New</a>
		<br><br>
		<table class="table table-bordered table-striped">
			<thead>
				<tr>
					<th>ID</th>
					<th>Name</th>
					<th>Position</th>
					<th>Office</th>
					<th width="200">Action</th>
				</tr>
			</thead>
			<tbody>
				{% for rs in users %}
					<tr>
						<td>{{ rs.id }}</td>
						<td>{{ rs.name }}</td>
						<td>{{ rs.position }}</td>
						<td>{{ rs.office }}</td>
						<td>
							<a href="edit/{{ rs.id }}" class="btn btn-success">Edit</a> | <a href="delete/{{ rs.id }}" class="btn btn-danger">Delete</a>  
						</td>
					</tr>
				{% endfor %}	
			</tbody>
		</table>
	</div>
</div>

{% endblock content %}
crud/templates/addnew.html
//crud/templates/addnew.html
{% extends 'base.html' %}

{% block content %}
<form action = "/add" method = "post"> 
    <div class="mb-3">
        <label>Name</label>
        <input type = "text" name = "name" placeholder = "Name" class="form-control" />
    </div> 
    <div class="mb-3">
        <label>Position</label>
        <input type = "text" name = "position" placeholder = "position" class="form-control" />
    </div> 
    <div class="mb-3">
        <label>Office</label>
        <input type = "text" name = "office" placeholder = "office" class="form-control" />
    </div> 

    <input type = "submit" value = "Submit" class="btn btn-primary mb-3"/>  
 </form> 
 
{% endblock content %}
crud/templates/edit.html
//crud/templates/edit.html
{% extends 'base.html' %}

{% block content %}
    <form action="/update/{{user.id}}" method="post">
        <div class="mb-3">
            <label>Name</label>
            <input type = "text" name = "name" placeholder = "Name" class="form-control" value="{{user.name}}"/>
        </div> 
        <div class="mb-3">
            <label>Position</label>
            <input type = "text" name = "position" placeholder = "position" class="form-control" value="{{user.position}}"/>
        </div> 
        <div class="mb-3">
            <label>Office</label>
            <input type = "text" name = "office" placeholder = "office" class="form-control" value="{{user.office}}"/>
        </div> 
    
        <input type = "submit" value = "Update" class="btn btn-primary mb-3"/>  
     </form> 
{% endblock content %}
run the FastAPI app

C:\fastAPI\myapp>uvicorn main:app --reload

with uvicorn using the file_name:app_instance
open the link on the browser http://127.0.0.1:8000/
http://127.0.0.1:8000/docs

Related Post