├── .gitignore ├── Dockerfile ├── README.md ├── app.py ├── config.py ├── database └── db.sql ├── docker-compose.yml ├── index.py ├── models └── contact.py ├── requirements.txt ├── routes └── contacts.py ├── static └── css │ └── main.css ├── templates ├── about.html ├── index.html ├── layout.html ├── partials │ ├── _message.html │ ├── _navbar.html │ └── _taskForm.html └── update.html └── utils └── db.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | __pycache__ 3 | 4 | static/css/bootstrap.min.css 5 | 6 | .env -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | 3 | ADD . /code 4 | 5 | WORKDIR /code 6 | 7 | RUN pip install -r requirements.txt 8 | 9 | CMD python index.py 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Flask SQLAlchemy CRUD 2 | 3 | this project is a CRUD application using flask and mysql using SQLAlchemy 4 | 5 | ### Installation with docker-compose 6 | 7 | ``` 8 | git clone https://github.com/FaztWeb/flask-sqlalchemy-crud 9 | cd flask-sqlalchemy-crud 10 | docker-compose up 11 | ``` 12 | 13 | ### Manual Installation 14 | 15 | ##### Requirements 16 | 17 | * Python3 18 | * Mysql 19 | 20 | before run the app you must create the following environnment variables: 21 | 22 | ``` 23 | MYSQL_USER= 24 | MYSQL_PASSWORD= 25 | MYSQL_DATABASE= 26 | MYSQL_HOST= 27 | MYSQL_PORT= 28 | ``` 29 | 30 | ``` 31 | git clone https://github.com/FaztWeb/flask-sqlalchemy-crud 32 | cd flask-sqlalchemy-crud 33 | pip install -r requirements.txt 34 | python index.py 35 | ``` 36 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from routes.contacts import contacts 3 | from flask_sqlalchemy import SQLAlchemy 4 | from config import DATABASE_CONNECTION_URI 5 | 6 | app = Flask(__name__) 7 | 8 | # settings 9 | app.secret_key = 'mysecret' 10 | print(DATABASE_CONNECTION_URI) 11 | app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE_CONNECTION_URI 12 | app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 13 | 14 | # no cache 15 | app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 16 | 17 | SQLAlchemy(app) 18 | 19 | app.register_blueprint(contacts) 20 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | from dotenv import load_dotenv 2 | import os 3 | 4 | load_dotenv() 5 | 6 | user = os.environ["MYSQL_USER"] 7 | password = os.environ["MYSQL_PASSWORD"] 8 | host = os.environ["MYSQL_HOST"] 9 | database = os.environ["MYSQL_DATABASE"] 10 | 11 | DATABASE_CONNECTION_URI = f'mysql://{user}:{password}@{host}/{database}' 12 | print(DATABASE_CONNECTION_URI) 13 | -------------------------------------------------------------------------------- /database/db.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE contactsdb; -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | flask_app: 5 | container_name: "web" 6 | build: . 7 | ports: 8 | - "5000:5000" 9 | volumes: 10 | - .:/code 11 | links: 12 | - flask_db 13 | flask_db: 14 | container_name: "database" 15 | image: mysql 16 | environment: 17 | MYSQL_ROOT_PASSWORD: root 18 | MYSQL_DATABASE: contactsdb 19 | ports: 20 | - "3306:3306" -------------------------------------------------------------------------------- /index.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | from utils.db import db 3 | 4 | with app.app_context(): 5 | db.create_all() 6 | 7 | if __name__ == '__main__': 8 | app.run(debug=True, host="0.0.0.0") 9 | -------------------------------------------------------------------------------- /models/contact.py: -------------------------------------------------------------------------------- 1 | from utils.db import db 2 | 3 | 4 | class Contact(db.Model): 5 | id = db.Column(db.Integer, primary_key=True) 6 | fullname = db.Column(db.String(100)) 7 | email = db.Column(db.String(100)) 8 | phone = db.Column(db.String(100)) 9 | 10 | def __init__(self, fullname, email, phone): 11 | self.fullname = fullname 12 | self.email = email 13 | self.phone = phone 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | autopep8==1.6.0 2 | click==8.0.3 3 | Flask==2.0.2 4 | Flask-SQLAlchemy==2.5.1 5 | greenlet==1.1.2 6 | itsdangerous==2.0.1 7 | Jinja2==3.0.2 8 | MarkupSafe==2.0.1 9 | mysqlclient==2.0.3 10 | pycodestyle==2.8.0 11 | python-dotenv==0.19.1 12 | SQLAlchemy==1.4.26 13 | toml==0.10.2 14 | Werkzeug==2.0.2 15 | -------------------------------------------------------------------------------- /routes/contacts.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template, request, redirect, url_for, flash 2 | from models.contact import Contact 3 | from utils.db import db 4 | 5 | contacts = Blueprint("contacts", __name__) 6 | 7 | 8 | @contacts.route('/') 9 | def index(): 10 | contacts = Contact.query.all() 11 | return render_template('index.html', contacts=contacts) 12 | 13 | 14 | @contacts.route('/new', methods=['POST']) 15 | def add_contact(): 16 | if request.method == 'POST': 17 | 18 | # receive data from the form 19 | fullname = request.form['fullname'] 20 | email = request.form['email'] 21 | phone = request.form['phone'] 22 | 23 | # create a new Contact object 24 | new_contact = Contact(fullname, email, phone) 25 | 26 | # save the object into the database 27 | db.session.add(new_contact) 28 | db.session.commit() 29 | 30 | flash('Contact added successfully!') 31 | 32 | return redirect(url_for('contacts.index')) 33 | 34 | 35 | @contacts.route("/update/", methods=["GET", "POST"]) 36 | def update(id): 37 | # get contact by Id 38 | print(id) 39 | contact = Contact.query.get(id) 40 | 41 | if request.method == "POST": 42 | contact.fullname = request.form['fullname'] 43 | contact.email = request.form['email'] 44 | contact.phone = request.form['phone'] 45 | 46 | db.session.commit() 47 | 48 | flash('Contact updated successfully!') 49 | 50 | return redirect(url_for('contacts.index')) 51 | 52 | return render_template("update.html", contact=contact) 53 | 54 | 55 | @contacts.route("/delete/", methods=["GET"]) 56 | def delete(id): 57 | contact = Contact.query.get(id) 58 | db.session.delete(contact) 59 | db.session.commit() 60 | 61 | flash('Contact deleted successfully!') 62 | 63 | return redirect(url_for('contacts.index')) 64 | 65 | 66 | @contacts.route("/about") 67 | def about(): 68 | return render_template("about.html") 69 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #121212; 3 | } 4 | 5 | .bg-black { 6 | background: #090909 !important; 7 | } -------------------------------------------------------------------------------- /templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block body %} 4 | 5 |
6 |

About

7 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem doloribus molestiae harum in, reprehenderit ipsa architecto totam a blanditiis aut corrupti ratione pariatur delectus quod asperiores, adipisci ipsam veritatis quos animi, necessitatibus sit consequatur. Aliquam quibusdam, laudantium dolore iste aspernatur quaerat, nostrum sequi illum tempore, laborum explicabo nesciunt quasi asperiores officia vitae beatae rem aliquid molestias consectetur exercitationem similique ab? Impedit esse labore dignissimos ut sit, facilis eaque error minima ipsam sint porro hic a atque quaerat excepturi autem perspiciatis dicta officia eum veniam maxime at! Mollitia assumenda ratione atque. Consequatur architecto voluptas esse delectus qui sunt eligendi perferendis, voluptatum, nemo, expedita provident. Corrupti adipisci deleniti sint ullam ut veniam similique ratione ipsam. Qui iste nulla possimus necessitatibus odit magnam laboriosam obcaecati alias ex saepe libero non quos at dignissimos hic neque reprehenderit aut, sit distinctio? Omnis dolor dignissimos autem minus asperiores amet, ipsum animi architecto sit quisquam ab laudantium molestias, sapiente nostrum accusamus quia qui nobis. Sunt reiciendis at, voluptatum similique eius aperiam molestiae nemo rerum, iste qui maxime iusto omnis expedita excepturi vitae aliquam dolorum doloribus commodi. Hic dolores in dolorem tenetur laborum similique error fuga vitae cum! Architecto, odio aut tempore eius autem iure reiciendis corporis perferendis neque veritatis quis sapiente libero ipsa voluptas labore fuga exercitationem alias nobis facilis qui numquam illum. Accusamus, quam nihil illo recusandae pariatur repellendus dolorem aliquid maiores amet ab omnis officiis esse nobis animi magnam dolore corrupti, quidem natus. Illo praesentium corrupti cumque voluptatibus deleniti, hic facilis maiores provident harum unde rem quisquam facere ex ducimus odio. Laborum excepturi voluptatibus dolorem doloribus. Labore corporis non obcaecati blanditiis dolorum facilis sequi, suscipit quam cum. Aliquam vitae voluptatem, consectetur iste repellat nulla fugit odio rerum rem minus architecto tempora, eveniet facilis nam nostrum suscipit? Delectus, consequatur repudiandae eos deserunt omnis modi quos perspiciatis.

8 |
9 | 10 | {% endblock %} 11 | 12 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} 4 | Flask SQLAlchemy CRUD | Home 5 | {% endblock %} 6 | 7 | {% block body %} 8 | 9 | 10 |
11 | 12 |
13 | 14 | {% include 'partials/_message.html' %} 15 | 16 | 17 | {% include 'partials/_taskForm.html' %} 18 |
19 | 20 | 21 |
22 | {% for contact in contacts %} 23 |
24 |
25 |
26 |
{{ contact.fullname}}
27 |
28 | Edit 29 | Delete 30 |
31 |
32 |

{{ contact.email }}

33 |

{{ contact.phone }}

34 |
35 |
36 | {% endfor %} 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% block title %} {% endblock %} 8 | 12 | 18 | 22 | 23 | 24 | {% include 'partials/_navbar.html' %} 25 | 26 |
{% block body %} {% endblock %}
27 | 28 | 29 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/partials/_message.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages() %} {% if messages %} {% for message in 2 | messages %} 3 | 12 | {% endfor %} {% endif %} {% endwith %} 13 | -------------------------------------------------------------------------------- /templates/partials/_navbar.html: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /templates/partials/_taskForm.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Add Contact

4 | 5 |
6 | 7 | 14 |
15 | 16 |
17 | 18 | 25 |
26 | 27 |
28 | 29 | 35 |
36 | 37 | 38 |
39 |
40 | -------------------------------------------------------------------------------- /templates/update.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} {% block body %} 2 | 3 |
4 |
5 |

Edit Task

6 | 7 |
8 |
9 | 10 | 16 |
17 |
18 | 19 | 25 |
26 |
27 | 28 | 34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /utils/db.py: -------------------------------------------------------------------------------- 1 | from flask_sqlalchemy import SQLAlchemy 2 | 3 | db = SQLAlchemy() 4 | --------------------------------------------------------------------------------