From 66db8adb105a3089718e5d5e6e2d40ef178ca9b6 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 20 Apr 2023 11:22:52 -0700 Subject: [PATCH 01/20] Define planet in routes.py --- app/routes.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..7cd368b5b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,19 @@ from flask import Blueprint +class Planet: + def __init__(self, id, name, description): + self.id = id + self.name = name + self.description = description + +mercury = Planet(1, "Mercury", "smallest planet, and hot") +venus = Planet(2, "Venus", "small, the hottest") +earth = Planet(3, "Earth", "medium, green, lush, home planet, in danger") +mars = Planet(4, "Mars", "red, no water, also in danger") +jupiter = Planet(5, "Jupiter", "largest, many moons") +saturn = Planet(6, "Saturn", "cool rings, large") +uranus = Planet(8, "Uranus", "large, funny name") +neptune = Planet(7, "Neptune", "large, blue, cold") +pluto = Planet(8, "Pluto", "dwarf planet, very cold") + +planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] \ No newline at end of file From 4b55ed25c25827cbd5bf650f547cceddbe158ff7 Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Thu, 20 Apr 2023 11:30:38 -0700 Subject: [PATCH 02/20] created planet endpoint with id, name, description for planet data --- app/__init__.py | 3 +++ app/routes.py | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..b2bd60609 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,4 +4,7 @@ def create_app(test_config=None): app = Flask(__name__) + from .routes import planet_bp + app.register_blueprint(planet_bp) + return app diff --git a/app/routes.py b/app/routes.py index 7cd368b5b..85f7a7270 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint +from flask import Blueprint, jsonify class Planet: def __init__(self, id, name, description): @@ -16,4 +16,19 @@ def __init__(self, id, name, description): neptune = Planet(7, "Neptune", "large, blue, cold") pluto = Planet(8, "Pluto", "dwarf planet, very cold") -planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] \ No newline at end of file +planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] + +planet_bp = Blueprint("planet", __name__, url_prefix="/planet") + +@planet_bp.route("", methods=["GET"]) +def get_restaurants(): + response = [] + for planet in planet_list: + planet_dict = { + "id": planet.id, + "name": planet.name, + "description": planet.description + } + response.append(planet_dict) + + return jsonify(response), 200 \ No newline at end of file From 916e83bcc5f9ee673e1165dd6329ed2ca405f155 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 20 Apr 2023 11:31:35 -0700 Subject: [PATCH 03/20] Accidental Edits --- app/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..ede1f7ec3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,5 @@ from flask import Flask - def create_app(test_config=None): app = Flask(__name__) From 9d11b1a7cc57979ce625c6da21d737f0b6ae9c69 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Fri, 21 Apr 2023 14:17:29 -0700 Subject: [PATCH 04/20] Fixed error in routes.py --- app/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index effb7564b..93acb83da 100644 --- a/app/routes.py +++ b/app/routes.py @@ -41,7 +41,7 @@ def get_one_planet(id): return {"message": f"invalid {id}"}, 400 for planet in planet_list: - if planet.id = planet_id: + if planet.id == planet_id: return jsonify({ "id": planet.id, "name": planet.name, From fd9a032166dd2ac6b479f1a3a971d2220be5caaa Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Fri, 21 Apr 2023 14:23:23 -0700 Subject: [PATCH 05/20] corrected errors in planet numbers and return messages --- app/routes.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/routes.py b/app/routes.py index 93acb83da..81ca192c7 100644 --- a/app/routes.py +++ b/app/routes.py @@ -12,9 +12,9 @@ def __init__(self, id, name, description): mars = Planet(4, "Mars", "red, no water, also in danger") jupiter = Planet(5, "Jupiter", "largest, many moons") saturn = Planet(6, "Saturn", "cool rings, large") -uranus = Planet(8, "Uranus", "large, funny name") -neptune = Planet(7, "Neptune", "large, blue, cold") -pluto = Planet(8, "Pluto", "dwarf planet, very cold") +uranus = Planet(7, "Uranus", "large, funny name") +neptune = Planet(8, "Neptune", "large, blue, cold") +pluto = Planet(9, "Pluto", "dwarf planet, very cold") planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] @@ -33,12 +33,12 @@ def get_restaurants(): return jsonify(response), 200 -@planet_bp.route("", methods=["GET"]) +@planet_bp.route("/", methods=["GET"]) def get_one_planet(id): try: planet_id = int(id) except: - return {"message": f"invalid {id}"}, 400 + return {"message": f"invalid id: {id}"}, 400 for planet in planet_list: if planet.id == planet_id: From 37eb80214979402fee0e9aa79bb529c2975fcf64 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 27 Apr 2023 11:50:21 -0700 Subject: [PATCH 06/20] Edited __init__.py --- app/models/planet.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/models/planet.py diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..e69de29bb From 112d017dc6259928af0502523779d5998b2600b8 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 27 Apr 2023 11:53:15 -0700 Subject: [PATCH 07/20] Added migrations --- app/__init__.py | 13 ++++++ migrations/README | 1 + migrations/alembic.ini | 45 ++++++++++++++++++ migrations/env.py | 96 +++++++++++++++++++++++++++++++++++++++ migrations/script.py.mako | 24 ++++++++++ 5 files changed, 179 insertions(+) create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako diff --git a/app/__init__.py b/app/__init__.py index 57f895006..9974ce2a4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,8 +1,21 @@ from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() def create_app(test_config=None): app = Flask(__name__) + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@127.0.0.1:5432/solar_system_development" + + # from .models.planet import Planet + + db.init_app(app) + migrate.init_app(app, db) + from .routes import planet_bp app.register_blueprint(planet_bp) diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 000000000..f8ed4801f --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 000000000..8b3fb3353 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 000000000..2c0156303 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} From 45746360bc4bc1d4d7b23b0aaa2c15162313d6b4 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 27 Apr 2023 12:00:13 -0700 Subject: [PATCH 08/20] Edited models/planet.py and migrated and upgraded --- app/__init__.py | 2 +- app/models/planet.py | 9 ++++++++ migrations/versions/4500beae0686_.py | 34 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/4500beae0686_.py diff --git a/app/__init__.py b/app/__init__.py index 9974ce2a4..588b31e3a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,7 +11,7 @@ def create_app(test_config=None): app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@127.0.0.1:5432/solar_system_development" - # from .models.planet import Planet + from .models.planet import Planet db.init_app(app) migrate.init_app(app, db) diff --git a/app/models/planet.py b/app/models/planet.py index e69de29bb..f0dfbddea 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -0,0 +1,9 @@ +from app import db + +class Planet(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String) + description = db.Column(db.String) + num_moons = db.Column(db.Integer) + + diff --git a/migrations/versions/4500beae0686_.py b/migrations/versions/4500beae0686_.py new file mode 100644 index 000000000..9b0931650 --- /dev/null +++ b/migrations/versions/4500beae0686_.py @@ -0,0 +1,34 @@ +"""empty message + +Revision ID: 4500beae0686 +Revises: +Create Date: 2023-04-27 11:57:37.732216 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4500beae0686' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planet', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('num_moons', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### From 4920dba1fdb100140aa270348ab4f9d0c88cb65b Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 27 Apr 2023 12:07:50 -0700 Subject: [PATCH 09/20] Created post method in routes.py --- app/routes.py | 98 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/app/routes.py b/app/routes.py index 81ca192c7..eecfc9feb 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,50 +1,66 @@ from flask import Blueprint, jsonify +from app import db +from app.models.planet import Planet -class Planet: - def __init__(self, id, name, description): - self.id = id - self.name = name - self.description = description +# class Planet: +# def __init__(self, id, name, description): +# self.id = id +# self.name = name +# self.description = description -mercury = Planet(1, "Mercury", "smallest planet, and hot") -venus = Planet(2, "Venus", "small, the hottest") -earth = Planet(3, "Earth", "medium, green, lush, home planet, in danger") -mars = Planet(4, "Mars", "red, no water, also in danger") -jupiter = Planet(5, "Jupiter", "largest, many moons") -saturn = Planet(6, "Saturn", "cool rings, large") -uranus = Planet(7, "Uranus", "large, funny name") -neptune = Planet(8, "Neptune", "large, blue, cold") -pluto = Planet(9, "Pluto", "dwarf planet, very cold") +# mercury = Planet(1, "Mercury", "smallest planet, and hot") +# venus = Planet(2, "Venus", "small, the hottest") +# earth = Planet(3, "Earth", "medium, green, lush, home planet, in danger") +# mars = Planet(4, "Mars", "red, no water, also in danger") +# jupiter = Planet(5, "Jupiter", "largest, many moons") +# saturn = Planet(6, "Saturn", "cool rings, large") +# uranus = Planet(7, "Uranus", "large, funny name") +# neptune = Planet(8, "Neptune", "large, blue, cold") +# pluto = Planet(9, "Pluto", "dwarf planet, very cold") -planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] +# planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] planet_bp = Blueprint("planet", __name__, url_prefix="/planet") -@planet_bp.route("", methods=["GET"]) -def get_restaurants(): - response = [] - for planet in planet_list: - planet_dict = { - "id": planet.id, - "name": planet.name, - "description": planet.description - } - response.append(planet_dict) - - return jsonify(response), 200 - -@planet_bp.route("/", methods=["GET"]) -def get_one_planet(id): - try: - planet_id = int(id) - except: - return {"message": f"invalid id: {id}"}, 400 +@planet_bp.route("", methods=["POST"]) +def add_planet(): + request_body = request.get_json() + new_planet = Planet( + name = request_body["name"], + description = request_body["description"], + num_moons = request_body["num_moons"] + ) + + db.session.add(new_planet) + db.session.commit() + + return {"id": new_planet.id}, 201 + +# @planet_bp.route("", methods=["GET"]) +# def get_restaurants(): +# response = [] +# for planet in planet_list: +# planet_dict = { +# "id": planet.id, +# "name": planet.name, +# "description": planet.description +# } +# response.append(planet_dict) + +# return jsonify(response), 200 + +# @planet_bp.route("/", methods=["GET"]) +# def get_one_planet(id): +# try: +# planet_id = int(id) +# except: +# return {"message": f"invalid id: {id}"}, 400 - for planet in planet_list: - if planet.id == planet_id: - return jsonify({ - "id": planet.id, - "name": planet.name, - "description": planet.description}), 200 +# for planet in planet_list: +# if planet.id == planet_id: +# return jsonify({ +# "id": planet.id, +# "name": planet.name, +# "description": planet.description}), 200 - return jsonify({"message": f"id {planet_id} not found"}), 404 \ No newline at end of file +# return jsonify({"message": f"id {planet_id} not found"}), 404 \ No newline at end of file From 0177940b09126315c30b17836ecb8b94e919614f Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Thu, 27 Apr 2023 12:15:45 -0700 Subject: [PATCH 10/20] posted planets in postman --- app/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index eecfc9feb..084843b38 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, jsonify +from flask import Blueprint, jsonify, request from app import db from app.models.planet import Planet From 974080a0a0a69a6fda8d7b1910bdb0b3cec9dd90 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Thu, 27 Apr 2023 12:24:24 -0700 Subject: [PATCH 11/20] Added class method to models/planet.py and refactored app/routes.py --- app/models/planet.py | 8 ++++++++ app/routes.py | 36 +++++++----------------------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index f0dfbddea..32966d4a7 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -6,4 +6,12 @@ class Planet(db.Model): description = db.Column(db.String) num_moons = db.Column(db.Integer) + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "description": self.description, + "num_moons": self.num_moons + } + diff --git a/app/routes.py b/app/routes.py index 084843b38..78f40a158 100644 --- a/app/routes.py +++ b/app/routes.py @@ -2,24 +2,6 @@ from app import db from app.models.planet import Planet -# class Planet: -# def __init__(self, id, name, description): -# self.id = id -# self.name = name -# self.description = description - -# mercury = Planet(1, "Mercury", "smallest planet, and hot") -# venus = Planet(2, "Venus", "small, the hottest") -# earth = Planet(3, "Earth", "medium, green, lush, home planet, in danger") -# mars = Planet(4, "Mars", "red, no water, also in danger") -# jupiter = Planet(5, "Jupiter", "largest, many moons") -# saturn = Planet(6, "Saturn", "cool rings, large") -# uranus = Planet(7, "Uranus", "large, funny name") -# neptune = Planet(8, "Neptune", "large, blue, cold") -# pluto = Planet(9, "Pluto", "dwarf planet, very cold") - -# planet_list = [mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, pluto] - planet_bp = Blueprint("planet", __name__, url_prefix="/planet") @planet_bp.route("", methods=["POST"]) @@ -36,18 +18,14 @@ def add_planet(): return {"id": new_planet.id}, 201 -# @planet_bp.route("", methods=["GET"]) -# def get_restaurants(): -# response = [] -# for planet in planet_list: -# planet_dict = { -# "id": planet.id, -# "name": planet.name, -# "description": planet.description -# } -# response.append(planet_dict) +@planet_bp.route("", methods=["GET"]) +def get_restaurants(): + response = [] + all_planets = Planet.query.all() + for planet in all_planets: + response.append(planet.to_dict()) -# return jsonify(response), 200 + return jsonify(response), 200 # @planet_bp.route("/", methods=["GET"]) # def get_one_planet(id): From be520b67cc13f4bca0f141ffd58c0f72f691fdf2 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Mon, 1 May 2023 13:11:50 -0700 Subject: [PATCH 12/20] Added validate_planet and get_one_planet functions to routes.py --- app/routes.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/app/routes.py b/app/routes.py index 78f40a158..b7c81ee16 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, jsonify, request +from flask import Blueprint, jsonify, request, abort, make_response from app import db from app.models.planet import Planet @@ -19,7 +19,7 @@ def add_planet(): return {"id": new_planet.id}, 201 @planet_bp.route("", methods=["GET"]) -def get_restaurants(): +def get_planets(): response = [] all_planets = Planet.query.all() for planet in all_planets: @@ -27,18 +27,17 @@ def get_restaurants(): return jsonify(response), 200 -# @planet_bp.route("/", methods=["GET"]) -# def get_one_planet(id): -# try: -# planet_id = int(id) -# except: -# return {"message": f"invalid id: {id}"}, 400 - -# for planet in planet_list: -# if planet.id == planet_id: -# return jsonify({ -# "id": planet.id, -# "name": planet.name, -# "description": planet.description}), 200 +@planet_bp.route("/", methods=["GET"]) +def get_one_planet(p_id): + planet = validate_planet(p_id) + + return planet.to_dict(), 200 + + +def validate_planet(p_id): + try: + planet_id = int(p_id) + except ValueError: + return abort(make_response({"message": f"invalid id: {p_id}"}, 400)) -# return jsonify({"message": f"id {planet_id} not found"}), 404 \ No newline at end of file + return Planet.query.get_or_404(p_id) \ No newline at end of file From 815a1872bac83c557a80a22ca6aed3335ed572be Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Mon, 1 May 2023 13:23:50 -0700 Subject: [PATCH 13/20] update, and delete routes added to routes.py and validate helper function --- app/routes.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index b7c81ee16..108fc948b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -40,4 +40,28 @@ def validate_planet(p_id): except ValueError: return abort(make_response({"message": f"invalid id: {p_id}"}, 400)) - return Planet.query.get_or_404(p_id) \ No newline at end of file + return Planet.query.get_or_404(p_id) + +@planet_bp.route("/", methods=["PUT"]) +def update_planet(p_id): + planet = validate_planet(p_id) + + request_data = request.get_json() + + planet.name = request_data["name"] + planet.description = request_data["description"] + planet.num_moons = request_data["num_moons"] + + db.session.commit() + + return {"msg": f"planet {p_id} successfully updated"}, 200 + +@planet_bp.route("/", methods=["DELETE"]) +def delete_planet(p_id): + planet = validate_planet(p_id) + + db.session.delete(planet) + + db.session.commit() + + return {"msg": f"planet {p_id} successfully deleted"}, 200 From f002be81738a5f1e048a9feed3acec8d1ce05ec8 Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Tue, 2 May 2023 10:45:29 -0700 Subject: [PATCH 14/20] added name_query to get_planet route --- app/routes.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 108fc948b..d1ac107a6 100644 --- a/app/routes.py +++ b/app/routes.py @@ -21,7 +21,12 @@ def add_planet(): @planet_bp.route("", methods=["GET"]) def get_planets(): response = [] - all_planets = Planet.query.all() + name_query = request.args.get("name") + if name_query is None: + all_planets = Planet.query.all() + else: + all_planets = Planet.query.filter_by(name=name_query) + for planet in all_planets: response.append(planet.to_dict()) From e1a2a0b59e55c5257d4deb43027bb348cb85738c Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Tue, 2 May 2023 10:53:05 -0700 Subject: [PATCH 15/20] Added testing check to create_app function in __init__.py --- app/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 588b31e3a..7a71df547 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,15 +1,23 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate +from dotenv import load_dotenv +import os db = SQLAlchemy() migrate = Migrate() -def create_app(test_config=None): +load_dotenv() + +def create_app(testing=None): app = Flask(__name__) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@127.0.0.1:5432/solar_system_development" + + if testing is None: + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_DATABASE_URI") + else: + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_TEST_DATABASE_URI") from .models.planet import Planet From 13f2b068d479c9e47b96b497ab3ec561d0688851 Mon Sep 17 00:00:00 2001 From: Kira Sidhu Date: Wed, 3 May 2023 13:09:12 -0700 Subject: [PATCH 16/20] Created tests folder and files, in conftest.py defined app, client and two_planets --- tests/__init__.py | 0 tests/conftest.py | 29 +++++++++++++++++++++++++++++ tests/test_routes.py | 0 3 files changed, 29 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_routes.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..fbf67a944 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,29 @@ +import pytest +from app import create_app, db +from app.models.planet import Planet +from flask.signals import request_finished + +@pytest.fixture +def app(): + app = create_app(testing=True) + + @request_finished.connect_via(app) + def expire_session(sender, response, **extra): + db.session.remove() + + with app.app_context(): + db.create_all() + yield app + db.drop_all + +@pytest.fixture +def client(app): + return app.test_client() + +@pytest.fixture +def two_planets(): + earth = Planet(name="earth", description="in danger", num_moons=1) + mars = Planet(name="mars", description="red", num_moons=2) + + db.session.add_all([earth, mars]) + db.session.commit() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..e69de29bb From d11b7617545050eebb82738ed6cf564e2766a051 Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Wed, 3 May 2023 13:25:03 -0700 Subject: [PATCH 17/20] added tests to test_routes, passed with pytest --- tests/conftest.py | 2 +- tests/test_routes.py | 70 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index fbf67a944..63f379aee 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ def expire_session(sender, response, **extra): with app.app_context(): db.create_all() yield app - db.drop_all + db.drop_all() @pytest.fixture def client(app): diff --git a/tests/test_routes.py b/tests/test_routes.py index e69de29bb..01d711483 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -0,0 +1,70 @@ +import pytest + +def test_post_creates_planet(client): + response = client.post("/planet", json={ + "name": "earth", + "description": "in danger", + "num_moons": 1 + }) + + response_body = response.get_json() + + assert response.status_code == 201 + assert "id" in response_body + +def test_get_all_planets(client, two_planets): + response = client.get("/planet") + + response_body = response.get_json() + + assert response.status_code == 200 + assert response_body == [ + { + "id": 1, + "name": "earth", + "description": "in danger", + "num_moons": 1 + }, + { + "id": 2, + "name": "mars", + "description": "red", + "num_moons": 2 + } + ] + +def test_get_one_planet(client, two_planets): + response = client.get("/planet/1") + + response_body = response.get_json() + + assert response.status_code == 200 + assert response_body == { + "id": 1, + "name": "earth", + "description": "in danger", + "num_moons": 1 + } + +def test_put_planet(client, two_planets): + response = client.put("/planet/1", json = { + "id": 1, + "name": "mercury", + "description": "small", + "num_moons": 0 + + }) + + response_body = response.get_json() + + assert response.status_code == 200 + assert response_body == {"msg": "planet 1 successfully updated"} + +def test_delet_planet(client, two_planets): + response = client.delete("/planet/2") + + response_body = response.get_json() + + assert response.status_code == 200 + assert response_body == {"msg": "planet 2 successfully deleted"} + From 8b1f77498e3aae1c109ff0036a8970fb24814e82 Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Fri, 5 May 2023 11:13:42 -0700 Subject: [PATCH 18/20] refactored routes.py and planets.py and added test --- app/models/planet.py | 8 ++++++++ app/routes.py | 20 ++++++++------------ tests/test_routes.py | 10 +++++++++- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 32966d4a7..340f4b4f3 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -13,5 +13,13 @@ def to_dict(self): "description": self.description, "num_moons": self.num_moons } + + @classmethod + def from_dict(cls, planet_data): + return cls( + name = planet_data["name"], + description = planet_data["description"], + num_moons = planet_data["num_moons"] + ) diff --git a/app/routes.py b/app/routes.py index d1ac107a6..9efa16086 100644 --- a/app/routes.py +++ b/app/routes.py @@ -7,11 +7,7 @@ @planet_bp.route("", methods=["POST"]) def add_planet(): request_body = request.get_json() - new_planet = Planet( - name = request_body["name"], - description = request_body["description"], - num_moons = request_body["num_moons"] - ) + new_planet = Planet.from_dict(request_body) db.session.add(new_planet) db.session.commit() @@ -34,22 +30,22 @@ def get_planets(): @planet_bp.route("/", methods=["GET"]) def get_one_planet(p_id): - planet = validate_planet(p_id) + planet = validate_item(Planet, p_id) return planet.to_dict(), 200 -def validate_planet(p_id): +def validate_item(model, item_id): try: - planet_id = int(p_id) + item_id = int(item_id) except ValueError: - return abort(make_response({"message": f"invalid id: {p_id}"}, 400)) + return abort(make_response({"message": f"invalid id: {item_id}"}, 400)) - return Planet.query.get_or_404(p_id) + return model.query.get_or_404(item_id) @planet_bp.route("/", methods=["PUT"]) def update_planet(p_id): - planet = validate_planet(p_id) + planet = validate_item(Planet, p_id) request_data = request.get_json() @@ -63,7 +59,7 @@ def update_planet(p_id): @planet_bp.route("/", methods=["DELETE"]) def delete_planet(p_id): - planet = validate_planet(p_id) + planet = validate_item(Planet, p_id) db.session.delete(planet) diff --git a/tests/test_routes.py b/tests/test_routes.py index 01d711483..76770c436 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -60,7 +60,7 @@ def test_put_planet(client, two_planets): assert response.status_code == 200 assert response_body == {"msg": "planet 1 successfully updated"} -def test_delet_planet(client, two_planets): +def test_delete_planet(client, two_planets): response = client.delete("/planet/2") response_body = response.get_json() @@ -68,3 +68,11 @@ def test_delet_planet(client, two_planets): assert response.status_code == 200 assert response_body == {"msg": "planet 2 successfully deleted"} +def test_get_no_data_returns_404(client): + response = client.get("/planet/20") + + response_body = response.get_json() + + assert response.status_code == 404 + + From e92da37567781b8523d8a1de3eced433bcdaabec Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Tue, 9 May 2023 10:56:47 -0700 Subject: [PATCH 19/20] added gunicorn to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index ae59e7b55..05fce9f67 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ click==7.1.2 Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 +gunicorn==20.1.0 idna==2.10 itsdangerous==1.1.0 Jinja2==2.11.3 From f7cba6afcfe548f6c57e86a7c4f31f167fd641ae Mon Sep 17 00:00:00 2001 From: Limary Gonzalez Date: Tue, 9 May 2023 11:08:33 -0700 Subject: [PATCH 20/20] added render database --- app/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 7a71df547..30913a26d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,8 @@ def create_app(testing=None): app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False if testing is None: - app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_DATABASE_URI") + # app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_DATABASE_URI") + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("RENDER_DATABASE_URI") else: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_TEST_DATABASE_URI")