article

Showing posts with label Python-FastAPI. Show all posts
Showing posts with label Python-FastAPI. Show all posts

Friday, March 24, 2023

FastAPI jwt token authentication with sqlite

FastAPI jwt token authentication with sqlite

Install Fastapi

https://github.com/tiangolo/fastapi

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


Create main.py
fastapi-jwt/main.py
 
#fastapi-jwt/main.py
from typing import List
import fastapi as _fastapi
import fastapi.security as _security

import sqlalchemy.orm as _orm

import services as _services, schemas as _schemas

app = _fastapi.FastAPI()

@app.post("/api/users")
async def create_user(
    user: _schemas.UserCreate, db: _orm.Session = _fastapi.Depends(_services.get_db)
):
    db_user = await _services.get_user_by_email(user.email, db)
    if db_user:
        raise _fastapi.HTTPException(status_code=400, detail="Email already in use")

    user = await _services.create_user(user, db)

    return await _services.create_token(user)


@app.post("/api/token")
async def generate_token(
    form_data: _security.OAuth2PasswordRequestForm = _fastapi.Depends(),
    db: _orm.Session = _fastapi.Depends(_services.get_db),
):
    user = await _services.authenticate_user(form_data.username, form_data.password, db)

    if not user:
        raise _fastapi.HTTPException(status_code=401, detail="Invalid Credentials")

    return await _services.create_token(user)


@app.get("/api/users/myprofile", response_model=_schemas.User)
async def get_user(user: _schemas.User = _fastapi.Depends(_services.get_current_user)):
    return user
install python-jwt
https://pypi.org/project/python-jwt/

pip install python_jwt
C:\fastAPI\react>pip install python_jwt

fastapi-jwt/services.py
 
#fastapi-jwt/services.py
import fastapi as _fastapi
import fastapi.security as _security
import jwt as _jwt #pip install python_jwt https://pypi.org/project/python-jwt/
import datetime as _dt
import sqlalchemy.orm as _orm
import passlib.hash as _hash

import database as _database, models as _models, schemas as _schemas

oauth2schema = _security.OAuth2PasswordBearer(tokenUrl="/api/token")

JWT_SECRET = "cairocodersednalan"

def create_database():
    return _database.Base.metadata.create_all(bind=_database.engine)

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

async def get_user_by_email(email: str, db: _orm.Session):
    return db.query(_models.User).filter(_models.User.email == email).first()

async def create_user(user: _schemas.UserCreate, db: _orm.Session):
    user_obj = _models.User(
        email=user.email, hashed_password=_hash.bcrypt.hash(user.hashed_password)
    )
    db.add(user_obj)
    db.commit()
    db.refresh(user_obj)
    return user_obj

async def authenticate_user(email: str, password: str, db: _orm.Session):
    user = await get_user_by_email(db=db, email=email)

    if not user:
        return False
    if not user.verify_password(password):
        return False
    return user


async def create_token(user: _models.User):
    user_obj = _schemas.User.from_orm(user)

    token = _jwt.encode(user_obj.dict(), JWT_SECRET)

    return dict(access_token=token, token_type="bearer")

async def get_current_user(
    db: _orm.Session = _fastapi.Depends(get_db),
    token: str = _fastapi.Depends(oauth2schema),
):
    try:
        payload = _jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
        user = db.query(_models.User).get(payload["id"])
    except:
        raise _fastapi.HTTPException(
            status_code=401, detail="Invalid Email or Password"
        )

    return _schemas.User.from_orm(user)
fastapi-jwt/database.py
 
#fastapi-jwt/database.py
import sqlalchemy as _sql
import sqlalchemy.ext.declarative as _declarative
import sqlalchemy.orm as _orm

DATABASE_URL = "sqlite:///./database.db"

engine = _sql.create_engine(DATABASE_URL, connect_args={"check_same_thread": False})

SessionLocal = _orm.sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = _declarative.declarative_base()
fastapi-jwt/models.py
 
#fastapi-jwt/models.py
import datetime as _dt

import sqlalchemy as _sql
import sqlalchemy.orm as _orm
import passlib.hash as _hash

import database as _database

class User(_database.Base):
    __tablename__ = "users"
    id = _sql.Column(_sql.Integer, primary_key=True, index=True)
    email = _sql.Column(_sql.String, unique=True, index=True)
    hashed_password = _sql.Column(_sql.String)

    def verify_password(self, password: str):
        return _hash.bcrypt.verify(password, self.hashed_password)
fastapi-jwt/schemas.py
 
#fastapi-jwt/schemas.py
import datetime as _dt

import pydantic as _pydantic

class _UserBase(_pydantic.BaseModel):
    email: str

class UserCreate(_UserBase):
    hashed_password: str

    class Config:
        orm_mode = True

class User(_UserBase):
    id: int

    class Config:
        orm_mode = True
Run C:\fastAPI\fastapi-jwt>uvicorn main:app --reload

http://127.0.0.1:8000/docs

Tuesday, March 21, 2023

React and FastAPI Login with PyJWT token authentication

React and FastAPI Login with PyJWT token authentication

Install Fastapi

https://github.com/tiangolo/fastapi

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


Create main.py
react/main.py
 
#react/main.py
from fastapi import FastAPI
import jwt #pip install pyjwt https://pypi.org/project/PyJWT/
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder

SECRET_KEY = "cairocoders123456789"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 800

dummy_user = {
    "username": "cairocoders",
    "password": "123456ednalan",
}

from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_methods=["*"],
    allow_headers=["*"],
    allow_credentials=True,
    allow_origins=["http://localhost:3000"])

class Loginclass(BaseModel):
    username: str
    password: str
@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.post("/login")
async def login_user(login_item: Loginclass):
    data = jsonable_encoder(login_item)
    if dummy_user['username'] == data['username'] and dummy_user['password'] == data['password']:
        encoded_jwt = jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
        return {'token': encoded_jwt }
    else:
        return {'message': 'Login failed'}
install PyJWT
https://github.com/jpadilla/pyjwt

pip install PyJWT
C:\fastAPI\react>pip install PyJWT

Rn C:\fastAPI\react>uvicorn main:app --reload 

http://127.0.0.1:8000/docs

React JS
Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start

Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { } from 'react';
import './App.css';

import {BrowserRouter, Routes, Route, Link} from 'react-router-dom';

import Login from './components/Login.js'
import Profile from './components/Profile.js'
import {RequireToken} from './components/Auth.js'

function App() {
  return (
    <div className="vh-100 gradient-custom">
    <div className="container">
      <h1 className="page-header text-center">React and FastAPI Login with PyJWT token authentication</h1>
 
      <BrowserRouter>
        <p><Link to="/" className="btn btn-success">Login</Link> | <Link to="profile" className="btn btn-success">Profile</Link> </p>
 
        <Routes>
			<Route path="/" element={<Login />} />
			<Route
			  path="/profile"
			  element={
				<RequireToken>
				  <Profile />
				</RequireToken>
			  }
			/>
        </Routes>
      </BrowserRouter>
    </div>
    </div>
  );
}
 
export default App;
open index.html C:\react-js\myreactdev\public\index.html add bootstrap 5 <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
Login.js
C:\react-js\myreactdev\src\components\Login.js
//C:\react-js\myreactdev\src\components\Login.js
import React, { useState } from 'react';
import axios from 'axios';
import {useNavigate} from "react-router-dom";
import {setToken, fetchToken} from './Auth.js'

export default function Login(){
	const navigate = useNavigate();
	const [username,setUsername] = useState('');
	const [password,setPassword] = useState('');
 
	const handleSubmit = () => {
		if(username.length === 0){
		  alert("Username has left Blank!");
		}
		else if(password.length === 0){
		  alert("password has left Blank!");
		}
		else{
			console.log('axios')
			axios.post('http://localhost:8000/login', {
				username: username,
				password: password
			})
			.then(function (response) {
				console.log(response);
				//console.log(response.data);
				alert(response.data["message"])
				if (response.data["message"]=="Login failed") {
					alert("Login failed");
				}else {	
					if(response.data.token){
						setToken(response.data.token)
						navigate("/profile");
					}
				}
			})
			.catch(function (error) {
				console.log(error, 'error');
			});
		}
	}
  return (
    <div>
      <div className="mask d-flex align-items-center h-100 gradient-custom-3">
        <div className="container h-100">
            <div className="row d-flex justify-content-center align-items-center h-100">
            <div className="col-12 col-md-9 col-lg-7 col-xl-6">
            <div className="card">
              <div className="card-body p-5">
			  {
                fetchToken() 
                ? (
                    <p>You are logged in!</p>
                )
				: (
					<p>Login Account!</p>
				)
			  }	
                <form>
                  
				  <div className="form-outline mb-4">
                    <label className="form-label">Your User Name</label>
                    <input type="text" className="form-control form-control-lg" name="username" id="username" value={username} onChange={(e) => setUsername(e.target.value)} />
                  </div>
				  
                  <div className="form-outline mb-4">
                    <label className="form-label">Your Password</label>
                    <input type="text" className="form-control form-control-lg" name="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} />
                  </div>
				  

                  <div className="d-flex justify-content-center">
                  <input type="button" className="btn btn-success btn-lg" name="submit" id="submit" value="Login" onClick={handleSubmit} />
                  </div>
 
                </form>
            </div>
            </div>
            </div>
            </div>
        </div>
      </div>
    </div>
  );
}
Profile.js
C:\react-js\myreactdev\src\components\Profile.js
//C:\react-js\myreactdev\src\components\Profile.js
import React, { } from "react";
import {useNavigate} from "react-router-dom";

export default function Profile(){
    const navigate = useNavigate();
    const signOut = () => {
        localStorage.removeItem('cairocodersToken')
        navigate("/");
    }
    return(
        <>
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Profile Page</h1>
                <p>Hi, this is your profile</p>
                <div>
                    <button type = 'button' className="btn btn-success btn-lg" onClick= {signOut}>Sign Out</button>
                </div>
            </div>
            
        </>
    )
}
Auth.js
C:\react-js\myreactdev\src\components\Auth.js
//C:\react-js\myreactdev\src\components\Auth.js
import React, { } from "react";

import {
    Navigate ,
    useLocation
  } from "react-router-dom";
export const setToken = (token) =>{
    // set token in localStorage
    localStorage.setItem('cairocodersToken', token)
}
export const fetchToken = (token) =>{
    // fetch the token
    return localStorage.getItem('cairocodersToken')
}
export function RequireToken({children}) {
    
    let auth = fetchToken()
    let location = useLocation();
  
    if (!auth) {
      
      return <Navigate to="/" state={{ from: location }} />;
    }
  
    return children;
}
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
.card {
  border-radius: 15px;
}
.gradient-custom {
  background: linear-gradient(to bottom right, rgba(240, 147, 251, 1), rgba(245, 87, 108, 1));
}
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Monday, March 20, 2023

FastAPI login with PyJWT token authentication

FastAPI login with PyJWT token authentication

Install Fastapi

https://github.com/tiangolo/fastapi

pip install fastapi
C:\fastAPI\jwt-auth>pip install fastapi
C:\fastAPI\jwt-auth>pip install "uvicorn[standard]"


Create main.py
jwt-auth/main.py
 
#jwt-auth/main.py
from fastapi import FastAPI
import jwt #pip install pyjwt https://pypi.org/project/PyJWT/
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder

SECRET_KEY = "cairocoders123456789"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 800

dummy_user = {
    "username": "cairocoders",
    "password": "123456ednalan",
}

app = FastAPI()

class Loginclass(BaseModel):
    username: str
    password: str
@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.post("/login")
async def login_user(login_item: Loginclass):
    data = jsonable_encoder(login_item)
    if dummy_user['username'] == data['username'] and dummy_user['password'] == data['password']:
        encoded_jwt = jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
        return {'token': encoded_jwt }
    else:
        return {'message': 'Login failed'}
install PyJWT
https://github.com/jpadilla/pyjwt

pip install PyJWT
C:\fastAPI\jwt-auth>pip install PyJWT

Rn C:\fastAPI\jwt-auth>uvicorn main:app --reload 

http://127.0.0.1:8000/docs

Saturday, February 25, 2023

Fastapi React

Fastapi React

Install Fastapi

https://github.com/tiangolo/fastapi

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

Create main.py
react/main.py
 
//react/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_methods=["*"],
    allow_headers=["*"],
    allow_credentials=True,
    allow_origins=["http://localhost:3000"]
)

@app.get('/get_data')
async def get_data():
    return {'body': 'Hello World from python fastapi'}
run the FastAPI app

C:\fastAPI\react>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
Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\App.js
//myreactdev\src\App.js
import axios from "axios";
import { useState, useEffect } from "react";

function App() {
    const [ body, setBody ] = useState('')
    
    useEffect( () => {
        axios
            .get("http://127.0.0.1:8000/get_data")
            .then((response) => {
                const data = response.data
                setBody(data['body'])
            })
            .catch( (e) => {
                // Placeholder
            })
    }, [])

    return (
        <div>
            <p><h1>{body}</h1></p>
        </div>
    );
}

export default App;
Run C:\react-j\myreactdev>npm start

Monday, February 20, 2023

FastAPI Login Register User Token Authentication with Password Hashing and Send Email SMTP

FastAPI Login Register User Token Authentication with Password Hashing and Send Email SMTP

Install Fastapi

https://github.com/tiangolo/fastapi

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

Install sqlalchemy jinja2
https://pypi.org/project/Jinja2/
pip install python-multipart sqlalchemy jinja2
C:\fastAPI\loginregister>pip install python-multipart sqlalchemy jinja2


Create main.py
loginregister/main.py
#loginregister/main.py
from fastapi import FastAPI, Request, APIRouter,Depends,Form,HTTPException,Response
from starlette.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from connection import Base,engine, sess_db
from sqlalchemy.orm import Session
from scurity import get_password_hash,verify_password, create_access_token, verify_token, COOKIE_NAME
from starlette.responses  import RedirectResponse

# Repository
from repositoryuser import UserRepository, SendEmailVerify

# Model
from models import UserModel

templates = Jinja2Templates(directory="templates")

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

#db engin
Base.metadata.create_all(bind=engine)

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

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

@app.get("/user/signup")
def signup(req: Request):
    return templates.TemplateResponse("signup.html", {"request": req})

@app.post("/signupuser")
def signup_user(db:Session=Depends(sess_db),username : str = Form(),email:str=Form(),password:str=Form()):
    print(username)
    print(email)
    print(password)
    userRepository=UserRepository(db)
    db_user= userRepository.get_user_by_username(username)
    if db_user:
        return "username is not valid"

    signup=UserModel(email=email,username=username,password=get_password_hash(password))
    success=userRepository.create_user(signup)
    token=create_access_token(signup)
    SendEmailVerify.sendVerify(token)
    if success:
        return "create  user successfully"
    else:
        raise HTTPException(
            status_code=401, detail="Credentials not correct"
        )

@app.get("/user/signin")
def login(req: Request):
    return templates.TemplateResponse("/signin.html", {"request": req})

@app.post("/signinuser")
def signin_user(response:Response,db:Session=Depends(sess_db),username : str = Form(),password:str=Form()):
    userRepository = UserRepository(db)
    db_user = userRepository.get_user_by_username(username)
    if not db_user:
        return "username or password is not valid"

    if verify_password(password,db_user.password):
        token=create_access_token(db_user)
        response.set_cookie(
            key=COOKIE_NAME,
            value=token,
            httponly=True,
            expires=1800
        )
        return {COOKIE_NAME:token,"token_type":"cairocoders"}

@app.get('/user/verify/{token}')
def verify_user(token,db:Session=Depends(sess_db)):
    userRepository=UserRepository(db)
    payload=verify_token(token)
    username=payload.get("username")
    db_user=userRepository.get_user_by_username(username)

    if not username:
        raise  HTTPException(
            status_code=401, detail="Credentials not correct"
        )
    if db_user.is_active==True:
        return "your account  has been allreay activeed"

    db_user.is_active=True
    db.commit()
    response=RedirectResponse(url="/user/signin")
    return response
    #http://127.0.0.1:8000/user/verify/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNseWRleTAxMzEiLCJlbWFpbCI6ImNseWRleUBnbWFpbC5jb20iLCJyb2xlIjoidXNlciIsImFjdGl2ZSI6ZmFsc2V9.BKektCLzr47qn-fRtnGVulSdYlcMdemJQO_p32jWDk0
Create database Connection sqlalchemy
loginregister/connection.py
#loginregister/connection.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from typing import Optional

#dbcon = "postgresql://user:password@postgresserver/db"
dbcon = 'sqlite:///fastapidb.sqlite3'

engine = create_engine(dbcon)
SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
Base.metadata.create_all(bind=engine)


DATABASE_URL: Optional[str] = None
SECRET_KEY: Optional[str] = "cairocoders"

def sess_db():
    db = SessionFactory()
    try:
        yield db
    finally:
        db.close()

Create database Model sqlalchemy

loginregister/models.py
#loginregister/models.py
from sqlalchemy import Column,String,Integer,Boolean,Enum
from schema import Roles
from connection import  Base

class UserModel(Base):
    __tablename__ = "users"
    id=Column(Integer,primary_key=True,index=True)
    email=Column(String,unique=True,index=True)
    username=Column(String,unique=True,index=True)
    password=Column(String,unique=False,index=True)
    is_active=Column(Boolean,default=False)
    role=Column(Enum(Roles),default="user")
loginregister/repositoryuser.py

#loginregister/repositoryuser.py
from sqlalchemy.orm import Session
from models import UserModel
from typing import  Dict,Any
from sqlalchemy.orm import Session

import smtplib
from email.message import EmailMessage

class UserRepository:
    def __init__(self,sess:Session):
        self.sess: Session=sess

    def create_user(self,signup:UserModel) -> bool:
         try:
             self.sess.add(signup)
             self.sess.commit()
         except:
             return False
         return True

    def get_user(self):
        return  self.sess.query(UserModel).all()

    def get_user_by_username(self,username:str):
        return self.sess.query(UserModel).filter(UserModel.username==username).first()

    def update_user(self,id:int,details:Dict[str,Any]) -> bool:
        try:
            self.sess.query(UserModel).filter(UserModel.id==id).update(details)
            self.sess.commit()
        except:
            return False
        return True
    def delete_user(self,id:int)-> bool:
        try:
            self.sess.query(UserModel).filter(UserModel.id==id).delete()
            self.sess.commit()
        except:
            return  False
        return  True

class SendEmailVerify:

  def sendVerify(token):
    email_address = "cairocoders0711@gmail.com" # type Email
    email_password = "cairocoders-ednalan" # If you do not have a gmail apps password, create a new app with using generate password. Check your apps and passwords https://myaccount.google.com/apppasswords

    # create email
    msg = EmailMessage()
    msg['Subject'] = "Email subject"
    msg['From'] = email_address
    msg['To'] = "clydeymojica0130@gmail.com" # type Email
    msg.set_content(
       f"""\
    verify account        
    http://localhost:8080/user/verify/{token}
    """,
        
    )
    # send email
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
        smtp.login(email_address, email_password)
        smtp.send_message(msg)
loginregister/schema.py

#loginregister/schema.py
from datetime import date
from pydantic import BaseModel, EmailStr #pip install pydantic[email]
from enum import Enum
from fastapi import Form


class UserSchema(BaseModel):
    email: EmailStr
    username: str
    password: str

    class Config:
        orm_mode = True

class Roles(Enum):
    user = "user"
    admin = "admin"
loginregister/scurity.py

#loginregister/scurity.py
from passlib.context import  CryptContext #pip install passlib
from fastapi.security import OAuth2PasswordBearer
from jose import jwt #https://pypi.org/project/python-jose/ = pip install python-jose
from fastapi import Depends,Request
from fastapi import HTTPException

from models import UserModel

JWT_SECRET="cairocoders$§%§$Ednalan"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=3000

pwd_context=CryptContext(schemes=["bcrypt"],deprecated="auto") #pip install bcrypt
# save token to oauth2_scheme
oauth2_scheme=OAuth2PasswordBearer(tokenUrl="user/signin")
COOKIE_NAME="Authorization"

# create Token
def create_access_token(user):
    try:
        payload={
            "username":user.username,
            "email":user.email,
            "role":user.role.value,
            "active":user.is_active,

        }
        return  jwt.encode(payload,key=JWT_SECRET,algorithm=ALGORITHM)
    except Exception as ex:
        print(str(ex))
        raise ex

# create verify Token
def verify_token(token):
    try:
        payload=jwt.decode(token,key=JWT_SECRET)
        return payload
    except Exception as ex:
        print(str(ex))
        raise ex

# password hash
def  get_password_hash(password):
    return pwd_context.hash(password)

# password verify
def verify_password(plain_password,hashed_password):
    return pwd_context.verify(plain_password,hashed_password)

def get_current_user_from_token(token:str=Depends(oauth2_scheme)):
    user= verify_token(token)
    return user

def get_current_user_from_cookie(request:Request) -> UserModel:
    token=request.cookies.get(COOKIE_NAME)
    if token:
        user = verify_token(token)
        return user
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

loginregister/templates/index.html
//loginregister/templates/index.html
{% extends "base.html" %}

{% block title %}Home Page{% endblock %}

{% block content %}

<div class="event">
  <p><h1>Welcome to the home page.</h1></p>
</div>

{% endblock %}
loginregister/templates/base.html
//loginregister/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', path='/style.css')}}"/>
<title>{% block title %} My Webpage {% endblock %}</title>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">Navbar</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item active">
              <a class="nav-link" href="/">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="/about">About</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="/user/signin">Login</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="/user/signup">Sign Up</a>
            </li>
          </ul>
        </div>
      </nav>
<div class="container">    
    <div class="row"><p><h3>FastAPI Login Register User Token Authentication with Password Hashing and Send Email SMTP</h3></p>
    {% block content %}{% endblock %}
  </div>  
</div>
</body>
</html>
loginregister/templates/about.html
//loginregister/templates/about.html
{% extends "base.html" %}

{% block title %}About Page{% endblock %}

{% block content %}

<div class="event">
  <p><h1> About page.</h1></p>
</div>

{% endblock %}
loginregister/templates/signin.html
//loginregister/templates/signin.html
{% extends "base.html" %}

{% block title %}Login Page{% endblock %}

{% block content %}
<section style="margin-top: 50px;">
  <div class="container h-custom">
    <div class="row d-flex justify-content-center align-items-center h-100">
      <div class="col-lg-6">
        <img src="{{ url_for('static', path='/login.png')}}" class="img-fluid" alt="Sample image">
      </div>
      <div class="col-lg-6 col-md-6">
        <form action="/signinuser" method="post">
          <div class="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
            <p class="lead fw-normal mb-0 me-3">Sign in with</p>
            <button type="button" class="btn btn-primary btn-floating mx-1">
              <i class="fab fa-facebook-f"></i>
            </button>
            <button type="button" class="btn btn-primary btn-floating mx-1">
              <i class="fab fa-twitter"></i>
            </button>
            <button type="button" class="btn btn-primary btn-floating mx-1">
              <i class="fab fa-linkedin-in"></i>
            </button>
          </div>

          <div class="divider d-flex align-items-center my-4">
            <p class="text-center fw-bold mx-3 mb-0">Or</p>
          </div>

          <div class="form-outline mb-4">
            <input type="text" id="username" class="form-control form-control-lg" name="username" placeholder="User Name" type="text" value="{{ username }}" />
            <label class="form-label" for="username">User Name</label>
          </div>
          <div class="form-outline mb-3">
            <input type="password" id="pass" name="password" value="{{ password }}" class="form-control form-control-lg" placeholder="Enter password" />
            <label class="form-label" for="pass">Password</label>
          </div>

          <div class="d-flex justify-content-between align-items-center">
            <div class="form-check mb-0">
              <input class="form-check-input me-2" type="checkbox" value="" id="remme" />
              <label class="form-check-label" for="remme">Remember me</label>
            </div>
            <a href="#!" class="text-body">Forgot password?</a>
          </div>

          <div class="text-center text-lg-start mt-4 pt-2">
            <button type="submit" class="btn btn-primary btn-lg" style="padding-left: 2.5rem; padding-right: 2.5rem;">Login</button>
            <p class="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="/user/signup" class="link-danger">Register</a></p>
          </div>
        </form>
      </div>
    </div>
  </div>
</section>
{% endblock %}
loginregister/templates/signup.html
//loginregister/templates/signup.html
{% extends "base.html" %}

{% block title %}Sign Up Page{% endblock %}

{% block content %}
<section style="margin-top: 50px;">
  <div class="container h-custom">
    <div class="row d-flex justify-content-center align-items-center h-100">
      <div class="col-lg-6">
        <img src="{{ url_for('static', path='/reg.svg')}}" class="img-fluid" alt="Sample image">
      </div>
      <div class="col-lg-6 col-md-6">
        <form action="/signupuser" method="post">
          <div class="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
            <p class="lead fw-normal mb-2 me-3">CREATE AN ACCOUNT</p>
          </div>

          <div class="form-outline mb-4">
            <input type="text" id="username" class="form-control form-control-lg" name="username" placeholder="User Name" value="{{ username }}" />
            <label class="form-label" for="username">User Name</label>
          </div>

          <div class="form-outline mb-4">
            <input type="email" id="mail" class="form-control form-control-lg" name="email" value="{{ email }}" placeholder="Enter a valid email address" />
            <label class="form-label" for="mail">Email address</label>
          </div>

          <div class="form-outline mb-3">
            <input type="password" id="pass" name="password" value="{{ password }}" class="form-control form-control-lg" placeholder="Enter password" />
            <label class="form-label" for="pass">Password</label>
          </div>

          <div class="text-center text-lg-start mt-4 pt-2">
            <button type="submit" class="btn btn-success btn-lg" style="padding-left: 2.5rem; padding-right: 2.5rem;">Register</button>
            <p class="small fw-bold mt-2 pt-1 mb-0">I am already a member? <a href="/user/signin" class="link-danger">Login</a></p>
          </div>
        </form>
      </div>
    </div>
  </div>
</section>
{% endblock %}
loginregister/templates/verify.html
//loginregister/templates/verify.html
{% extends "base.html" %}
{% block title %}Contact Page{% endblock %}

{% block content %}

<div class="wrapper">
  <div class="contacts">
    <h3> verify your account</h3>
  </div>
  <div class="form">
    <h3>Sign in to your email to verify your account</h3>
    <form method="post">
      <div>
        <a class="signin__link" href="/user/signin">back to Login page</a>
      </div>

    </form>
  </div>
</div>

{% endblock %}
run the FastAPI app

C:\fastAPI\loginregister>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

Python FastAPI How to Send Email using SMTP - smtplib

Python FastAPI How to Send Email using SMTP - smtplib

Install Fastapi

https://github.com/tiangolo/fastapi

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

Install sqlalchemy jinja2
https://pypi.org/project/Jinja2/
C:\fastAPI\sendemail>pip install Jinja2

Create main.py
sendemail/main.py
#sendemail/main.py
from fastapi import FastAPI, Request, Form

from starlette.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

import smtplib
from email.message import EmailMessage

templates = Jinja2Templates(directory="templates")

app = FastAPI()

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

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

@app.post("/submit")
def submit(name : str = Form(),emailAddress:str=Form(),message:str=Form()):
    print(name)
    print(emailAddress)
    print(message)

    email_address = "cairocoders0711@gmail.com" # type Email
    email_password = "cairocodersednalan" # If you do not have a gmail apps password, create a new app with using generate password. Check your apps and passwords https://myaccount.google.com/apppasswords

    # create email
    msg = EmailMessage()
    msg['Subject'] = "Email subject"
    msg['From'] = email_address
    msg['To'] = "clydeymojica0130@gmail.com" # type Email
    msg.set_content(
       f"""\
    Name : {name}
    Email : {emailAddress}
    Message : {message}    
    """,
        
    )
    # send email
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
        smtp.login(email_address, email_password)
        smtp.send_message(msg)

    return "email successfully sent"
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

endemail/templates/index.html
//sendemail/templates/index.html
{% extends "base.html" %}

{% block title %}Home Page{% endblock %}

{% block content %}
<div class="container py-4"><p><h3>Python FastAPI How to Send Email using SMTP - smtplib</h3></p>
    <form id="contactForm" action="/submit" method="post">
      <div class="mb-3">
        <label class="form-label" for="name">Name</label>
        <input class="form-control" name="name" id="name" type="text" placeholder="Name" />
      </div>

      <div class="mb-3">
        <label class="form-label" for="emailAddress">Email Address</label>
        <input class="form-control" name="emailAddress" id="emailAddress" type="email" placeholder="Email Address" />
      </div>
  
      <div class="mb-3">
        <label class="form-label" for="message">Message</label>
        <textarea class="form-control" name="message" id="message" type="text" placeholder="Message" style="height: 10rem;"></textarea>
      </div>
  
      <div class="d-grid">
        <button class="btn btn-primary btn-lg" type="submit">Submit</button>
      </div>
    </form>
  </div>
{% endblock %}
sendemail/templates/base.html
//sendemail/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="{{ url_for('static', path='/styles.css')}}"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<title>{% block title %} My Webpage {% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>
run the FastAPI app

C:\fastAPI\sendmail>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

Friday, February 17, 2023

FastAPI Simple Website with Jinja2 Template

FastAPI Simple Website with Jinja2 Template

Install Fastapi

https://github.com/tiangolo/fastapi

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

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

Create main.py
simplewebsite/main.py
simplewebsite/main.py

#simplewebsite/main.py
from fastapi import FastAPI, Request

from starlette.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

templates = Jinja2Templates(directory="templates")

app = FastAPI()

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

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

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

@app.get("/contact")
def contact(request: Request):
    return templates.TemplateResponse("contact.html", {"request": request})
download bootstrap template https://startbootstrap.com/template/modern-business

simplewebsite/templates/base.html
//simplewebsite/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="{{ url_for('static', path='/css/styles.css')}}"/>
<!-- Bootstrap icons-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet" />
<title>{% block title %} My Webpage {% endblock %}</title>
</head>
<body class="d-flex flex-column h-100">
<main class="flex-shrink-0">    
    {% include "nav.html" %}
    {% block content %}{% endblock %}
</main>
{% include "footer.html" %}
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="{{ url_for('static', path='/js/scripts.js')}}"></script>
</body>
</html>
simplewebsite/templates/index.html
//simplewebsite/templates/index.html
{% extends "base.html" %}

{% block title %}Home Page{% endblock %}

{% block content %}
  Index.html Home page

{% endblock %}
simplewebsite/templates/nav.html
//simplewebsite/templates/nav.html
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container px-5">
        <a class="navbar-brand" href="/">Start Bootstrap</a>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                <li class="nav-item"><a class="nav-link" href="/">Home</a></li>
                <li class="nav-item"><a class="nav-link" href="/about">About</a></li>
                <li class="nav-item"><a class="nav-link" href="/contact">Contact</a></li>
                <li class="nav-item"><a class="nav-link" href="pricing.html">Pricing</a></li>
                <li class="nav-item"><a class="nav-link" href="faq.html">FAQ</a></li>
            </ul>
        </div>
    </div>
</nav>
simplewebsite/templates/footer.html
//simplewebsite/templates/footer.html
        <footer class="bg-dark py-4 mt-auto">
          <div class="container px-5">
              <div class="row align-items-center justify-content-between flex-column flex-sm-row">
                  <div class="col-auto"><div class="small m-0 text-white">Copyright © Your Website 2022</div></div>
                  <div class="col-auto">
                      <a class="link-light small" href="#!">Privacy</a>
                      <span class="text-white mx-1">·</span>
                      <a class="link-light small" href="#!">Terms</a>
                      <span class="text-white mx-1">·</span>
                      <a class="link-light small" href="#!">Contact</a>
                  </div>
              </div>
          </div>
      </footer>
simplewebsite/templates/about.html
//simplewebsite/templates/about.html
{% extends "base.html" %}
{% block title %}About Page{% endblock %}

{% block content %}
	About Page

{% endblock %}	  
simplewebsite/templates/contact.html
//simplewebsite/templates/contact.html
{% extends "base.html" %}

{% block title %}Contact Page{% endblock %}

{% block content %}
    Contact Page
{% endblock %}
run the FastAPI app

C:\fastAPI\simplewebsite>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

Sunday, February 12, 2023

FastAPI Registration Form Validation with sqlalchemy Jinja2 Template

FastAPI Registration Form Validation with sqlalchemy Jinja2 Template

Install Fastapi

https://github.com/tiangolo/fastapi

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

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

Create main.py
registration/main.py
registration/main.py
 
#registration/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 import responses
from sqlalchemy.exc import IntegrityError
from fastapi.responses import RedirectResponse
 
from forms import UserCreateForm

models.Base.metadata.create_all(bind=engine)
 
templates = Jinja2Templates(directory="templates")
 
app = FastAPI()
 
def get_db():
    db = sessionlocal()
    try:
        yield db
    finally:
        db.close()
 
@app.get("/")
async def home(request: Request, db: Session = Depends(get_db)):
    return templates.TemplateResponse("index.html", {"request": request})
 
@app.post("/register/")
async def register(request: Request, username: str = Form(...), email: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
    form = UserCreateForm(request)
    await form.load_data()
    print("submited")
    if await form.is_valid():
        try:
            print(username)
            print(email)
            print(password)
            
            total_row = db.query(models.User).filter(models.User.email == email).first()
            print(total_row)
            if total_row == None:
                print("Save")
                users = models.User(username=username, email=email, password=password)
                db.add(users)
                db.commit()

                return responses.RedirectResponse(
                    "/", status_code=status.HTTP_302_FOUND
                ) 
            else:
                print("taken email")  
                errors = ["The email has already been taken"]  

        except IntegrityError:
            return {"msg":"Error"}
    else:
        print("Error Form")
        errors = form.errors

    return templates.TemplateResponse("index.html", {"request": request, "errors": errors})      
registration/database.py
 
#registration/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()   
registration/models.py
 
#registration/models.py
from sqlalchemy import Column, Integer, String
from database import Base
 
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(150))
    email = Column(String(150))
    password = Column(String(150))
 
    def __repr__(self):
        return '<User %r>' % (self.id)  
registration/forms.py
 
#registration/forms.py
from typing import List
from typing import Optional

from fastapi import Request

class UserCreateForm:
    def __init__(self, request: Request):
        self.request: Request = request
        self.errors: List = []
        self.username: Optional[str] = None
        self.email: Optional[str] = None
        self.password: Optional[str] = None

    async def load_data(self):
        form = await self.request.form()
        self.username = form.get("username")
        self.email = form.get("email")
        self.password = form.get("password")

    async def is_valid(self):
        if not self.username or not len(self.username) > 3:
            self.errors.append("Username should be > 3 chars")
        if not self.email or not (self.email.__contains__("@")):
            self.errors.append("Email is required")
        if not self.password or not len(self.password) >= 4:
            self.errors.append("Password must be > 4 chars")
        if not self.errors:
            return True
        return False 
make templates inside the templates directory

registration/templates/base.html
//registration/templates/index.html
{% extends 'base.html' %}
 
{% block content %}
<div class="container">
    <div class="row">
      <div class="text-danger font-weight-bold">
        <ul>
          {% for error in errors %}
            <li class="alert alert-danger">{{error}}</li>
          {% endfor %}
        </ul>  
      </div>
    </div>

    <div class="row my-5">
        <form action = "/register" method = "post"> 
        <div class="mb-3">
          <label>Username</label>
          <input type="text" required class="form-control" name="username" value="" placeholder="username">
        </div>
        <div class="mb-3">
          <label>Email</label>
          <input type="text" required placeholder="Your email" name="email" value="" class="form-control">
        </div>
        <div class="mb-3">
          <label>Password</label>
          <input type="password" required placeholder="Choose a secure password" value="" name="password" class="form-control">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
      </form>
    </div>
</div>
<style>
ul {
    list-style-type: none;
}
</style>    
{% endblock content %}
registration/temmplates/base.html
//registration/temmplates/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 Registration Form with sqlalchemy Jinja2 Template - Cairocoders</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <h1 class="page-header text-center">FastAPI Registration Form Validation with sqlalchemy Jinja2 Template</h1>
    {% block content %}
         
    {% endblock content %}
</div>
</body>
</html> 
run the FastAPI app

C:\fastAPI\registration>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

Monday, February 6, 2023

FastAPI Jinja2 Upload multiple images and show images

FastAPI Jinja2 Upload multiple images and show images

Install Fastapi

https://github.com/tiangolo/fastapi

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

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

Create main.py
multipleupload/main.py
//multipleupload/main.py
from fastapi import FastAPI, Request, UploadFile, File
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

from typing import List

IMAGEDIR = "images/"

app = FastAPI()
templates = Jinja2Templates(directory="templates")
app.mount("/images", StaticFiles(directory="images"), name="images")

@app.get('/', response_class=HTMLResponse)
def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.post("/upload-files")
async def create_upload_files(request: Request, files: List[UploadFile] = File(...)):
    for file in files:
        contents = await file.read()
        #save the file
        with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
            f.write(contents)

    show = [file.filename for file in files]

    #return {"Result": "OK", "filenames": [file.filename for file in files]}
    return templates.TemplateResponse("index.html", {"request": request, "show": show})
make templates inside the templates directory

multipleupload/templates/base.html
//multipleupload/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 Jinja2 Upload multiple images and show images - Cairocoders</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <h1 class="page-header text-center">FastAPI Jinja2 Upload multiple images and show images</h1>
    {% block content %}
        
    {% endblock content %}
</div>
</body>
</html>
multipleupload/templates/index.html
//multipleupload/templates/index.html
{% extends 'base.html' %}

{% block content %}
<div class="row">
	<form action="/upload-files/" enctype="multipart/form-data" method="post">
        <div class="mb-3">
            <label>Upload Files</label>
            <input class="form-control form-control-lg" name="files" type="file" multiple accept=".jpg, .png">
        </div>
        <div class="mb-3">
            <input type="submit" class="btn btn-primary btn-lg">
        </div>
	</form>
    <div class="col-12">
    {% for rs in show %}
        <div style="padding:20px;float:left;">
            <img width="500" src="{{ url_for('images', path=rs) }}">  
        </div>
    {% endfor %}  
    </div>
</div>    
{% endblock content %}
run the FastAPI app

C:\fastAPI\multipleupload>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

Sunday, February 5, 2023

FastAPI Jinja2 File Upload Progress Bar using JQuery Ajax

FastAPI Jinja2 File Upload Progress Bar using JQuery Ajax

Install Fastapi

https://github.com/tiangolo/fastapi

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

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

Create main.py
uploadajax/main.py
 
#uploadajax/main.py
from typing import Union

from fastapi import FastAPI, Request, UploadFile, File
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

IMAGEDIR = "images/"

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get('/', response_class=HTMLResponse)
def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.post('/uploadfile', response_class=HTMLResponse)
async def post_basic_form(request: Request, file: UploadFile = File(...)):
    print(f'Filename: {file.filename}')
     
    contents = await file.read()
     
    #save the file
    with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
        f.write(contents)
   
    return templates.TemplateResponse('success.html', context={'request': request})
make templates inside the templates directory

The jQuery Form Plugin allows you to easily and unobtrusively upgrade HTML forms to use AJAX.
https://github.com/jquery-form/form

uploadajax/templates/base.html
//uploadajax/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 Jinja2 File Upload Progress Bar using JQuery Ajax - Cairocoders</title>
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js"></script>
</head>
<body>
<div class="container">
    <h1 class="page-header text-center">FastAPI Jinja2 File Upload Progress Bar using JQuery Ajax</h1>
    {% block content %}
        
    {% endblock content %}
</div>
</body>
</html>
uploadajax/templates/index.html
//uploadajax/templates/index.html
{% extends 'base.html' %}

{% block content %}
	<div class="panel panel-default" style="margin-top: 50px;">
		<div class="panel-heading"><b>FastAPI Jinja2 File Upload Progress Bar using JQuery Ajax</b></div>
		<div class="panel-body">
			<form id="uploadImage" method="post" action="/uploadfile" enctype="multipart/form-data">
				<div class="form-group">
					<label>File Upload</label>
					<input type="file" name="file" multiple="true" id="file" />
				</div>
				<div class="form-group">
					<input type="submit" id="uploadSubmit" value="Upload" class="btn btn-info" />
				</div>
				<div class="progress">
					<div class="progress-bar progress-bar-striped bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
				</div>
				<div id="targetLayer" style="display:none;"></div>
			</form>
		</div>
	</div>
<script>
$(document).ready(function(){
$('#uploadImage').submit(function(event){
	if($('#file').val()){
		event.preventDefault();
		$('#targetLayer').hide();
		$(this).ajaxSubmit({
			target: '#targetLayer',
			beforeSubmit:function(){
				$('.progress-bar').width('50%');
			},
			uploadProgress: function(event, position, total, percentageComplete)
			{
				$('.progress-bar').animate({
					width: percentageComplete + '%'
				}, {
					duration: 1000
				});
			},
			success:function(data){ //alert(data);
				$('#targetLayer').show();
				$('#targetLayer').append(data.htmlresponse);
			},
			resetForm: true
		});
	}
	return false;
});
});
</script>
{% endblock content %}
uploadajax/templates/success.html
//uploadajax/templates/success.html
<h4>File successfully uploaded to /images!</h4>
run the FastAPI app

C:\fastAPI\uploadajax>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

FastAPI File Upload with Jinja2 Template

FastAPI File Upload with Jinja2 Template

Install Fastapi

https://github.com/tiangolo/fastapi

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

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

Create main.py
uploadfile/main.py
 
//uploadfile/main.py
from fastapi import FastAPI, Request, Form, UploadFile, File
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

IMAGEDIR = "images/"

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

@app.get('/file-upload', response_class=HTMLResponse)
def get_basic_form(request: Request):
    return templates.TemplateResponse("form.html", {"request": request})

@app.post('/file-upload', response_class=HTMLResponse)
async def post_basic_form(request: Request, username: str = Form(...), password: str = Form(...), file: UploadFile = File(...)):
    print(f'username: {username}')
    print(f'password: {password}')
    print(f'Filename: {file.filename}')
    
    contents = await file.read()
    
    #save the file
    with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
        f.write(contents)

    return templates.TemplateResponse("form.html", {"request": request})
make templates inside the templates directory

uploadfile/form.html
//uploadfile/form.html
<html>
<head>
<title>FastAPI File Upload with Jinja2 Template</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
<link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}">
</head>
<body>
<div class="container">
	<div class="row main">
		<div class="panel-heading">
	        <div class="panel-title text-center">
	            <h1 class="title">FastAPI File Upload with Jinja2 Template</h1>
	            <hr />
	        </div>
	    </div> 
		<div class="main-login main-center">
            <form class="form-horizontal" method="POST" enctype="multipart/form-data">
				<div class="form-group">
					<label for="name" class="cols-sm-2 control-label">Your Name</label>
					<div class="cols-sm-10">
						<div class="input-group">
							<span class="input-group-addon"><i class="fa fa-user fa" aria-hidden="true"></i></span>
							<input type="text" class="form-control" name="name" id="name"  placeholder="Enter your Name"/>
						</div>
					</div>
				</div>
                <div class="form-group">
					<label for="email" class="cols-sm-2 control-label">Your Email</label>
					<div class="cols-sm-10">
						<div class="input-group">
							<span class="input-group-addon"><i class="fa fa-envelope fa" aria-hidden="true"></i></span>
							<input type="text" class="form-control" name="email" id="email"  placeholder="Enter your Email"/>
						</div>
					</div>
				</div>
                <div class="form-group">
					<label for="username" class="cols-sm-2 control-label">Username</label>
					<div class="cols-sm-10">
						<div class="input-group">
							<span class="input-group-addon"><i class="fa fa-users fa" aria-hidden="true"></i></span>
							<input type="text" class="form-control" name="username" id="username"  placeholder="Enter your Username"/>
						</div>
					</div>
				</div>
                <div class="form-group">
					<label for="password" class="cols-sm-2 control-label">Password</label>
					<div class="cols-sm-10">
						<div class="input-group">
							<span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span>
							<input type="password" class="form-control" name="password" id="password"  placeholder="Enter your Password"/>
						</div>
					</div>
				</div>
                <div class="form-group">
					<label for="confirm" class="cols-sm-2 control-label">Upload File</label>
						<div class="cols-sm-10">
							<div class="input-group">
							<input type="file" name="file" class="form-control">
						</div>
					</div>
				</div>
                <div class="form-group ">
                    <input type="submit" value="Register" class="btn btn-primary btn-lg btn-block login-button">
				</div>
			</form>
	    </div>
    </div>
</div>  
</body>
</html>
uploadfile/static/css/main.css
//uploadfile/static/css/main.css
body, html{
    height: 100%;
    background-repeat: no-repeat;
    background-color: #d3d3d3;
    font-family: 'Oxygen', sans-serif;
}
.main{
    margin-top: 70px;
}
h1.title { 
   font-size: 50px;
   font-family: 'Passion One', cursive; 
   font-weight: 400; 
}
hr{
   width: 10%;
   color: #fff;
}
.form-group{
   margin-bottom: 15px;
}
label{
   margin-bottom: 15px;
}
input,
input::-webkit-input-placeholder {
   font-size: 12px;
   padding-top: 3px;
}
.main-login{
    background-color: #fff;
   -moz-border-radius: 2px;
   -webkit-border-radius: 2px;
   border-radius: 2px;
   -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
   -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
   box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);

}
.main-center{
    margin-top: 30px;
    margin: 0 auto;
    max-width: 500px;
   padding: 40px 40px;
}
.login-button{
   margin-top: 5px;
}
.login-register{
   font-size: 12px;
   text-align: center;
}
uploadfile/static/css/main.css run the FastAPI app

C:\fastAPI\uploadfile>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

FastAPI Upload Image

FastAPI Upload Image

Install Fastapi

https://github.com/tiangolo/fastapi

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

Create main.py
upload/main.py
 
#upload/main.py
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import FileResponse
import os
from random import randint
import uuid

IMAGEDIR = "images/"

app = FastAPI()


@app.post("/upload/")
async def create_upload_file(file: UploadFile = File(...)):

    file.filename = f"{uuid.uuid4()}.jpg"
    contents = await file.read()

    #save the file
    with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
        f.write(contents)

    return {"filename": file.filename}


@app.get("/show/")
async def read_random_file():

    # get random file from the image directory
    files = os.listdir(IMAGEDIR)
    random_index = randint(0, len(files) - 1)

    path = f"{IMAGEDIR}{files[random_index]}"
    
    return FileResponse(path)
run the FastAPI app

C:\fastAPI\upload>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

Saturday, February 4, 2023

FastAPI Simple CRUD - SqlAlchemy

FastAPI Simple CRUD - SqlAlchemy

Install Fastapi

https://github.com/tiangolo/fastapi

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

Create main.py
crud/main.py
 
//crud/main.py
FastAPI Simple CRUD - SqlAlchemy


from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return "todo"

@app.post("/todo")
def create_todo():
    return "create todo item"

@app.get("/todo/{id}")
def read_todo(id: int):
    return "read todo item with id {id}"

@app.put("/todo/{id}")
def update_todo(id: int):
    return "update todo item with id {id}"

@app.delete("/todo/{id}")
def delete_todo(id: int):
    return "delete todo item with id {id}"

@app.get("/todo")
def read_todo_list():
    return "read todo list"
crud/main.py
 
//crud/main.py
from typing import List
from fastapi import FastAPI, status, HTTPException, Depends
from database import Base, engine, SessionLocal
from sqlalchemy.orm import Session
import models
import schemas

Base.metadata.create_all(engine) # Create the database

# Initialize app
app = FastAPI()

# Helper function to get database session
def get_session():
    session = SessionLocal()
    try:
        yield session
    finally:
        session.close()

@app.get("/")
def root():
    return "todo"

@app.post("/todo", response_model=schemas.ToDo, status_code=status.HTTP_201_CREATED)
def create_todo(todo: schemas.ToDoCreate, session: Session = Depends(get_session)):

    tododb = models.ToDo(task = todo.task)

    session.add(tododb)
    session.commit()
    session.refresh(tododb)

    return tododb

@app.get("/todo/{id}", response_model=schemas.ToDo)
def read_todo(id: int, session: Session = Depends(get_session)):

    todo = session.query(models.ToDo).get(id) # get item with the given id

    # check if id exists. If not, return 404 not found response
    if not todo:
        raise HTTPException(status_code=404, detail=f"todo item with id {id} not found")

    return todo

@app.put("/todo/{id}", response_model=schemas.ToDo)
def update_todo(id: int, task: str, session: Session = Depends(get_session)):

    todo = session.query(models.ToDo).get(id)     # get given id

    if todo:
        todo.task = task
        session.commit()

    # check if id exists. If not, return 404 not found response
    if not todo:
        raise HTTPException(status_code=404, detail=f"todo item with id {id} not found")

    return todo

@app.delete("/todo/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_todo(id: int, session: Session = Depends(get_session)):

    # get the given id
    todo = session.query(models.ToDo).get(id)

    # if todo item with given id exists, delete it from the database. Otherwise raise 404 error
    if todo:
        session.delete(todo)
        session.commit()
    else:
        raise HTTPException(status_code=404, detail=f"todo item with id {id} not found")

    return None

@app.get("/todo", response_model = List[schemas.ToDo])
def read_todo_list(session: Session = Depends(get_session)):

    todo_list = session.query(models.ToDo).all() # get all todo items

    return todo_list 	
Database sqlalchemy

https://www.sqlalchemy.org/

C:\fastAPI\crud_todo>pip install sqlalchemy
fastAPI\crud_todo\database.py
 
//fastAPI\crud_todo\database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Create a sqlite engine instance
engine = create_engine("sqlite:///fastapidb.db")

# Create a DeclarativeMeta instance
Base = declarative_base()

# Create SessionLocal class from sessionmaker factory
SessionLocal = sessionmaker(bind=engine, expire_on_commit=False)
fastAPI\crud_todo\models.py
 
//fastAPI\crud_todo\models.py
from sqlalchemy import Column, Integer, String
from database import Base

# Define ToDo class from Base
class ToDo(Base):
    __tablename__ = 'todos'
    id = Column(Integer, primary_key=True)
    task = Column(String(256))
fastAPI\crud_todo\schemas.py
 
//fastAPI\crud_todo\schemas.py
from pydantic import BaseModel

# Create ToDo Schema (Pydantic Model)
class ToDoCreate(BaseModel):
    task: str

# Complete ToDo Schema (Pydantic Model)
class ToDo(BaseModel):
    id: int
    task: str

    class Config:
        orm_mode = True
run the FastAPI app

C:\fastAPI\crud_todo>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

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

Friday, January 20, 2023

Python FastAPI To Do with Jinja2 Template

Python FastAPI To Do with 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 app.py
myapp/app.py
 
//myapp/app.py
from fastapi import FastAPI, Depends, Request, Form, status

from starlette.responses import RedirectResponse
from starlette.templating import Jinja2Templates

from sqlalchemy.orm import Session

import models
from database import SessionLocal, engine

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

templates = Jinja2Templates(directory="templates")

app = FastAPI()


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


@app.get("/")
def home(request: Request, db: Session = Depends(get_db)):
    todos = db.query(models.Todo).all()
    return templates.TemplateResponse("index.html",
                                      {"request": request, "todo_list": todos})

@app.post("/add")
def add(request: Request, title: str = Form(...), db: Session = Depends(get_db)):
    new_todo = models.Todo(title=title)
    db.add(new_todo)
    db.commit()

    url = app.url_path_for("home")
    return RedirectResponse(url=url, status_code=status.HTTP_303_SEE_OTHER)


@app.get("/update/{todo_id}")
def update(request: Request, todo_id: int, db: Session = Depends(get_db)):
    todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
    todo.complete = not todo.complete
    db.commit()

    url = app.url_path_for("home")
    return RedirectResponse(url=url, status_code=status.HTTP_302_FOUND)


@app.get("/delete/{todo_id}")
def delete(request: Request, todo_id: int, db: Session = Depends(get_db)):
    todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
    db.delete(todo)
    db.commit()

    url = app.url_path_for("home")
    return RedirectResponse(url=url, status_code=status.HTTP_302_FOUND)
myapp/database.py
 
//myapp/database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./db.sqlite"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
myapp/models.py
 
//myapp/models.py
from sqlalchemy import Boolean, Column, Integer, String

from database import Base

class Todo(Base):
    __tablename__ = "todos"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String)
    complete = Column(Boolean, default=False)
make templates inside the templates directory
//myapp/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Python FastAPI To Do with Jinja2 Template</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
</head>
<body>
<section class="vh-100" style="background-color: #eee;">
  <div class="container py-5 h-100">
    <div class="row d-flex justify-content-center align-items-center h-100">
      <div class="col col-lg-9 col-xl-7">
        <div class="card rounded-3">
          <div class="card-body p-4">

            <h4 class="text-center my-3 pb-3">Python FastAPI To Do with Jinja2 Template</h4>
			<form class="row" action="/add" method="post">
              <div class="col-4">
                <div class="form-outline">
                  <input type="text" id="title" name="title" class="form-control" placeholder="Enter a task here"/>
                </div>
              </div>

              <div class="col-6">
                <button type="submit" class="btn btn-primary">Save</button>
              </div>
            </form>

            <table class="table mb-4">
				<thead>
					<tr>
					  <th scope="col">No.</th>
					  <th scope="col">Todo item</th>
					  <th scope="col">Status</th>
					  <th scope="col">Actions</th>
					</tr>
				</thead>
				<tbody>
					{% for todo in todo_list %}
					<tr>
					  <th scope="row">{{todo.id }}</th>
					  <td>{{ todo.title }}</td>
					  <td>
						{% if todo.complete == False %}
						<div class="alert alert-secondary" role="alert">In progress</div>
						{% else %}
						<div class="alert alert-success" role="alert">Completed</div>
						{% endif %}
					  </td>
					  <td>
						<a class="btn btn-success" href="/update/{{ todo.id }}">Update</a>
						<a class="btn btn-danger ms-1" href="/delete/{{ todo.id }}">Delete</a>
					  </td>
					</tr>
					{% endfor %}
				</tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>
</body>
</html>	
run the FastAPI app

C:\fastAPI\myapp>uvicorn app: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