├── .gitignore
├── README.md
├── preview1.JPG
├── preview2.png
├── preview3.PNG
├── requirements.txt
└── src
├── app.py
├── config.py
├── database
└── db.py
├── models
├── MovieModel.py
├── __init__.py
└── entities
│ ├── Movie.py
│ └── __init__.py
├── routes
├── Movie.py
└── __init__.py
└── utils
└── DateFormat.py
/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
2 | .env
3 |
4 | __pycache__/
5 | *.py[cod]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # REST API con Python, Flask y PostgreSQL
2 |
3 | REST API con Python, Flask y PostgreSQL. Usaremos el protocolo HTTP junto con los métodos GET, POST, PUT y DELETE y el formato JSON para enviar y recibir datos; además, aprende a probarla utilizando un cliente REST como Insomnia.
4 |
5 |
6 |
7 | Primero, crear un entorno virtual:
8 | ### `python -m virtualenv env`
9 |
10 | Para instalar los paquetes necesarios:
11 | ### `pip install -r requirements.txt`
12 |
13 | Crear un archivo .env (en la raíz del proyecto) para las variables de entorno:
14 |
15 | ### `SECRET_KEY=SECRET_KEY`
16 | ### `PGSQL_HOST=host`
17 | ### `PGSQL_USER=user`
18 | ### `PGSQL_PASSWORD=password`
19 | ### `PGSQL_DB=database`
20 |
21 | Descarga de PostgreSQL: https://www.postgresql.org/download/
22 |
23 | Descarga de Insomnia: https://insomnia.rest/download
24 |
25 |
26 |
27 | 
28 |
29 | 
30 |
31 | 
32 |
33 | # 🌍 Por si deseas contactarme 👨💻 :
34 |
35 | [](https://pe.linkedin.com/in/uskokrum2010)
36 | [](https://youtube.com/uskokrum2010)
37 | [](https://twitter.com/uskokrum2010)
38 | [](https://instagram.com/uskokrum2010)
39 | [](https://facebook.com/uskokrum2010)
40 | [](https://www.udemy.com/course/sql-para-administracion-de-bases-de-datos-con-mysql/)
41 | [](https://uskokrum2010.com)
42 | [](mailto:uskokrum2010@gmail.com)
--------------------------------------------------------------------------------
/preview1.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/preview1.JPG
--------------------------------------------------------------------------------
/preview2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/preview2.png
--------------------------------------------------------------------------------
/preview3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/preview3.PNG
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/requirements.txt
--------------------------------------------------------------------------------
/src/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_cors import CORS
3 |
4 | from config import config
5 |
6 | # Routes
7 | from routes import Movie
8 |
9 | app = Flask(__name__)
10 |
11 | CORS(app, resources={"*": {"origins": "http://localhost:9300"}})
12 |
13 |
14 | def page_not_found(error):
15 | return "Not found page
", 404
16 |
17 |
18 | if __name__ == '__main__':
19 | app.config.from_object(config['development'])
20 |
21 | # Blueprints
22 | app.register_blueprint(Movie.main, url_prefix='/api/movies')
23 |
24 | # Error handlers
25 | app.register_error_handler(404, page_not_found)
26 | app.run()
27 |
--------------------------------------------------------------------------------
/src/config.py:
--------------------------------------------------------------------------------
1 | from decouple import config
2 |
3 |
4 | class Config:
5 | SECRET_KEY = config('SECRET_KEY')
6 |
7 |
8 | class DevelopmentConfig(Config):
9 | DEBUG = True
10 |
11 |
12 | config = {
13 | 'development': DevelopmentConfig
14 | }
15 |
--------------------------------------------------------------------------------
/src/database/db.py:
--------------------------------------------------------------------------------
1 | import psycopg2
2 | from psycopg2 import DatabaseError
3 | from decouple import config
4 |
5 |
6 | def get_connection():
7 | try:
8 | return psycopg2.connect(
9 | host=config('PGSQL_HOST'),
10 | user=config('PGSQL_USER'),
11 | password=config('PGSQL_PASSWORD'),
12 | database=config('PGSQL_DATABASE')
13 | )
14 | except DatabaseError as ex:
15 | raise ex
16 |
--------------------------------------------------------------------------------
/src/models/MovieModel.py:
--------------------------------------------------------------------------------
1 | from database.db import get_connection
2 | from .entities.Movie import Movie
3 |
4 |
5 | class MovieModel():
6 |
7 | @classmethod
8 | def get_movies(self):
9 | try:
10 | connection = get_connection()
11 | movies = []
12 |
13 | with connection.cursor() as cursor:
14 | cursor.execute("SELECT id, title, duration, released FROM movie ORDER BY title ASC")
15 | resultset = cursor.fetchall()
16 |
17 | for row in resultset:
18 | movie = Movie(row[0], row[1], row[2], row[3])
19 | movies.append(movie.to_JSON())
20 |
21 | connection.close()
22 | return movies
23 | except Exception as ex:
24 | raise Exception(ex)
25 |
26 | @classmethod
27 | def get_movie(self, id):
28 | try:
29 | connection = get_connection()
30 |
31 | with connection.cursor() as cursor:
32 | cursor.execute("SELECT id, title, duration, released FROM movie WHERE id = %s", (id,))
33 | row = cursor.fetchone()
34 |
35 | movie = None
36 | if row != None:
37 | movie = Movie(row[0], row[1], row[2], row[3])
38 | movie = movie.to_JSON()
39 |
40 | connection.close()
41 | return movie
42 | except Exception as ex:
43 | raise Exception(ex)
44 |
45 | @classmethod
46 | def add_movie(self, movie):
47 | try:
48 | connection = get_connection()
49 |
50 | with connection.cursor() as cursor:
51 | cursor.execute("""INSERT INTO movie (id, title, duration, released)
52 | VALUES (%s, %s, %s, %s)""", (movie.id, movie.title, movie.duration, movie.released))
53 | affected_rows = cursor.rowcount
54 | connection.commit()
55 |
56 | connection.close()
57 | return affected_rows
58 | except Exception as ex:
59 | raise Exception(ex)
60 |
61 | @classmethod
62 | def update_movie(self, movie):
63 | try:
64 | connection = get_connection()
65 |
66 | with connection.cursor() as cursor:
67 | cursor.execute("""UPDATE movie SET title = %s, duration = %s, released = %s
68 | WHERE id = %s""", (movie.title, movie.duration, movie.released, movie.id))
69 | affected_rows = cursor.rowcount
70 | connection.commit()
71 |
72 | connection.close()
73 | return affected_rows
74 | except Exception as ex:
75 | raise Exception(ex)
76 |
77 | @classmethod
78 | def delete_movie(self, movie):
79 | try:
80 | connection = get_connection()
81 |
82 | with connection.cursor() as cursor:
83 | cursor.execute("DELETE FROM movie WHERE id = %s", (movie.id,))
84 | affected_rows = cursor.rowcount
85 | connection.commit()
86 |
87 | connection.close()
88 | return affected_rows
89 | except Exception as ex:
90 | raise Exception(ex)
91 |
--------------------------------------------------------------------------------
/src/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/src/models/__init__.py
--------------------------------------------------------------------------------
/src/models/entities/Movie.py:
--------------------------------------------------------------------------------
1 | from utils.DateFormat import DateFormat
2 |
3 |
4 | class Movie():
5 |
6 | def __init__(self, id, title=None, duration=None, released=None) -> None:
7 | self.id = id
8 | self.title = title
9 | self.duration = duration
10 | self.released = released
11 |
12 | def to_JSON(self):
13 | return {
14 | 'id': self.id,
15 | 'title': self.title,
16 | 'duration': self.duration,
17 | 'released': DateFormat.convert_date(self.released)
18 | }
19 |
--------------------------------------------------------------------------------
/src/models/entities/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/src/models/entities/__init__.py
--------------------------------------------------------------------------------
/src/routes/Movie.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, jsonify, request
2 | import uuid
3 |
4 | # Entities
5 | from models.entities.Movie import Movie
6 | # Models
7 | from models.MovieModel import MovieModel
8 |
9 | main = Blueprint('movie_blueprint', __name__)
10 |
11 |
12 | @main.route('/')
13 | def get_movies():
14 | try:
15 | movies = MovieModel.get_movies()
16 | return jsonify(movies)
17 | except Exception as ex:
18 | return jsonify({'message': str(ex)}), 500
19 |
20 |
21 | @main.route('/')
22 | def get_movie(id):
23 | try:
24 | movie = MovieModel.get_movie(id)
25 | if movie != None:
26 | return jsonify(movie)
27 | else:
28 | return jsonify({}), 404
29 | except Exception as ex:
30 | return jsonify({'message': str(ex)}), 500
31 |
32 |
33 | @main.route('/add', methods=['POST'])
34 | def add_movie():
35 | try:
36 | title = request.json['title']
37 | duration = int(request.json['duration'])
38 | released = request.json['released']
39 | id = uuid.uuid4()
40 | movie = Movie(str(id), title, duration, released)
41 |
42 | affected_rows = MovieModel.add_movie(movie)
43 |
44 | if affected_rows == 1:
45 | return jsonify(movie.id)
46 | else:
47 | return jsonify({'message': "Error on insert"}), 500
48 |
49 | except Exception as ex:
50 | return jsonify({'message': str(ex)}), 500
51 |
52 |
53 | @main.route('/update/', methods=['PUT'])
54 | def update_movie(id):
55 | try:
56 | title = request.json['title']
57 | duration = int(request.json['duration'])
58 | released = request.json['released']
59 | movie = Movie(id, title, duration, released)
60 |
61 | affected_rows = MovieModel.update_movie(movie)
62 |
63 | if affected_rows == 1:
64 | return jsonify(movie.id)
65 | else:
66 | return jsonify({'message': "No movie updated"}), 404
67 |
68 | except Exception as ex:
69 | return jsonify({'message': str(ex)}), 500
70 |
71 |
72 | @main.route('/delete/', methods=['DELETE'])
73 | def delete_movie(id):
74 | try:
75 | movie = Movie(id)
76 |
77 | affected_rows = MovieModel.delete_movie(movie)
78 |
79 | if affected_rows == 1:
80 | return jsonify(movie.id)
81 | else:
82 | return jsonify({'message': "No movie deleted"}), 404
83 |
84 | except Exception as ex:
85 | return jsonify({'message': str(ex)}), 500
86 |
--------------------------------------------------------------------------------
/src/routes/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UskoKruM/python-flask-postgresql-rest-api/a6215cd4d2717b8cee66bba67ee35a598ac23ea4/src/routes/__init__.py
--------------------------------------------------------------------------------
/src/utils/DateFormat.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 |
4 | class DateFormat():
5 |
6 | @classmethod
7 | def convert_date(self, date):
8 | return datetime.datetime.strftime(date, '%d/%m/%Y')
9 |
--------------------------------------------------------------------------------