article

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

Thursday, April 20, 2023

React-JS and Python Flask Multiple Image Upload with Show Uploaded Images

React-JS and Python Flask Multiple Image Upload with Show Uploaded Images

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

Flask + marshmallow for beautiful APIs
https://pypi.org/project/flask-marshmallow/

(venv) PS C:\flask_dev\flaskreact>pip install flask-marshmallow

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors
(venv) PS C:\flask_dev\flaskreact>pip install Werkzeug

C:\flask_dev\flaskreact\app.py

//C:\flask_dev\flaskreact\app.py
from flask import Flask, json, request, jsonify
import os
import urllib.request
from werkzeug.utils import secure_filename #pip install Werkzeug
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from flask_marshmallow import Marshmallow #ModuleNotFoundError: No module named 'flask_marshmallow' = pip install flask-marshmallow https://pypi.org/project/flask-marshmallow/

from models import db, Image

app = Flask(__name__)
CORS(app, supports_credentials=True)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration mysql                             Username:password@hostname/databasename
#app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:''@localhost/flaskreact'

db.init_app(app)
 
with app.app_context():
    db.create_all()

UPLOAD_FOLDER = 'static/uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

ma=Marshmallow(app)

class ImageSchema(ma.Schema):
    class Meta:
        fields = ('id','title')
        
image_schema = ImageSchema(many=True)

@app.route("/")
def hello_world():
    return "Hello, World!"

@app.route('/upload', methods=['POST'])
def upload_file():
    # check if the post request has the file part
    if 'files[]' not in request.files:
        resp = jsonify({
            "message": 'No file part in the request',
            "status": 'failed'
        })
        resp.status_code = 400
        return resp
 
    files = request.files.getlist('files[]')
     
    errors = {}
    success = False
     
    for file in files:      
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

            newFile = Image(title=filename)
            db.session.add(newFile)
            db.session.commit()

            success = True
        else:
            resp = jsonify({
                "message": 'File type is not allowed',
                "status": 'failed'
            })
            return resp
        
    if success and errors:
        errors['message'] = 'File(s) successfully uploaded'
        errors['status'] = 'failed'
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    if success:
        resp = jsonify({
            "message": 'Files successfully uploaded',
            "status": 'successs'
        })
        resp.status_code = 201
        return resp
    else:
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    
@app.route('/images',methods =['GET'])
def images():
    all_images = Image.query.all()
    results = image_schema.dump(all_images)
    return jsonify(results)
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
  
db = SQLAlchemy()
  
class Image(db.Model):
    __tablename__ = "images"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), index=True, unique=True)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

upload
Post : http://127.0.0.1:5000/upload
Body - Form-data
Key : files[] - files
Value : select images

Create folder static\uploads

run (venv) C:\flask_dev\flaskreact>flask run

React JS
https://create-react-app.dev/

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

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js

//C:\react-js\myreactdev\src\App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';
import './App.css';
 
class App extends Component {
    render() {
      return (
        <Router>
            <Routes>
              <Route exact path="/upload-image" element={<ImageUpload/>}/>
            </Routes>
        </Router>
      );
    }
}
export default App;
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\components\ImageUpload.js
//C:\react-js\myreactdev\src\components\ImageUpload.js
import React, { Component } from "react";
import axios from "axios";
import Images from "./Image";
 
export default class ImageUpload extends Component {
  constructor(props) {
    super(props);
  
    this.state = {
      image: "",
      responseMsg: {
        status: "",
        message: "",
        error: "",
      },
    };
  }
  
  // image onchange hander
  handleChange = (e) => {
    const imagesArray = [];
  
    for (let i = 0; i < e.target.files.length; i++) {
      this.fileValidate(e.target.files[i]);
      imagesArray.push(e.target.files[i]);
    }
    this.setState({
      image: imagesArray,
    });
  };
  
  // submit handler
  submitHandler = (e) => {
    e.preventDefault();
    const data = new FormData(); 
    for (let i = 0; i < this.state.image.length; i++) {
      data.append("files[]", this.state.image[i]);
    }
  
    axios.post("http://127.0.0.1:5000/upload", data)
    .then((response) => {
            console.log(response)
        if (response.status === 201) {
          this.setState({
            responseMsg: {
              status: response.data.status,
              message: response.data.message,
            },
          });
          setTimeout(() => {
            this.setState({
              image: "",
              responseMsg: "",
            });
          }, 100000);
  
          document.querySelector("#imageForm").reset();
          // getting uploaded images
          this.refs.child.getImages();
        }
            alert("Successfully Uploaded");
    })
    .catch((error) => {
        console.error(error); 
        if (error.response) {
            console.log(error.response)
            if (error.response.status === 401) {
                alert("Invalid credentials");
            }
        }
    });
     
  };
  
  // file validation
  fileValidate = (file) => {
    if (
      file.type === "image/png" ||
      file.type === "image/jpg" ||
      file.type === "image/jpeg"
    ) {
      this.setState({
        responseMsg: {
          error: "",
        },
      });
      return true;
    } else {
      this.setState({
        responseMsg: {
          error: "File type allowed only jpg, png, jpeg",
        },
      });
      return false;
    }
  };
  
  render() {
    return (
      <div className="container py-5">
        <div className="row">
          <div className="col-lg-12">
            <form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
              <div className="card shadow">
  
                {this.state.responseMsg.status === "successs" ? (
                  <div className="alert alert-success">
                    {this.state.responseMsg.message}
                  </div>
                ) : this.state.responseMsg.status === "failed" ? (
                  <div className="alert alert-danger">
                    {this.state.responseMsg.message}
                  </div>
                ) : (
                  ""
                )}
                <div className="card-header">
                  <h4 className="card-title fw-bold">
                    React-JS and Python Flask Multiple Image Upload with Show Uploaded Images
                  </h4>
                </div>
  
                <div className="card-body">
                  <div className="form-group py-2">
                    <label htmlFor="images">Images</label>
                    <input
                      type="file"
                      name="image"
                      multiple
                      onChange={this.handleChange}
                      className="form-control"
                    />
                    <span className="text-danger">
                      {this.state.responseMsg.error}
                    </span>
                  </div>
                </div>
  
                <div className="card-footer">
                  <button type="submit" className="btn btn-success">
                    Upload
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
  
		<Images ref="child" />
      </div>
    );
  }
}
C:\react-js\myreactdev\src\components\Image.js
//C:\react-js\myreactdev\src\components\Image.js
import React, { Component } from "react";
import axios from "axios";
 
export default class Images extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      title: [],
    };
  }
 
  componentDidMount() {
    this.getImages();
  }
 
  getImages = () => {
    axios
      .get("http://127.0.0.1:5000/images")
      .then((response) => {
        if (response.status === 200) {
          this.setState({
            title: response.data,
          });
          console.log(response.data);
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };
 
  render() {
    return (
      <div className="container pt-4">
        <div className="row">
          <div className="col-lg-12">
            <div className="card shadow">
              <div className="card-header">
                <h4 className="card-title fw-bold"> Images List </h4>
              </div>
              <div className="card-body">
                <div className="row">
 
                  {
                    this.state.title.length > 0 ? (
                        this.state.title.map((image) => (
                        <div className="col-lg-3" key={image.id}>
                            <img src={ "http://127.0.0.1:5000/static/uploads/" + image.title } className="img-fluid img-bordered" width="200px"
                            />
                        </div>
                        ))
                    ) : (
                        <h6 className="text-danger text-center">No Image Found </h6>
                    )
                  }
 
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Wednesday, April 19, 2023

React-JS and Python Flask Multiple Image Upload with validation

React-JS and Python Flask Multiple Image Upload with validation

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors
(venv) PS C:\flask_dev\flaskreact>pip install Werkzeug

C:\flask_dev\flaskreact\app.py

 
#C:\flask_dev\flaskreact\app.py
from flask import Flask, json, request, jsonify
import os
import urllib.request
from werkzeug.utils import secure_filename #pip install Werkzeug
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors

app = Flask(__name__)
CORS(app, supports_credentials=True)

app.secret_key = "caircocoders-ednalan"
 
UPLOAD_FOLDER = 'static/uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
 
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
 
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
 
@app.route('/')
def main():
    return 'Homepage'
 
@app.route('/upload', methods=['POST'])
def upload_file():
    # check if the post request has the file part
    if 'files[]' not in request.files:
        resp = jsonify({
            "message": 'No file part in the request',
            "status": 'failed'
        })
        resp.status_code = 400
        return resp
 
    files = request.files.getlist('files[]')
     
    errors = {}
    success = False
     
    for file in files:      
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            success = True
        else:
            resp = jsonify({
                "message": 'File type is not allowed',
                "status": 'failed'
            })
            return resp
        
    if success and errors:
        errors['message'] = 'File(s) successfully uploaded'
        errors['status'] = 'failed'
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    if success:
        resp = jsonify({
            "message": 'Files successfully uploaded',
            "status": 'successs'
        })
        resp.status_code = 201
        return resp
    else:
        resp = jsonify(errors)
        resp.status_code = 500
        return resp

if __name__ == '__main__':
    app.run(debug=True)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

upload
Post : http://127.0.0.1:5000/upload
Body - Form-data
Key : files[] - files
Value : select images

Create folder static\uploads

run (venv) C:\flask_dev\flaskreact>flask run

React JS
https://create-react-app.dev/

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

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';
import './App.css';

class App extends Component {
    render() {
      return (
        <Router>
            <Routes>
              <Route exact path="/upload-image" element={<ImageUpload/>}/>
            </Routes>
        </Router>
      );
    }
}
export default App;
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\components\ImageUpload.js

//C:\react-js\myreactdev\src\components\ImageUpload.js
import React, { Component } from "react";
import axios from "axios";

export default class ImageUpload extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      image: "",
      responseMsg: {
        status: "",
        message: "",
        error: "",
      },
    };
  }
 
  // image onchange hander
  handleChange = (e) => {
    const imagesArray = [];
 
    for (let i = 0; i < e.target.files.length; i++) {
      this.fileValidate(e.target.files[i]);
      imagesArray.push(e.target.files[i]);
    }
    this.setState({
      image: imagesArray,
    });
  };
 
  // submit handler
  submitHandler = (e) => {
    e.preventDefault();
    const data = new FormData(); 
    for (let i = 0; i < this.state.image.length; i++) {
      data.append("files[]", this.state.image[i]);
    }
 
    axios.post("http://127.0.0.1:5000/upload", data)
    .then((response) => {
		    console.log(response)
        if (response.status === 201) {
          this.setState({
            responseMsg: {
              status: response.data.status,
              message: response.data.message,
            },
          });
          setTimeout(() => {
            this.setState({
              image: "",
              responseMsg: "",
            });
          }, 100000);
 
          document.querySelector("#imageForm").reset();
        }
		    alert("Successfully Uploaded");
    })
    .catch((error) => {
        console.error(error); 
        if (error.response) {
            console.log(error.response)
            if (error.response.status === 401) {
                alert("Invalid credentials");
            }
        }
    });
	
  };
 
  // file validation
  fileValidate = (file) => {
    if (
      file.type === "image/png" ||
      file.type === "image/jpg" ||
      file.type === "image/jpeg"
    ) {
      this.setState({
        responseMsg: {
          error: "",
        },
      });
      return true;
    } else {
      this.setState({
        responseMsg: {
          error: "File type allowed only jpg, png, jpeg",
        },
      });
      return false;
    }
  };
 
  render() {
    return (
      <div className="container py-5">
        <div className="row">
          <div className="col-lg-12">
            <form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
              <div className="card shadow">
 
                {this.state.responseMsg.status === "successs" ? (
                  <div className="alert alert-success">
                    {this.state.responseMsg.message}
                  </div>
                ) : this.state.responseMsg.status === "failed" ? (
                  <div className="alert alert-danger">
                    {this.state.responseMsg.message}
                  </div>
                ) : (
                  ""
                )}
                <div className="card-header">
                  <h4 className="card-title fw-bold">
                    React-JS and Python Flask Multiple Image Upload with validation
                  </h4>
                </div>
 
                <div className="card-body">
                  <div className="form-group py-2">
                    <label htmlFor="images">Images</label>
                    <input
                      type="file"
                      name="image"
                      multiple
                      onChange={this.handleChange}
                      className="form-control"
                    />
                    <span className="text-danger">
                      {this.state.responseMsg.error}
                    </span>
                  </div>
                </div>
 
                <div className="card-footer">
                  <button type="submit" className="btn btn-success">
                    Upload
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
 
      </div>
    );
  }
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Tuesday, April 18, 2023

React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.

React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-JWT-Extended
Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting routes, but also many helpful (and optional) features built in to make working with JSON Web Tokens easier.
https://pypi.org/project/Flask-JWT-Extended/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-JWT-Extended

Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py

#C:\flask_dev\flaskreact\app.py
import json
from flask import Flask, request, jsonify
from datetime import datetime, timedelta, timezone
from flask_jwt_extended import create_access_token,get_jwt,get_jwt_identity, unset_jwt_cookies, jwt_required, JWTManager #pip install Flask-JWT-Extended = https://pypi.org/project/Flask-JWT-Extended/
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors

from models import db, User

api = Flask(__name__)
CORS(api, supports_credentials=True)

api.config['SECRET_KEY'] = 'cairocoders-ednalan'
api.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration  Mysql                            Username:password@hostname/databasename
#app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:''@localhost/flaskreact'

api.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
jwt = JWTManager(api)

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True

bcrypt = Bcrypt(api)    
db.init_app(api)
 
with api.app_context():
    db.create_all()

@api.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

@api.route('/logintoken', methods=["POST"])
def create_token():
    email = request.json.get("email", None)
    password = request.json.get("password", None)
 
    user = User.query.filter_by(email=email).first()
    #if email != "test" or password != "test":
    #    return {"msg": "Wrong email or password"}, 401
    if user is None:
        return jsonify({"error": "Wrong email or passwords"}), 401
     
    if not bcrypt.check_password_hash(user.password, password):
        return jsonify({"error": "Unauthorized"}), 401
     
    access_token = create_access_token(identity=email)
    #response = {"access_token":access_token}
 
    return jsonify({
        "email": email,
        "access_token": access_token
    })
    #return response

@api.route("/signup", methods=["POST"])
def signup():
    email = request.json["email"]
    password = request.json["password"]
  
    user_exists = User.query.filter_by(email=email).first() is not None
  
    if user_exists:
        return jsonify({"error": "Email already exists"}), 409
      
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(name="cairocoders Ednalan", email=email, password=hashed_password, about="sample about me")
    db.session.add(new_user)
    db.session.commit()
  
    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })

@api.after_request
def refresh_expiring_jwts(response):
    try:
        exp_timestamp = get_jwt()["exp"]
        now = datetime.now(timezone.utc)
        target_timestamp = datetime.timestamp(now + timedelta(minutes=30))
        if target_timestamp > exp_timestamp:
            access_token = create_access_token(identity=get_jwt_identity())
            data = response.get_json()
            if type(data) is dict:
                data["access_token"] = access_token 
                response.data = json.dumps(data)
        return response
    except (RuntimeError, KeyError):
        # Case where there is not a valid JWT. Just return the original respone
        return response

@api.route("/logout", methods=["POST"])
def logout():
    response = jsonify({"msg": "logout successful"})
    unset_jwt_cookies(response)
    return response

@api.route('/profile/<getemail>')
@jwt_required() 
def my_profile(getemail):
    print(getemail)
    if not getemail:
        return jsonify({"error": "Unauthorized Access"}), 401
      
    user = User.query.filter_by(email=getemail).first()
 
    response_body = {
        "id": user.id,
        "name": user.name,
        "email": user.email,
        "about" : user.about
    }
 
    return response_body
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
 
db = SQLAlchemy()
 
def get_uuid():
    return uuid4().hex
 
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    name = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
    about = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

Login
Post : http://127.0.0.1:5000/logintoken
Body - row - json
{
"email":"cairocoders@gmail.com",
"password":"123456"
}
Sign Up
Post : http://127.0.0.1:5000/signup
Body - row - json
{
"email":"cairocoders@gmail.com",
"password":"123456"
}
Profile
Get : http://127.0.0.1:5000/profile/cairocoders@gmail.com

Headers :
Key : Authorization
value : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY

Log Out
Get : http://127.0.0.1:5000/logout

run (venv) C:\flask_dev\flaskreact>flask run

React JS
https://create-react-app.dev/

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

Run
C:\react-js\myreactdev> npm start
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} from 'react-router-dom';

import Login from './components/Login'
import Header from './components/Header'
import Profile from './components/Profile'
import useToken from './components/useToken'

function App() {
	
	const { token, removeToken, setToken } = useToken();
	
	return (
		<div className="vh-100 gradient-custom">
		<div className="container">
		  <h1 className="page-header text-center">React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.</h1>
			
		  <BrowserRouter>
			<Header token={removeToken}/>
			{!token && token!=="" &&token!== undefined?  
			<Login setToken={setToken} />
			:(
			  <>
				<Routes>
				  <Route exact path="/profile" element={<Profile token={token} setToken={setToken}/>}></Route>
				</Routes>
			  </>
			)}
		  </BrowserRouter>
		</div>
		</div>
	);
}
    
export default App;
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\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";

function Login(props) {
     
    const [loginForm, setloginForm] = useState({
      email: "",
      password: ""
    })

	const navigate = useNavigate();
	
    function btnlogin(event) {
		axios({
			method: "POST",
			url:"http://127.0.0.1:5000/logintoken",
			data:{
			  email: loginForm.email,
			  password: loginForm.password
			 }
		})
		.then((response) => {
			console.log(response)
			props.setToken(response.data.access_token)
			alert("Successfully Login");
			localStorage.setItem('email', loginForm.email)
			navigate('/profile');
		}).catch((error) => {
			if (error.response) {
			  console.log(error.response)
			  console.log(error.response.status)
			  console.log(error.response.headers)
				if (error.response.status === 401) {
                    alert("Invalid credentials");
                }
			}
		})

		setloginForm(({
			email: "",
			password: ""}))

		event.preventDefault()
    }

    function handleChange(event) { 
      const {value, name} = event.target
      setloginForm(prevNote => ({
          ...prevNote, [name]: value})
      )}

    let imgs = [
      'https://as1.ftcdn.net/v2/jpg/03/39/70/90/1000_F_339709048_ZITR4wrVsOXCKdjHncdtabSNWpIhiaR7.jpg',
    ];
	
    return (
    <div>
        <div className="container h-50">
          <div className="container-fluid h-custom">
            <div className="row d-flex justify-content-center align-items-center h-50">
              <div className="col-md-9 col-lg-6 col-xl-5">
                <img src={imgs[0]} className="img-fluid"/>
              </div>
              <div className="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
                <form>
                  <div className="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
                    <p className="lead fw-normal mb-0 me-3">Log Into Your Account</p>
                  </div>
 
                  <div className="form-outline mb-4">
                    <input type="email" value={loginForm.email} onChange={handleChange} text={loginForm.email} name="email" id="form3Example3" className="form-control form-control-lg" placeholder="Enter a valid email address" />
                    <label className="form-label" for="form3Example3">Email address</label>
                  </div>
 
             
                  <div className="form-outline mb-3">
                    <input type="password" value={loginForm.password} onChange={handleChange} text={loginForm.password} name="password" id="form3Example4" className="form-control form-control-lg" placeholder="Enter password" />
                    <label className="form-label" for="form3Example4">Password</label>
                  </div>
 
                  <div className="d-flex justify-content-between align-items-center">
                    <div className="form-check mb-0">
                      <input className="form-check-input me-2" type="checkbox" value="" id="form2Example3" />
                      <label className="form-check-label" for="form2Example3">
                        Remember me
                      </label>
                    </div>
                    <a href="#!" className="text-body">Forgot password?</a>
                  </div>
 
                  <div className="text-center text-lg-start mt-4 pt-2">
                    <button type="button" className="btn btn-primary btn-lg" onClick={btnlogin} >Login</button>
                    <p className="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="/register" className="link-danger">Register</a></p>
                  </div>
 
                </form>
              </div>
            </div>
          </div>
        </div>
    </div>
  );
  
}
export default Login;
C:\react-js\myreactdev\src\components\Header.js
//C:\react-js\myreactdev\src\components\Header.js
import React, { } from "react";
import axios from "axios";
import {useNavigate} from "react-router-dom";

function Header(props) {

	const navigate = useNavigate();
	
	function logMeOut() {
		axios({
			method: "POST",
			url:"http://127.0.0.1:5000/logout",
		})
		.then((response) => {
			props.token()
			localStorage.removeItem('email')
			navigate("/");
		}).catch((error) => {
			if (error.response) {
				console.log(error.response)
				console.log(error.response.status)
				console.log(error.response.headers)
			}
		})
	}
	
	const logged = localStorage.getItem('email');
	
    return(
		<nav className="navbar navbar-expand-lg bg-light">
		  <div className="container-fluid">
			<a className="navbar-brand" href="#">Cairocoders</a>
			<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
			  <span className="navbar-toggler-icon"></span>
			</button>
			<div className="collapse navbar-collapse" id="navbarSupportedContent">
			  <ul className="navbar-nav me-auto mb-2 mb-lg-0">
				<li className="nav-item">
				  <a className="nav-link active" aria-current="page" href="#">Home</a>
				</li>
				<li className="nav-item">
				  <a className="nav-link" href="#">About</a>
				</li>
			  </ul>
				{!logged?
					<button className="btn btn-outline-success" type="submit">Login</button>
				:<button className="btn btn-outline-danger" type="submit" onClick={logMeOut}>Logout</button>}
			</div>
		  </div>
		</nav>
    )
}

export default Header;
C:\react-js\myreactdev\src\components\useToken.js
//C:\react-js\myreactdev\src\components\useToken.js
import { useState } from 'react';

function useToken() {

  function getToken() {
    const userToken = localStorage.getItem('token'); //https://javascript.info/localstorage
    return userToken && userToken
  }

  const [token, setToken] = useState(getToken());

  function saveToken(userToken) {
    localStorage.setItem('token', userToken);
    setToken(userToken);
  };

  function removeToken() {
    localStorage.removeItem("token");
    setToken(null);
  }

  return {
    setToken: saveToken,
    token,
    removeToken
  }

}

export default useToken;
C:\react-js\myreactdev\src\components\Profile.js
//C:\react-js\myreactdev\src\components\Profile.js
import React, { useState, useEffect } from "react";
import axios from "axios";

function Profile(props) {

    const [profileData, setProfileData] = useState(null)
	
    useEffect(() => {
        getUsers();
    }, []);
	
	const email = localStorage.getItem('email');
	
    function getUsers() { 
		axios({
		  method: "GET",
		  url:`http://127.0.0.1:5000/profile/${email}`, 
		  headers: {
			Authorization: 'Bearer ' + props.token
		  }
		})
		.then((response) => {
			console.log(response)
		  const res =response.data
		  res.access_token && props.setToken(res.access_token)
		  setProfileData(({
			profile_name: res.name,
			profile_email: res.email,
			about_me: res.about}))
		}).catch((error) => {
		  if (error.response) {
			console.log(error.response)
			console.log(error.response.status)
			console.log(error.response.headers)
			}
		})
    }
	
    let imgs = [
      'https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava1-bg.webp',
    ];


  return (
	  <div className="container">
		<div className="row d-flex justify-content-center align-items-center h-50">
		  <div className="col col-lg-12">
				<div className="card mb-3">
				
					{profileData && <div className="row g-0">
					<div className="col-md-4 bg-c-lite-green text-center text-white">
						<img src={imgs[0]} className="img-fluid my-5" width="150"/>
						<h5>{profileData.profile_name}</h5>
						<p>Coder</p>
						<i className="far fa-edit mb-5"></i>
					</div>
			
					<div className="col-md-8">
						<div className="card-body p-4">
							<h6>Your profile details:</h6>
							
							<div className="row pt-1">
							<div className="col-6 mb-3">
								<h6>Email</h6>
								<p className="text-muted">{profileData.profile_email}</p>
							</div>
							<div className="col-6 mb-3">
								<h6>Phone</h6>
								<p className="text-muted">123 456 789</p>
							</div>
							</div>
							<h6>About</h6>
							<div className="d-flex justify-content-start">
							{profileData.about_me}
							</div>
						</div>
					</div>	

				</div>
				}
			</div>
		  </div>
		</div>
	</div>
  );
}

export default Profile;
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
body {
  margin: 0;
  background-color: #ffffff;
}

.h-50 {
	margin-top:50px;
}	

.bg-c-lite-green {
    background: -webkit-gradient(linear, left top, right top, from(#f29263), to(#ee5a6f));
    background: linear-gradient(to right, #ee5a6f, #f29263);
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Saturday, April 15, 2023

React-JS and Python Flask CRUD Create, Read, Update and Delete MySql-Database

React-JS and Python Flask CRUD Create, Read, Update and Delete MySql-Database

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy

Flask + marshmallow for beautiful APIs
https://pypi.org/project/flask-marshmallow/

(venv) PS C:\flask_dev\flaskreact>pip install flask-marshmallow
(venv) PS C:\flask_dev\flaskreact>pip install Flask-Cors

C:\flask_dev\flaskreact\app.py

#C:\flask_dev\flaskreact\app.py
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
import datetime
from flask_marshmallow import Marshmallow #ModuleNotFoundError: No module named 'flask_marshmallow' = pip install flask-marshmallow https://pypi.org/project/flask-marshmallow/
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors

app = Flask(__name__)
CORS(app)

# Databse configuration                                  Username:password@hostname/databasename
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:''@localhost/flaskreact'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db=SQLAlchemy(app)

ma=Marshmallow(app)

class Users(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(100))
    email = db.Column(db.String(100))
    date = db.Column(db.DateTime,default=datetime.datetime.now)

    def __init__(self,name,email):
        self.name=name
        self.email=email


class UserSchema(ma.Schema):
    class Meta:
        fields = ('id','name','email','date')

user_schema = UserSchema()
users_schema = UserSchema(many=True)

@app.route('/listusers',methods =['GET'])
def listusers():
    all_users = Users.query.all()
    results = users_schema.dump(all_users)
    return jsonify(results)

@app.route('/userdetails/<id>',methods =['GET'])
def userdetails(id):
    user = Users.query.get(id)
    return user_schema.jsonify(user)

@app.route('/userupdate/<id>',methods = ['PUT'])
def userupdate(id):
    user = Users.query.get(id)

    name = request.json['name']
    email = request.json['email']

    user.name = name
    user.email = email

    db.session.commit()
    return user_schema.jsonify(user)

@app.route('/userdelete/<id>',methods=['DELETE'])
def userdelete(id):
    user = Users.query.get(id)
    db.session.delete(user)
    db.session.commit()
    return user_schema.jsonify(user)

@app.route('/useradd',methods=['POST'])
def useradd():
    name = request.json['name']
    email = request.json['email']

    users = Users(name,email)
    db.session.add(users)
    db.session.commit()
    return user_schema.jsonify(users)

if __name__=='__main__':
    app.run(debug=True)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

run (venv) C:\flask_dev\flaskreact>flask run

React JS
https://create-react-app.dev/

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

Run
C:\react-js\myreactdev> npm start
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} from 'react-router-dom';
  
import ListUserPage from "./pages/ListUserPage";
import CreateUser from './pages/CreateUser';
import EditUser from './pages/EditUser';

function App() {
  return (
    <div className="vh-100 gradient-custom">
    <div className="container">
      <h1 className="page-header text-center">React-JS and Python Flask CRUD Create, Read, Update and Delete MySql-Database</h1>
   
      <BrowserRouter>
        <Routes>
            <Route path="/" element={<ListUserPage />} />
            <Route path="/addnewuser" element={<CreateUser />} />
			<Route path="user/:id/edit" element={<EditUser />} />
        </Routes>
      </BrowserRouter>
    </div>
    </div>
  );
}
   
export default App;
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\pages\ListUserPage.js
//C:\react-js\myreactdev\src\pages\ListUserPage.js
import React, { useEffect, useState } from "react";
import axios from "axios" //npm install axios --save 
import {Link} from 'react-router-dom';
 
export default function ListUserPage(){
 
    const [users, setUsers] = useState([]);
    useEffect(() => {
        getUsers();
    }, []);
 
    function getUsers() {
        axios.get('http://127.0.0.1:5000/listusers').then(function(response) {
            console.log(response.data);
            setUsers(response.data);
        });
    }
	
    const deleteUser = (id) => {
        axios.delete(`http://127.0.0.1:5000/userdelete/${id}`).then(function(response){
            console.log(response.data);
            getUsers();
        });
		alert("Successfully Deleted");
    }
	
	return (
    <div>
        <div className="container h-100">
            <div className="row h-100">
                <div className="col-12">
                    <p><Link to="/addnewuser" className="btn btn-success">Add New User</Link> </p>
                    <h1>List Users</h1>
					<table class="table table-bordered table-striped">
						<thead>
							<tr>
								<th>#</th>
								<th>Name</th>
								<th>Email</th>
								<th>Date Added</th>
								<th>Actions</th>
							</tr>
						</thead>
						<tbody>
							{users.map((user, key) =>
								<tr key={key}>
									<td>{user.id}</td>
									<td>{user.name}</td>
									<td>{user.email}</td>
									<td>{user.date}</td>
									<td>
										<Link to={`user/${user.id}/edit`} className="btn btn-success" style={{marginRight: "10px"}}>Edit</Link>
										<button onClick={() => deleteUser(user.id)} className="btn btn-danger">Delete</button>
									</td>
								</tr>
							)}
						</tbody>
					</table>
                </div>
            </div>
        </div>
    </div>
  );
}
C:\react-js\myreactdev\src\pages\CreateUser.js
//C:\react-js\myreactdev\src\pages\CreateUser.js
import React, { useState  } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";

export default function CreateUser(){
 
    const navigate = useNavigate();
 
    const [inputs, setInputs] = useState([]);
 
    const handleChange = (event) => {
        const name = event.target.name;
        const value = event.target.value;
        setInputs(values => ({...values, [name]: value}));
    }
    const handleSubmit = (event) => {
        event.preventDefault();
 
        axios.post('http://127.0.0.1:5000/useradd', inputs).then(function(response){
            console.log(response.data);
            navigate('/');
        });
         
    }
	
	return (
    <div>
        <div className="container h-100">
			<div className="row">
				<div className="col-2"></div>
				<div className="col-8">
				<h1>Create user</h1>
				<form onSubmit={handleSubmit}>
					<div className="mb-3">
					  <label>Name</label>
					  <input type="text" className="form-control" name="name" onChange={handleChange} />
					</div>
					<div className="mb-3">
					  <label>Email</label>
					  <input type="text" className="form-control" name="email" onChange={handleChange} />
					</div>   
					<button type="submit" name="add" className="btn btn-primary">Save</button>
				</form>
				</div>
				<div className="col-2"></div>
			</div>
        </div>
    </div>
  );
}
C:\react-js\myreactdev\src\pages\EditUser.js
//C:\react-js\myreactdev\src\pages\EditUser.js
import React, { useState, useEffect  } from "react";
import axios from "axios";
import { useNavigate, useParams } from "react-router-dom";

export default function EditUser(){
 
    const navigate = useNavigate();
 
    const [inputs, setInputs] = useState([]);
 
    const {id} = useParams();
 
    useEffect(() => {
        getUser();
    }, []);
 
    function getUser() {
        axios.get(`http://127.0.0.1:5000/userdetails/${id}`).then(function(response) {
            console.log(response.data);
            setInputs(response.data);
        });
    }
 
    const handleChange = (event) => {
        const name = event.target.name;
        const value = event.target.value;
        setInputs(values => ({...values, [name]: value}));
    }
    const handleSubmit = (event) => {
        event.preventDefault();
 
        axios.put(`http://127.0.0.1:5000/userupdate/${id}`, inputs).then(function(response){
            console.log(response.data);
            navigate('/');
        });
         
    }
	
	return (
    <div>
        <div className="container h-100">
        <div className="row">
            <div className="col-2"></div>
            <div className="col-8">
            <h1>Edit user</h1>
            <form onSubmit={handleSubmit}>
                <div className="mb-3">
                  <label>Name</label>
                  <input type="text" value={inputs.name} className="form-control" name="name" onChange={handleChange} />
                </div>
                <div className="mb-3">
                  <label>Email</label>
                  <input type="text" value={inputs.email} className="form-control" name="email" onChange={handleChange} />
                </div>   
                <button type="submit" name="update" className="btn btn-primary">Save</button>
            </form>
            </div>
            <div className="col-2"></div>
        </div>
        </div>
    </div>
  );
}
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Friday, April 14, 2023

React and Python Flask Login Register

React and Python Flask Login Register

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py
Install requirements
Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

C:\flask_dev\flaskreact\app.py
 
#C:\flask_dev\flaskreact\app.py
from flask import Flask, request, jsonify, session
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from models import db, User

app = Flask(__name__)

app.config['SECRET_KEY'] = 'cairocoders-ednalan'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
 
bcrypt = Bcrypt(app) 
CORS(app, supports_credentials=True)
db.init_app(app)
 
with app.app_context():
    db.create_all()

@app.route("/")
def hello_world():
    return "Hello, World!"

@app.route("/signup", methods=["POST"])
def signup():
    email = request.json["email"]
    password = request.json["password"]

    user_exists = User.query.filter_by(email=email).first() is not None

    if user_exists:
        return jsonify({"error": "Email already exists"}), 409
    
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(email=email, password=hashed_password)
    db.session.add(new_user)
    db.session.commit()

    session["user_id"] = new_user.id

    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })

@app.route("/login", methods=["POST"])
def login_user():
    email = request.json["email"]
    password = request.json["password"]
 
    user = User.query.filter_by(email=email).first()
 
    if user is None:
        return jsonify({"error": "Unauthorized Access"}), 401
 
    if not bcrypt.check_password_hash(user.password, password):
        return jsonify({"error": "Unauthorized"}), 401
     
    session["user_id"] = user.id
 
    return jsonify({
        "id": user.id,
        "email": user.email
    })

if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4

db = SQLAlchemy()

def get_uuid():
    return uuid4().hex

class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

run (venv) C:\flask_dev\flaskreact>flask run

React JS
https://create-react-app.dev/

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

Run
C:\react-js\myreactdev> npm start
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 LandingPage from "./pages/LandingPage";
import LoginPage from './pages/LoginPage'
import RegisterPage from './pages/RegisterPage'

function App() {
  return (
    <div className="vh-100 gradient-custom">
    <div className="container">
      <h1 className="page-header text-center">React and Python Flask Login Register</h1>
  
      <BrowserRouter>
        <Routes>
            <Route path="/" element={<LandingPage />} />
            <Route path="/login" element={<LoginPage />} />
            <Route path="/register" element={<RegisterPage />} />
        </Routes>
      </BrowserRouter>
    </div>
    </div>
  );
}
  
export default App;
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\pages\LandingPage.js
//C:\react-js\myreactdev\src\pages\LandingPage.js
import React, { } from "react";

import {Link} from 'react-router-dom';

export default function LandingPage(){

  return (
    <div>
        <div className="container h-100">
            <div className="row h-100">
				<div className="col-12">
					<h1>Welcome to this React Application</h1>
					<p><Link to="/login" className="btn btn-success">Login</Link> | <Link to="/register" className="btn btn-success">register</Link> </p>
				</div>
            </div>
        </div>
    </div>
  );
}
C:\react-js\myreactdev\src\pages\LoginPage.js
//C:\react-js\myreactdev\src\pages\LoginPage.js
import React, { useState } from "react";
import axios from 'axios';
import {useNavigate} from "react-router-dom";

export default function LoginPage(){

    const [email,setEmail] = useState('');
    const [password,setPassword] = useState('');
  
	const navigate = useNavigate();
	
	const logInUser = () => {
        if(email.length === 0){
          alert("Email has left Blank!");
        }
        else if(password.length === 0){
          alert("password has left Blank!");
        }
        else{
            axios.post('http://127.0.0.1:5000/login', {
                email: email,
                password: password
            })
            .then(function (response) {
                console.log(response);
                //console.log(response.data);
				navigate("/");
            })
            .catch(function (error) {
                console.log(error, 'error');
				if (error.response.status === 401) {
					alert("Invalid credentials");
				}
            });
        }
    }

	let imgs = [
	  'https://as1.ftcdn.net/v2/jpg/03/39/70/90/1000_F_339709048_ZITR4wrVsOXCKdjHncdtabSNWpIhiaR7.jpg',
	];
	
  return (
    <div>
        <div className="container h-100">
		  <div className="container-fluid h-custom">
			<div className="row d-flex justify-content-center align-items-center h-100">
			  <div className="col-md-9 col-lg-6 col-xl-5">
				<img src={imgs[0]} className="img-fluid"/>
			  </div>
			  <div className="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
				<form>
				  <div className="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
					<p className="lead fw-normal mb-0 me-3">Log Into Your Account</p>
				  </div>

				  <div className="form-outline mb-4">
					<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} id="form3Example3" className="form-control form-control-lg" placeholder="Enter a valid email address" />
					<label className="form-label" for="form3Example3">Email address</label>
				  </div>

			
				  <div className="form-outline mb-3">
					<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} id="form3Example4" className="form-control form-control-lg" placeholder="Enter password" />
					<label className="form-label" for="form3Example4">Password</label>
				  </div>

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

				  <div className="text-center text-lg-start mt-4 pt-2">
					<button type="button" className="btn btn-primary btn-lg" onClick={logInUser} >Login</button>
					<p className="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="/register" className="link-danger">Register</a></p>
				  </div>

				</form>
			  </div>
			</div>
		  </div>
		</div>
    </div>
  );
}
C:\react-js\myreactdev\src\pages\RegisterPage.js
//C:\react-js\myreactdev\src\pages\RegisterPage.js
import React, { useState } from "react";
import axios from 'axios';
import {useNavigate} from "react-router-dom";

export default function RegisterPage(){

    const [email,setEmail] = useState('');
    const [password,setPassword] = useState('');
  
	const navigate = useNavigate();
	
	const registerUser = () => {
        axios.post('http://127.0.0.1:5000/signup', {
            email: email,
            password: password
        })
        .then(function (response) {
             console.log(response);
			navigate("/");
        })
        .catch(function (error) {
            console.log(error, 'error');
			if (error.response.status === 401) {
				alert("Invalid credentials");
			}
        });
	};
	
	let imgs = [
	  'https://as2.ftcdn.net/v2/jpg/03/39/70/91/1000_F_339709132_H9HSSTtTmayePcbARkTSB2qoZTubJ6bR.jpg',
	];
	
  return (
    <div>
        <div className="container h-100">
		  <div className="container-fluid h-custom">
			<div className="row d-flex justify-content-center align-items-center h-100">
			  <div className="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
				<form>
				  <div className="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
					<p className="lead fw-normal mb-0 me-3">Create Your Account</p>
				  </div>

				  <div className="form-outline mb-4">
					<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} id="form3Example3" className="form-control form-control-lg" placeholder="Enter a valid email address" />
					<label className="form-label" for="form3Example3">Email address</label>
				  </div>

			
				  <div className="form-outline mb-3">
					<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} id="form3Example4" className="form-control form-control-lg" placeholder="Enter password" />
					<label className="form-label" for="form3Example4">Password</label>
				  </div>

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

				  <div className="text-center text-lg-start mt-4 pt-2">
					<button type="button" className="btn btn-primary btn-lg" onClick={() => registerUser()} >Sign Up</button>
					<p className="small fw-bold mt-2 pt-1 mb-0">Login to your account <a href="/login" className="link-danger">Login</a></p>
				  </div>

				</form>
			  </div>
			  <div className="col-md-9 col-lg-6 col-xl-5">
				<img src={imgs[0]} className="img-fluid"/>
			  </div>
			</div>
		  </div>
		</div>
    </div>
  );
}
react-js\myreactdev\src\App.css
body {
  margin: 0;
  background-color: #ffffff;
}

.h-100 {
	margin-top:100px;
}	
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Python Flask Authentication Server-Sided Sessions

Python Flask Authentication Server-Sided Sessions

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask

Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

Flask-Session
Flask-Session is an extension for Flask that adds support for Server-side Session to your application.
https://flask-session.readthedocs.io/en/latest/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Session

python-dotenv
Python-dotenv reads key-value pairs from a .env file and can set them as environment variables.
https://pypi.org/project/python-dotenv/

(venv) PS C:\flask_dev\flaskreact>pip install python-dotenv

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

 
#C:\flask_dev\flaskreact\app.py
from flask import Flask, request, jsonify, session
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_session import Session #pip install Flask-Session = https://flask-session.readthedocs.io/en/latest/

from dotenv import load_dotenv #pip install python-dotenv = https://pypi.org/project/python-dotenv/
load_dotenv()

from models import db, User
from datetime import timedelta

app = Flask(__name__)

app.config['SESSION_PERMANENT'] = True
app.config['SESSION_TYPE'] = 'filesystem'
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=5)

# The maximum number of items the session stores before it starts deleting some, default 500
app.config['SESSION_FILE_THRESHOLD'] = 100  


app.config['SECRET_KEY'] = 'cairocoders-ednalan'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True

bcrypt = Bcrypt(app)
server_session = Session(app)
db.init_app(app)

with app.app_context():
    db.create_all()

@app.route("/profile")
def profile():
    user_id = session.get("user_id")

    if not user_id:
        return jsonify({"error": "Unauthorized Access"}), 401
    
    user = User.query.filter_by(id=user_id).first()
    return jsonify({
        "id": user.id,
        "email": user.email
    }) 

@app.route("/signup", methods=["POST"])
def signup():
    email = request.json["email"]
    password = request.json["password"]

    user_exists = User.query.filter_by(email=email).first() is not None

    if user_exists:
        return jsonify({"error": "Email already exists"}), 409

    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(email=email, password=hashed_password)
    db.session.add(new_user)
    db.session.commit()
    
    session["user_id"] = new_user.id

    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })

@app.route("/login", methods=["POST"])
def login_user():
    email = request.json["email"]
    password = request.json["password"]

    user = User.query.filter_by(email=email).first()

    if user is None:
        return jsonify({"error": "Unauthorized Access"}), 401

    if not bcrypt.check_password_hash(user.password, password):
        return jsonify({"error": "Unauthorized"}), 401
    
    session["user_id"] = user.id

    return jsonify({
        "id": user.id,
        "email": user.email
    })

@app.route("/logout", methods=["POST"])
def logout_user():
    session.pop("user_id")
    return "200"

if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4

db = SQLAlchemy()

def get_uuid():
    return uuid4().hex

class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

run (venv) C:\flask_dev\flaskreact>flask run

Thursday, April 13, 2023

Python Flask and React

Python Flask and React

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py
 
#C:\flask_dev\flaskreact\app.py
from flask import Flask
from flask_restful import Api, Resource, reqparse #ModuleNotFoundError: No module named 'flask_restful' = pip install flask-restful
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from api.ApiHandler import ApiHandler

app = Flask(__name__)

CORS(app)
api = Api(app)

api.add_resource(ApiHandler, '/flask')

@app.route("/")
def hello_world():
    return "

Hello, World!

" if __name__ == '__main__': app.run(debug=True)
C:\flask_dev\flaskreact\api\ApiHandler.py
 
#C:\flask_dev\flaskreact\api\ApiHandler.py
from flask_restful import Api, Resource

class ApiHandler(Resource):
  def get(self):
    return {
      'resultStatus': 'SUCCESS',
      'message': "Hello Api Handler ApiHandler.py"
      }
flask run (venv) C:\flask_dev\flaskreact>flask run:
React JS

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

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

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

function App() {
  const [getMessage, setGetMessage] = useState({})

  useEffect(()=>{
    axios.get('http://localhost:5000/flask').then(response => {
      console.log("SUCCESS", response)
      setGetMessage(response)
    }).catch(error => {
      console.log(error)
    })

  }, [])
  return (
    <div className="App">
      <header className="App-header">
        <p><h1>Python Flask and React</h1></p>
        <div>{getMessage.status === 200 ? 
          <h3>{getMessage.data.message}</h3>
          :
          <h3>LOADING</h3>}</div>
      </header>
    </div>
  );
}

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

Wednesday, March 29, 2023

Convert Python Flask App to exe File || Convert py to exe file

Convert Python Flask App to exe File || Convert py to exe file

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask

C:\flask_dev\flasktoexe\app.py
#C:\flask_dev\flasktoexe\app.py
from flask import Flask,render_template

import webview

app = Flask(__name__, static_folder='./static', template_folder='./templates')

@app.route('/')
def home():
    return render_template("index.html",name='cairocoders Home page')

@app.route('/page2')
def page2():
    return render_template("page2.html",name='cairocoders page 2')
    
webview.create_window('Flask to exe', app)

if __name__ == '__main__':
    #app.run(debug=True)
    webview.start()
install pywebview
pywebview is a lightweight cross-platform wrapper around a webview component that allows to display HTML content in its own native GUI window.
https://pypi.org/project/pywebview/
C:\flask_dev>pip install pywebview

templates/index.html
//templates/index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Calculator</title>
    <link href="{{ url_for('static',filename='style.css') }}" rel="stylesheet">
    <script src="{{ url_for('static',filename='script.js') }}" defer></script>
  </head>
  <body>
    <div class="calculator-grid">
    <div class="output">
    <div data-previous-operand class="previous-operand"></div>
    <div data-current-operand class="current-operand"></div>
    </div>
    <button data-all-clear class="span-two">AC</button>
    <button data-delete class="operation">DEL</button>
    <button data-operation class="operation">÷</button>
    <button data-number>1</button>
    <button data-number>2</button>
    <button data-number>3</button>
    <button data-operation class="operation">*</button>
    <button data-number>4</button>
    <button data-number>5</button>
    <button data-number>6</button>
    <button data-operation class="operation">+</button>
    <button data-number>7</button>
    <button data-number>8</button>
    <button data-number>9</button>
    <button data-operation class="operation">-</button>
    <button data-number>.</button>
    <button data-number>0</button>
    <button data-equals class="span-two">=</button>

    </div>
    <a href="/page2">Page 2</a>
  </body>
</html>
templates/page2.html
//templates/page2.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Page 2</title>
  </head>
  <body>
<h1>Page2</h1>
<a href="/">Home</a>
  </body>
</html>
static/style.html
//static/style.html
*, *::before, *::after {
  box-sizing: border-box;
  font-family: Gotham Rounded, sans-serif;
  font-weight: normal;
}

body {
  margin: 0;
  padding: 0;
  background: linear-gradient(to right, #0187d0, #a5c2c8);
  }

  .calculator-grid {
    display: grid;
    justify-content: center;
    align-content: center;
    min-height: 100vh;
    grid-template-columns: repeat(4, 100px);
    grid-template-rows: minmax(120px, auto) repeat(5, 100px);
    }

    .calculator-grid > button {
      cursor: pointer;
      font-size: 2rem;
      border: 1px, solid #FFFFFF;
      outline: none;     
    }

      .calculator-grid > button:hover {
        background-color: #a5a5a5;
      }

      .span-two {
        grid-column: span 2;
        color: #adf802;
        background-color: #fd9502;
      }
      .operation {
        color: #ffffff;
        background-color: #fd9502;
      }
      .output{
        grid-column: 1 / -1;
        background-color: rgba(0, 0, 0, 0.75);
        display: flex;
        align-items: flex-end;
        justify-content: space-around;
        flex-direction: column;
        padding: 10px;
        word-wrap: break-word;
        word-break: break-all;
      }

      .output .previous-operand{
        color: rgba(255,255, 255, 0.75);
        font-size: 1.5rem;
      }

      .output .current-operand{
        color: white;
        font-size: 2.5rem;
      }
static/script.js
//static/script.js
class Calculator {
    constructor(previousOperandTextElement, currentOperandTextElement) {
      this.previousOperandTextElement = previousOperandTextElement
      this.currentOperandTextElement = currentOperandTextElement
      this.clear()
    }
  
    clear() {
      this.currentOperand = ''
      this.previousOperand = ''
      this.operation = undefined
    }
  
    delete() {
      this.currentOperand = this.currentOperand.toString().slice(0, -1)
    }
  
    appendNumber(number) {
      if (number === '.' && this.currentOperand.includes('.')) return
      this.currentOperand = this.currentOperand.toString() + number.toString()
    }
  
    chooseOperation(operation) {
      if (this.currentOperand === '') return
      if (this.previousOperand !== '') {
        this.compute()
      }
      this.operation = operation
      this.previousOperand = this.currentOperand
      this.currentOperand = ''
    }
  
    compute() {
      let computation
      const prev = parseFloat(this.previousOperand)
      const current = parseFloat(this.currentOperand)
      if (isNaN(prev) || isNaN(current)) return
      switch (this.operation) {
        case '+':
          computation = prev + current
          break
        case '-':
          computation = prev - current
          break
        case '*':
          computation = prev * current
          break
        case '÷':
          computation = prev / current
          break
        default:
          return
      }
      this.currentOperand = computation
      this.operation = undefined
      this.previousOperand = ''
    }
  
    getDisplayNumber(number) {
      const stringNumber = number.toString()
      const integerDigits = parseFloat(stringNumber.split('.')[0])
      const decimalDigits = stringNumber.split('.')[1]
      let integerDisplay
      if (isNaN(integerDigits)) {
        integerDisplay = ''
      } else {
        integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 })
      }
      if (decimalDigits != null) {
        return `${integerDisplay}.${decimalDigits}`
      } else {
        return integerDisplay
      }
    }
  
    updateDisplay() {
      this.currentOperandTextElement.innerText =
        this.getDisplayNumber(this.currentOperand)
      if (this.operation != null) {
        this.previousOperandTextElement.innerText =
          `${this.getDisplayNumber(this.previousOperand)} ${this.operation}`
      } else {
        this.previousOperandTextElement.innerText = ''
      }
    }
  }
  
  
  const numberButtons = document.querySelectorAll('[data-number]')
  const operationButtons = document.querySelectorAll('[data-operation]')
  const equalsButton = document.querySelector('[data-equals]')
  const deleteButton = document.querySelector('[data-delete]')
  const allClearButton = document.querySelector('[data-all-clear]')
  const previousOperandTextElement = document.querySelector('[data-previous-operand]')
  const currentOperandTextElement = document.querySelector('[data-current-operand]')
  
  const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)
  
  numberButtons.forEach(button => {
    button.addEventListener('click', () => {
      calculator.appendNumber(button.innerText)
      calculator.updateDisplay()
    })
  })
  
  operationButtons.forEach(button => {
    button.addEventListener('click', () => {
      calculator.chooseOperation(button.innerText)
      calculator.updateDisplay()
    })
  })
  
  equalsButton.addEventListener('click', button => {
    calculator.compute()
    calculator.updateDisplay()
  })
  
  allClearButton.addEventListener('click', button => {
    calculator.clear()
    calculator.updateDisplay()
  })
  
  deleteButton.addEventListener('click', button => {
    calculator.delete()
    calculator.updateDisplay()
  })
  
  document.addEventListener('keydown', function (event) {
    let patternForNumbers = /[0-9]/g;
    let patternForOperators = /[+\-*\/]/g
    if (event.key.match(patternForNumbers)) {
      event.preventDefault();
      calculator.appendNumber(event.key)
      calculator.updateDisplay()
    }
    if (event.key === '.') {
      event.preventDefault();
      calculator.appendNumber(event.key)
      calculator.updateDisplay()
    }
    if (event.key.match(patternForOperators)) {
      event.preventDefault();
      calculator.chooseOperation(event.key)
      calculator.updateDisplay()
    }
    if (event.key === 'Enter' || event.key === '=') {
      event.preventDefault();
      calculator.compute()
      calculator.updateDisplay()
    }
    if (event.key === "Backspace") {
      event.preventDefault();
      calculator.delete()
      calculator.updateDisplay()
    }
    if (event.key == 'Delete') {
      event.preventDefault();
      calculator.clear()
      calculator.updateDisplay()
    }
  
  });
run (venv) C:\flask_dev\flasktoexe>flask run

convert to exe file

install Auto PY to EXE
Converts .py to .exe using a simple graphical interface.

https://pypi.org/project/auto-py-to-exe/
C:\>pip install auto-py-to-exe

execute terminal:
C:\>auto-py-to-exe

Monday, February 13, 2023

Python Flask Simple To Do - SQLAlchemy

Python Flask Simple To Do - SQLAlchemy

pip install Flask
pip install Flask-SQLAlchemy

todo/app.py
//todo/app.py
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


class Todo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    complete = db.Column(db.Boolean)


db.create_all()

@app.route('/')
def home():
    todo_list = db.session.query(Todo).all()
    # return "Hello, World!"
    return render_template("index.html", todo_list=todo_list)


@app.route("/add", methods=["POST"])
def add():
    title = request.form.get("title")
    new_todo = Todo(title=title, complete=False)
    db.session.add(new_todo)
    db.session.commit()
    return redirect(url_for("home"))

@app.route("/update/<int:todo_id>")
def update(todo_id):
    todo = db.session.query(Todo).filter(Todo.id == todo_id).first()
    todo.complete = not todo.complete
    db.session.commit()
    return redirect(url_for("home"))

@app.route("/delete/<int:todo_id>")
def delete(todo_id):
    todo = db.session.query(Todo).filter(Todo.id == todo_id).first()
    db.session.delete(todo)
    db.session.commit()
    return redirect(url_for("home"))

if __name__ == '__main__':
	app.run(debug=True)
Bootstrap 5
https://getbootstrap.com/docs/5.0/getting-started/introduction/

templates/index.html
//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 Flask Simple To Do - SQLAlchemy</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 Flask Simple To Do - SQLAlchemy</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 (venv) C:\flask_dev\todo>flask run

Tuesday, January 25, 2022

Python Flask Vuejs CRUD (Create, Read, Update and Delete) with Mysql

Python Flask Vuejs CRUD (Create, Read, Update and Delete) with Mysql


https://bootstrap-vue.org/

https://bootstrap-vue.org/docs/components/modal#modals

https://vuejs.org/v2/guide/

Install Flask-CORS extension https://flask-cors.readthedocs.io/

$ pip install -U flask-cors
from flask_cors import CORS

https://github.com/axios/axios

CREATE TABLE `members` (
  `id` int(11) NOT NULL,
  `firstname` varchar(30) NOT NULL,
  `lastname` varchar(30) NOT NULL,
  `address` varchar(150) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `members` (`id`, `firstname`, `lastname`, `address`) VALUES
(1, 'Airi', 'Satou', 'Tokyo'),
(2, 'Angelica ', 'Ramos', 'London'),
(3, 'Ashton ', 'Cox', 'San Francisco'),
(4, 'Bradley', 'Greer', 'London'),
(5, 'Brenden ', 'Wagner', 'San Francisco'),
(40, 'Brielle', 'Williamson', 'New York'),
(54, 'Bruno', 'Nash', 'London'),
(55, 'Caesar', 'Vance', 'New York'),
(56, 'Cara', 'Stevens', 'New York'),
(57, 'Cedric', 'Kelly', 'Edinburgh'),
(58, 'Zorita Serran', 'Satou', 'Tokyo'),
(59, 'Angelica ', 'Ramos', 'London'),
(60, 'Ashton ', 'Cox', 'San Francisco'),
(61, 'Bradley ', 'Greer', 'London'),
(62, 'Brenden ', 'Wagner', 'San Francisco'),
(63, 'Brielle', 'Williamson', 'New York'),
(64, 'Bruno', 'Nash', 'London'),
(65, 'Caesar', 'Vance', 'New York'),
(66, 'Cara', 'Stevens', 'New York'),
(67, 'Brenden ', 'Wagner', 'San Francisco'),
(68, 'Brielle', 'Williamson', 'New York'),
(69, 'Bruno', 'Nash', 'London'),
(70, 'Caesar', 'Vance', 'New York'),
(71, 'Cara', 'Stevens', 'New York'),
(72, 'Cedric', 'Kelly', 'Edinburgh');

ALTER TABLE `members`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `members`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=73;
crud.html
//crud.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
<title>Python Flask Vuejs CRUD (Create, Read, Update and Delete) with PHP Mysql</title>
</head>
<body>
<div class="container" id="vuejscrudapp">
	<div class="row">
        <div class="col-md-12 mt-5">
          <h1 class="text-center">Python Flask Vuejs CRUD (Create, Read, Update and Delete) with PHP Mysql</h1>
          <hr>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
          <!-- Add Records -->
        <div>
            <b-button id="show-btn" @click="showModal('my-modal')">Add Records</b-button>
 
            <b-modal ref="my-modal" hide-footer title="Add Records">
              <div>
                <form action="" @submit.prevent="onSubmit">
                  <div class="form-group">
                    <label for="">First Name</label>
                    <input type="text" v-model="firstname" class="form-control">
                  </div>
                  <div class="form-group">
                    <label for="">Last Name</label>
                    <input type="text" v-model="lastname" class="form-control">
                  </div>
				  <div class="form-group">
                    <label for="">Address</label>
                    <input type="text" v-model="address" class="form-control">
                  </div>
                  <div class="form-group">
                    <button class="btn btn-sm btn-outline-info">Add Records</button>
                  </div>
                </form>
              </div>
              <b-button class="mt-3" variant="outline-danger" block @click="hideModal('my-modal')">Close Me</b-button>
            </b-modal>
        </div>
 
        <!-- Update Record -->
        <div>
            <b-modal ref="my-modal1" hide-footer title="Update Record">
              <div>
                <form action="" @submit.prevent="onUpdate">
                  <div class="form-group">
                    <label for="">First Name</label>
                    <input type="text" v-model="edit_id">
                    <input type="text" v-model="edit_firstname" class="form-control">
                  </div>
                  <div class="form-group">
                    <label for="">Last Name</label>
                    <input type="text" v-model="edit_lastname" class="form-control">
                  </div>
				  <div class="form-group">
                    <label for="">Address</label>
                    <input type="text" v-model="edit_address" class="form-control">
                  </div>
                  <div class="form-group">
                    <button class="btn btn-sm btn-outline-info">Update Record</button>
                  </div>
                </form>
              </div>
              <b-button class="mt-3" variant="outline-danger" block @click="hideModal('my-modal1')">Close Me</b-button>
            </b-modal>
          </div>
		  
        </div>
	</div>
	  
    <div class="row">
        <div class="col-md-12">
          <table class="table table-striped table-bordered">
            <thead>
              <tr>
                <th>ID</th>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Address</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(record, i) in records" :key="record.id">
                <td>{{i + 1}}</td>
                <td>{{record.firstname}}</td>
                <td>{{record.lastname}}</td>
                <td>{{record.address}}</td>
                <td>
                  <button @click="deleteRecord(record.id)" class="btn btn-sm btn-outline-danger">Delete</button>
                  <button @click="editRecord(record.id)" class="btn btn-sm btn-outline-info">Edit</button>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
    </div>
</div>
 
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- BootstrapVue js -->
<script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<!-- Axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
    var app = new Vue({
        el: '#vuejscrudapp',
        data: {
			firstname: '',
			lastname: '',
			address: '',
			records: [],
			edit_id: '',
			edit_firstname: '',
			edit_lastname: '',
			edit_address: ''
        },
 
        methods: {
			showModal(id) {
				this.$refs[id].show()
			},
			hideModal(id) {
				this.$refs[id].hide()
			},
 
			onSubmit(){
				if (this.firstname !== '' && this.lastname !== '' && this.address !== '') {
					var config = { headers: {  
						'Content-Type': 'application/json',
						'Access-Control-Allow-Origin': '*'}
					}
					axios.post("http://127.0.0.1:5000/insert", 
						{ firstname : this.firstname, lastname : this.lastname, address : this.address}, config
					)
					.then(res => {
						console.log(res)
						alert('New record Successfully added')
						this.firstname = ''
						this.lastname = ''
						this.address = ''
		 
						app.hideModal('my-modal')
						app.getRecords()
					})
					.catch(err => {
						console.log(err)
					})
				}else{
				  alert('empty')
				}
			},
 
			getRecords(){
				axios({
				  url: 'http://localhost:5000/',
				  method: 'get'
				})
				.then(res => {
				  console.log(res)
				  this.records = res.data.members
				})
				.catch(err => {
				  console.log(err)
				})
			},
 
			editRecord(id){
				axios.get("http://127.0.0.1:5000/edit/" + id)
				.then(res => {
					console.log(res.data)
				    this.edit_id = res.data.editmember['id']
				    this.edit_firstname = res.data.editmember['firstname']
				    this.edit_lastname = res.data.editmember['lastname']
				    this.edit_address = res.data.editmember['address']
					app.showModal('my-modal1')
				})
				.catch(err => {
				  console.log(err)
				})
			},
			
			onUpdate(){
				if (this.edit_firstname !== '' && this.edit_lastname !== '' && this.edit_address !== '' && this.edit_id !== '') {

				    var config = { headers: {  
						'Content-Type': 'application/json',
						'Access-Control-Allow-Origin': '*'}
					}
					axios.post("http://127.0.0.1:5000/update", 
						{ edit_id : this.edit_id, edit_firstname : this.edit_firstname, edit_lastname : this.edit_lastname, edit_address : this.edit_address}, config
					)
					.then(res => {
						console.log(res)
						alert('record update');
		 
						this.edit_firstname = '';
						this.edit_lastname = '';
						this.edit_address = '';
						this.edit_id = '';
		 
						app.hideModal('my-modal1');
						app.getRecords();
					})
					  .catch(err => {
						console.log(err)
					})
	 
				}else{
				  alert('empty')
				}
			},
			
			deleteRecord(id){
				if (window.confirm('Delete this record')) {
					axios.get("http://127.0.0.1:5000/delete/" + id)
					.then(res => {
						console.log(res)
						alert('delete successfully')
						app.getRecords();
					})
					.catch(err => {
						console.log(err)
					})
				}
			},
		
        },
		  
        mounted: function(){
          this.getRecords()
        }
    })
</script>
</body>   
</html>
app.py
//app.py
from flask import Flask, jsonify, request
from flask_cors import CORS
from flaskext.mysql import MySQL #pip install flask-mysql
import pymysql

MEMBERS = [
    {
        'id': '1',
        'firstname': 'cairocoders',
        'lastname': 'Ednalan',
        'address': 'Olongapo city'
    },
    {
        'id': '2',
        'firstname': 'clydey',
        'lastname': 'Ednalan',
        'address': 'Angles city'
    }
]
# configuration
DEBUG = True

# instantiate the app
app = Flask(__name__)
app.config.from_object(__name__)
    
mysql = MySQL()
   
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = ''
app.config['MYSQL_DATABASE_DB'] = 'testingdb'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)

# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})


# sanity check route
@app.route('/ping', methods=['GET'])
def ping_pong():
    return jsonify('pong!')

@app.route('/members', methods=['GET'])
def all_members():
    return jsonify({
        'status': 'success',
        'members': MEMBERS
    })

@app.route('/')
def home():
    conn = mysql.connect()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    try:
        cursor.execute("SELECT * from members order by id")
        userslist = cursor.fetchall()
        return jsonify({
            'status': 'success',
            'members': userslist
        })
    except Exception as e:
        print(e)
    finally:
        cursor.close() 
        conn.close()

@app.route('/insert', methods=['GET', 'POST'])
def insert():
    conn = mysql.connect()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json(silent=True)
        firstname = post_data.get('firstname')
        lastname = post_data.get('lastname')
        address = post_data.get('address')

        print(firstname)
        print(lastname)

        sql = "INSERT INTO members(firstname,lastname,address) VALUES(%s, %s, %s)"
        data = (firstname, lastname, address)
        conn = mysql.connect()
        cursor = conn.cursor()
        cursor.execute(sql, data)
        conn.commit()

        response_object['message'] = "Successfully Added"
    return jsonify(response_object)

@app.route('/edit/<string:id>', methods=['GET', 'POST'])
def edit(id):
    conn = mysql.connect()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    print(id)
    cursor.execute("SELECT * FROM members WHERE id = %s", [id])
    row = cursor.fetchone() 

    return jsonify({
        'status': 'success',
        'editmember': row
    })

@app.route('/update', methods=['GET', 'POST'])
def update():
    conn = mysql.connect()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json(silent=True)
        edit_id = post_data.get('edit_id')
        edit_firstname = post_data.get('edit_firstname')
        edit_lastname = post_data.get('edit_lastname')
        edit_address = post_data.get('edit_address')

        print(edit_firstname)
        print(edit_lastname)

        cursor.execute ("UPDATE members SET firstname=%s, lastname=%s, address=%s WHERE id=%s",(edit_firstname, edit_lastname, edit_address, edit_id))
        conn.commit()
        cursor.close()

        response_object['message'] = "Successfully Updated"
    return jsonify(response_object)

@app.route('/delete/<string:id>', methods=['GET', 'POST'])
def delete(id):
    conn = mysql.connect()
    cursor = conn.cursor(pymysql.cursors.DictCursor)
  
    response_object = {'status': 'success'}

    cursor.execute("DELETE FROM members WHERE id = %s", [id])
    conn.commit()
    cursor.close()
    response_object['message'] = "Successfully Deleted"
    return jsonify(response_object)

if __name__ == '__main__':
    app.run()

Related Post