From e5d719c1224c746fe589387f5bf3f062e7b9490d Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 14 Dec 2022 14:00:00 -0500 Subject: [PATCH 01/36] Created Planets Co-authored-by: Soumya Sah --- app/routes.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..1e0828440 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,14 @@ from flask import Blueprint +class Planet: + def __init__(self, id, name, description, num_moons): + self.id = id + self.name = name + self.description = description + self.num_moons = num_moons + + planets = [ + Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), + Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), + Planet(3, "Earth", "Our home planet", 1) + ] \ No newline at end of file From fe92aad21f30738f9cf26a83d7874e737f78c262 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 14 Dec 2022 14:21:13 -0500 Subject: [PATCH 02/36] Added /planets endpoint --- app/__init__.py | 3 ++- app/routes.py | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..e40af4355 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,5 +3,6 @@ def create_app(test_config=None): app = Flask(__name__) - + from .routes import planets_bp + app.register_blueprint(planets_bp) return app diff --git a/app/routes.py b/app/routes.py index 1e0828440..0f490128a 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, num_moons): @@ -7,8 +7,21 @@ def __init__(self, id, name, description, num_moons): self.description = description self.num_moons = num_moons - planets = [ - Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), - Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), - Planet(3, "Earth", "Our home planet", 1) - ] \ No newline at end of file +planets = [ + Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), + Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), + Planet(3, "Earth", "Our home planet", 1) +] + +planets_bp = Blueprint("planets", __name__,url_prefix="/planets") +@planets_bp.route("", methods=["GET"]) +def get_all_planets(): + planets_response = [] + for planet in planets: + planets_response.append({ + "id" : planet.id, + "name" :planet.name, + "description" : planet.description, + "number of moons" : planet.num_moons + }) + return jsonify(planets_response),200 \ No newline at end of file From 6e1b7872c8f83a1804d5bf14c1812c50e241fad3 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 15 Dec 2022 09:47:22 -0800 Subject: [PATCH 03/36] added get planet by id, and add validation --- app/routes.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 0f490128a..9a3d9661c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, jsonify +from flask import Blueprint, jsonify, abort, make_response class Planet: def __init__(self, id, name, description, num_moons): @@ -24,4 +24,27 @@ def get_all_planets(): "description" : planet.description, "number of moons" : planet.num_moons }) - return jsonify(planets_response),200 \ No newline at end of file + return jsonify(planets_response),200 + +@planets_bp.route("/", methods=["GET"]) +def get_one_planet(planet_id): + planet = validate_planet(planet_id) + + return{ + "id" : planet.id, + "name" :planet.name, + "description" : planet.description, + "number of moons" : planet.num_moons + } + +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"planet {planet_id} is invalid"}, 400)) + + for planet in planets: + if planet.id == planet_id: + return planet + + abort(make_response({"message":f"planet {planet_id} is not found"}, 404)) \ No newline at end of file From 4759c30a466183d36eee349e725db49c067f9439 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 15 Dec 2022 10:18:59 -0800 Subject: [PATCH 04/36] Added a to_dict() method to convert data to dictionary. --- app/routes.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/app/routes.py b/app/routes.py index 9a3d9661c..1659d476b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -7,6 +7,14 @@ def __init__(self, id, name, description, num_moons): self.description = description self.num_moons = num_moons + def to_dict(self): + return{ + "id": self.id, + "name": self.name, + "description": self.description, + "number of moons": self.num_moons, + } + planets = [ Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), @@ -18,24 +26,14 @@ def __init__(self, id, name, description, num_moons): def get_all_planets(): planets_response = [] for planet in planets: - planets_response.append({ - "id" : planet.id, - "name" :planet.name, - "description" : planet.description, - "number of moons" : planet.num_moons - }) + planets_response.append(planet.to_dict()) + return jsonify(planets_response),200 @planets_bp.route("/", methods=["GET"]) def get_one_planet(planet_id): planet = validate_planet(planet_id) - - return{ - "id" : planet.id, - "name" :planet.name, - "description" : planet.description, - "number of moons" : planet.num_moons - } + return jsonify(planet.to_dict()) def validate_planet(planet_id): try: From 15c886577d3f11d1b4cedbc3ab630fea76032431 Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 15 Dec 2022 13:42:29 -0500 Subject: [PATCH 05/36] Made planet module and added attribute --- app/routes.py | 16 ---------------- planet.py | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 planet.py diff --git a/app/routes.py b/app/routes.py index 1659d476b..26852ca4d 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,20 +1,4 @@ from flask import Blueprint, jsonify, abort, make_response - -class Planet: - def __init__(self, id, name, description, num_moons): - self.id = id - self.name = name - self.description = description - self.num_moons = num_moons - - def to_dict(self): - return{ - "id": self.id, - "name": self.name, - "description": self.description, - "number of moons": self.num_moons, - } - planets = [ Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), diff --git a/planet.py b/planet.py new file mode 100644 index 000000000..2b7da1c90 --- /dev/null +++ b/planet.py @@ -0,0 +1,17 @@ +class Planet: + def __init__(self, id, name, description, len_years, num_moons): + self.id = id + self.name = name + self.description = description + self.len_years = len_years + self.num_moons = num_moons + + + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "description": self.description, + "length of year": self.len_years, + "number of moons": self.num_moons, + } \ No newline at end of file From 209d0920636fb3225d4f4f0e67f4ac0ffc7c6cca Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 15 Dec 2022 11:15:35 -0800 Subject: [PATCH 06/36] Moved planet.py, imported in routes.py, added additional planets. --- planet.py => app/planet.py | 0 app/routes.py | 12 +++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) rename planet.py => app/planet.py (100%) diff --git a/planet.py b/app/planet.py similarity index 100% rename from planet.py rename to app/planet.py diff --git a/app/routes.py b/app/routes.py index 26852ca4d..f4750be7c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,8 +1,14 @@ +from .planet import Planet from flask import Blueprint, jsonify, abort, make_response planets = [ - Planet(1, "Mercury", "Mercury is the closest planet to the Sun", 0), - Planet(2, "Venus", "Venus is the hottest planet in the solar system", 0 ), - Planet(3, "Earth", "Our home planet", 1) + Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), + Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), + Planet(3, "Earth", "Our home planet.", 365,1), + Planet(4, "Mars", "Also known as Red planet.",687, 2), + Planet(5, "Jupiter","Largest planet in the solar system.",4333, 80), + Planet(6, "Saturn", "Only planet to have rings made of ice and rock.",10759, 83), + Planet(7, "Uranus", "Only planet with a 97 degree tilted axis.", 30687, 27), + Planet(8, "Neptune", "Blue ice giant" ,60190, 14 ) ] planets_bp = Blueprint("planets", __name__,url_prefix="/planets") From 349bdcad729fb01ec78e963943046e00ff1da36d Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Tue, 20 Dec 2022 12:41:37 -0800 Subject: [PATCH 07/36] changes to create the planet model. make sure to separately CREATE DATABASE solar_system_development; in the postgres user before further development and testing. --- app/__init__.py | 17 +++- app/models/__init__.py | 0 app/models/planet.py | 31 ++++++ app/planet.py | 17 ---- app/routes.py | 62 ++++++------ migrations/README | 1 + migrations/alembic.ini | 45 +++++++++ migrations/env.py | 96 +++++++++++++++++++ migrations/script.py.mako | 24 +++++ .../35df06ad1029_adds_planet_model.py | 35 +++++++ 10 files changed, 278 insertions(+), 50 deletions(-) create mode 100644 app/models/__init__.py create mode 100644 app/models/planet.py delete mode 100644 app/planet.py create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/35df06ad1029_adds_planet_model.py diff --git a/app/__init__.py b/app/__init__.py index e40af4355..98289ae5c 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__) - from .routes import planets_bp - app.register_blueprint(planets_bp) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres+psycopg2://postgres:postgres@localhost:5432/solar_system_development' + + db.init_app(app) + migrate.init_app(app, db) + + from app.models.planet import Planet + + # from .routes import planets_bp + # app.register_blueprint(planets_bp) + return app diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..f9c679598 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,31 @@ +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()) + orbit_days = db.Column(db.Integer()) + num_moons = db.Column(db.Integer()) + + + + + + +# ------------Hardcoded Data for Planet------------------------------ +# class Planet: +# def __init__(self, id, name, description, len_years, num_moons): +# self.id = id +# self.name = name +# self.description = description +# self.len_years = len_years +# self.num_moons = num_moons + + +# def to_dict(self): +# return { +# "id": self.id, +# "name": self.name, +# "description": self.description, +# "length of year": self.len_years, +# "number of moons": self.num_moons, +# } \ No newline at end of file diff --git a/app/planet.py b/app/planet.py deleted file mode 100644 index 2b7da1c90..000000000 --- a/app/planet.py +++ /dev/null @@ -1,17 +0,0 @@ -class Planet: - def __init__(self, id, name, description, len_years, num_moons): - self.id = id - self.name = name - self.description = description - self.len_years = len_years - self.num_moons = num_moons - - - def to_dict(self): - return { - "id": self.id, - "name": self.name, - "description": self.description, - "length of year": self.len_years, - "number of moons": self.num_moons, - } \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index f4750be7c..3df79d1ef 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,38 +1,38 @@ -from .planet import Planet +from .models.planet import Planet from flask import Blueprint, jsonify, abort, make_response -planets = [ - Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), - Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), - Planet(3, "Earth", "Our home planet.", 365,1), - Planet(4, "Mars", "Also known as Red planet.",687, 2), - Planet(5, "Jupiter","Largest planet in the solar system.",4333, 80), - Planet(6, "Saturn", "Only planet to have rings made of ice and rock.",10759, 83), - Planet(7, "Uranus", "Only planet with a 97 degree tilted axis.", 30687, 27), - Planet(8, "Neptune", "Blue ice giant" ,60190, 14 ) -] +# planets = [ +# Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), +# Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), +# Planet(3, "Earth", "Our home planet.", 365,1), +# Planet(4, "Mars", "Also known as Red planet.",687, 2), +# Planet(5, "Jupiter","Largest planet in the solar system.",4333, 80), +# Planet(6, "Saturn", "Only planet to have rings made of ice and rock.",10759, 83), +# Planet(7, "Uranus", "Only planet with a 97 degree tilted axis.", 30687, 27), +# Planet(8, "Neptune", "Blue ice giant" ,60190, 14 ) +# ] -planets_bp = Blueprint("planets", __name__,url_prefix="/planets") -@planets_bp.route("", methods=["GET"]) -def get_all_planets(): - planets_response = [] - for planet in planets: - planets_response.append(planet.to_dict()) +# planets_bp = Blueprint("planets", __name__,url_prefix="/planets") +# @planets_bp.route("", methods=["GET"]) +# def get_all_planets(): +# planets_response = [] +# for planet in planets: +# planets_response.append(planet.to_dict()) - return jsonify(planets_response),200 +# return jsonify(planets_response),200 -@planets_bp.route("/", methods=["GET"]) -def get_one_planet(planet_id): - planet = validate_planet(planet_id) - return jsonify(planet.to_dict()) +# @planets_bp.route("/", methods=["GET"]) +# def get_one_planet(planet_id): +# planet = validate_planet(planet_id) +# return jsonify(planet.to_dict()) -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message":f"planet {planet_id} is invalid"}, 400)) +# def validate_planet(planet_id): +# try: +# planet_id = int(planet_id) +# except: +# abort(make_response({"message":f"planet {planet_id} is invalid"}, 400)) - for planet in planets: - if planet.id == planet_id: - return planet +# for planet in planets: +# if planet.id == planet_id: +# return planet - abort(make_response({"message":f"planet {planet_id} is not found"}, 404)) \ No newline at end of file +# abort(make_response({"message":f"planet {planet_id} is not found"}, 404)) \ No newline at end of file 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"} diff --git a/migrations/versions/35df06ad1029_adds_planet_model.py b/migrations/versions/35df06ad1029_adds_planet_model.py new file mode 100644 index 000000000..03081a331 --- /dev/null +++ b/migrations/versions/35df06ad1029_adds_planet_model.py @@ -0,0 +1,35 @@ +"""adds Planet model + +Revision ID: 35df06ad1029 +Revises: +Create Date: 2022-12-20 12:08:30.904434 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '35df06ad1029' +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('orbit_days', sa.Integer(), 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 1d2d1dc60bbc10e99c880d5ee7f6b947c44c4cef Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Tue, 20 Dec 2022 19:40:39 -0800 Subject: [PATCH 08/36] added POST and GET routes to planets blueprint to create_planet_data() and to read_all_planets(). --- app/__init__.py | 4 ++-- app/routes.py | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 98289ae5c..7e0b42f08 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,7 @@ def create_app(test_config=None): from app.models.planet import Planet - # from .routes import planets_bp - # app.register_blueprint(planets_bp) + from .routes import planets_bp + app.register_blueprint(planets_bp) return app diff --git a/app/routes.py b/app/routes.py index 3df79d1ef..7212ded52 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,5 +1,42 @@ -from .models.planet import Planet -from flask import Blueprint, jsonify, abort, make_response +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, make_response, request + +planets_bp = Blueprint("planets_bp", __name__,url_prefix="/planets") +@planets_bp.route("", methods=["POST"]) +def create_planet_data(): + request_body = request.get_json() + if "name"not in request_body: + return make_response("Invalid Request", 400) + + new_planet = Planet( + name=request_body["name"], + description=request_body["description"], + orbit_days =request_body["orbit_days"], + num_moons = request_body["num_moons"] + ) + db.session.add(new_planet) + db.session.commit() + return make_response(f"Planet {new_planet.name} successfully created", 201) + +@planets_bp.route("", methods=["GET"]) +def read_all_planets(): + planets_response = [] + planets = Planet.query.all() + + for planet in planets: + planets_response.append( + { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "orbit_days": planet.orbit_days, + "num_moons": planet.num_moons + } + ) + return jsonify(planets_response) + +# ---------------------------Hardcoded Data for Planet------------------------------ # planets = [ # Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), # Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), From 798befbdfe4a1385105d982aac16ac77a28e42e9 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 21 Dec 2022 07:27:08 -0500 Subject: [PATCH 09/36] Added endpoints to create and get all planets. --- app/__init__.py | 4 ++-- app/routes.py | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 98289ae5c..7e0b42f08 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,7 @@ def create_app(test_config=None): from app.models.planet import Planet - # from .routes import planets_bp - # app.register_blueprint(planets_bp) + from .routes import planets_bp + app.register_blueprint(planets_bp) return app diff --git a/app/routes.py b/app/routes.py index 3df79d1ef..baade1874 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,5 +1,46 @@ -from .models.planet import Planet -from flask import Blueprint, jsonify, abort, make_response +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, abort, make_response, request + +planets_bp = Blueprint("planets_bp", __name__, url_prefix="/planets") + +@planets_bp.route("", methods=["POST"]) +def create_planet(): + planet_data = request.get_json() + + new_planet = Planet( + name = planet_data["name"], + description = planet_data["description"], + orbit_days = planet_data["orbit_days"], + num_moons = planet_data["num_moons"] + ) + + db.session.add(new_planet) + db.session.commit() + + return make_response(f"Planet {new_planet.name} created", 201) + +@planets_bp.route("", methods=["GET"]) +def get_all_planets(): + all_planets = Planet.query.all() + planet_response = [] + for planet in all_planets: + planet_response.append({ + "id": planet.id, + "name": planet.name, + "description": planet.description, + "orbit_days": planet.orbit_days, + "num_moons": planet.num_moons + }) + return jsonify(planet_response) + + + + + + + +# # planets = [ # Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), # Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), From 842e96dbcebf833d5b441e9e6929fc0f65e44ae6 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 21 Dec 2022 13:59:06 -0500 Subject: [PATCH 10/36] Added Read, Update, and Delete endpoints --- app/routes.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 7212ded52..8c441dda7 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,8 +1,22 @@ from app import db from app.models.planet import Planet -from flask import Blueprint, jsonify, make_response, request +from flask import Blueprint, jsonify, abort, make_response, request planets_bp = Blueprint("planets_bp", __name__,url_prefix="/planets") + +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"planet {planet_id} invalid"}, 400)) + + planet = Planet.query.get(planet_id) + + if not planet: + abort(make_response({"message":f"planet {planet_id} not found"}, 404)) + + return planet + @planets_bp.route("", methods=["POST"]) def create_planet_data(): request_body = request.get_json() @@ -36,6 +50,42 @@ def read_all_planets(): ) return jsonify(planets_response) +@planets_bp.route("/", methods=["GET"]) +def read_one_planet(planet_id): + planet = validate_planet(planet_id) + return { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "orbit_days": planet.orbit_days, + "num_moons": planet.num_moons + } + +@planets_bp.route("/", methods=["PUT"]) +def update_planet(planet_id): + planet = validate_planet(planet_id) + + request_body = request.get_json() + + planet.name = request_body["name"] + planet.description = request_body["description"] + planet.orbit_days = request_body["orbit_days"] + planet.num_moons = request_body["num_moons"] + + db.session.commit() + + return make_response(f"Planet #{planet.id} successfully updated") + +@planets_bp.route("/", methods=["DELETE"]) +def delete_planet(planet_id): + planet = validate_planet(planet_id) + + db.session.delete(planet) + db.session.commit() + + return make_response(f"Planet #{planet.id} successfully deleted") + + # ---------------------------Hardcoded Data for Planet------------------------------ # planets = [ # Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), From eb94c7309b7d4b2f623b572975f30cd79bdacae2 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 22 Dec 2022 01:26:04 -0800 Subject: [PATCH 11/36] add query params to sort planets by name and display results in ascending or descending order. --- app/__init__.py | 2 ++ app/routes.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 7e0b42f08..0de85b37f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -8,6 +8,8 @@ def create_app(test_config=None): app = Flask(__name__) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['JSON_SORT_KEYS'] = False + app.url_map.strict_slashes = False app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres+psycopg2://postgres:postgres@localhost:5432/solar_system_development' db.init_app(app) diff --git a/app/routes.py b/app/routes.py index 8c441dda7..aa9fc857c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -20,7 +20,7 @@ def validate_planet(planet_id): @planets_bp.route("", methods=["POST"]) def create_planet_data(): request_body = request.get_json() - if "name"not in request_body: + if "name" not in request_body: return make_response("Invalid Request", 400) new_planet = Planet( @@ -36,7 +36,17 @@ def create_planet_data(): @planets_bp.route("", methods=["GET"]) def read_all_planets(): planets_response = [] - planets = Planet.query.all() + name_query = request.args.get("name") + sort_query = request.args.get("sort") + if name_query: + planets = Planet.query.filter_by(name=name_query) + else: + if sort_query == "asc": + planets = Planet.query.order_by(Planet.name).all() + elif sort_query == "desc": + planets = Planet.query.order_by(Planet.name.desc()).all() + else: + planets = Planet.query.all() for planet in planets: planets_response.append( From e06912c1d986f0b45bc086a27f2f26090b354d9a Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 22 Dec 2022 10:50:30 -0800 Subject: [PATCH 12/36] refactor code for query params by name and sort asc or desc --- app/routes.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/routes.py b/app/routes.py index aa9fc857c..c799b2509 100644 --- a/app/routes.py +++ b/app/routes.py @@ -36,17 +36,20 @@ def create_planet_data(): @planets_bp.route("", methods=["GET"]) def read_all_planets(): planets_response = [] + planet_query = Planet.query + name_query = request.args.get("name") - sort_query = request.args.get("sort") if name_query: - planets = Planet.query.filter_by(name=name_query) - else: - if sort_query == "asc": - planets = Planet.query.order_by(Planet.name).all() - elif sort_query == "desc": - planets = Planet.query.order_by(Planet.name.desc()).all() - else: - planets = Planet.query.all() + planet_query = planet_query.filter(Planet.name.ilike(f"%{name_query}%")) + + sort_query = request.args.get("sort") + if sort_query == "desc": + planet_query = planet_query.order_by(Planet.name.desc()) + else: + planet_query = planet_query.order_by(Planet.name) + + + planets = planet_query.all() for planet in planets: planets_response.append( From 87292755b8dd5381cce60d59404c6b5b17565742 Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 22 Dec 2022 16:38:28 -0500 Subject: [PATCH 13/36] Added seed file --- app/planet_seed.sql | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/planet_seed.sql diff --git a/app/planet_seed.sql b/app/planet_seed.sql new file mode 100644 index 000000000..2207985d4 --- /dev/null +++ b/app/planet_seed.sql @@ -0,0 +1,9 @@ +ALTER SEQUENCE planet_id_seq RESTART WITH 1; +INSERT INTO planet VALUES (DEFAULT,'Mercury', 'Mercury is the closest planet to the Sun.', 88, 0); +INSERT INTO planet VALUES (DEFAULT,'Venus', 'Venus is the hottest planet in the solar system.', 225 ,0); +INSERT INTO planet VALUES (DEFAULT,'Earth', 'Our home planet.', 365,1); +INSERT INTO planet VALUES (DEFAULT,'Mars', 'Also known as Red planet.', 687, 2); +INSERT INTO planet VALUES (DEFAULT,'Jupiter','Largest planet in the solar system.', 4333, 80); +INSERT INTO planet VALUES (DEFAULT,'Saturn', 'Only planet to have rings made of ice and rock.', 10759, 83); +INSERT INTO planet VALUES (DEFAULT,'Uranus', 'Only planet with a 97 degree tilted axis.', 30687, 27); +INSERT INTO planet VALUES (DEFAULT,'Neptune', 'Blue ice giant',60190, 14); From 8a4bdd8561317334f8c53b8a9b8864e3c366ff15 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Tue, 3 Jan 2023 23:07:50 -0800 Subject: [PATCH 14/36] added reading SQL configuration from .env file. jsonified make_response returns. --- app/__init__.py | 10 +++++++++- app/models/planet.py | 26 +------------------------- app/routes.py | 29 ++--------------------------- 3 files changed, 12 insertions(+), 53 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 0de85b37f..6eaa9ec34 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,17 +1,25 @@ 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() +load_dotenv() def create_app(test_config=None): app = Flask(__name__) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['JSON_SORT_KEYS'] = False app.url_map.strict_slashes = False - app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres+psycopg2://postgres:postgres@localhost:5432/solar_system_development' + if not test_config: + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') + else: + app.config['SQLALCHEMY_TEST_DATABASE_URI'] = os.environ.get('SQLALCHEMY_TEST_DATABASE_URI') + db.init_app(app) migrate.init_app(app, db) diff --git a/app/models/planet.py b/app/models/planet.py index f9c679598..88d502440 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,28 +4,4 @@ class Planet(db.Model): name = db.Column(db.String()) description = db.Column(db.String()) orbit_days = db.Column(db.Integer()) - num_moons = db.Column(db.Integer()) - - - - - - -# ------------Hardcoded Data for Planet------------------------------ -# class Planet: -# def __init__(self, id, name, description, len_years, num_moons): -# self.id = id -# self.name = name -# self.description = description -# self.len_years = len_years -# self.num_moons = num_moons - - -# def to_dict(self): -# return { -# "id": self.id, -# "name": self.name, -# "description": self.description, -# "length of year": self.len_years, -# "number of moons": self.num_moons, -# } \ No newline at end of file + num_moons = db.Column(db.Integer()) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index c799b2509..0fed1436b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -31,7 +31,7 @@ def create_planet_data(): ) db.session.add(new_planet) db.session.commit() - return make_response(f"Planet {new_planet.name} successfully created", 201) + return make_response(jsonify(f"Planet {new_planet.name} successfully created", 201)) @planets_bp.route("", methods=["GET"]) def read_all_planets(): @@ -96,7 +96,7 @@ def delete_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(f"Planet #{planet.id} successfully deleted") + return make_response(jsonify(f"Planet #{planet.id} successfully deleted")) # ---------------------------Hardcoded Data for Planet------------------------------ @@ -111,28 +111,3 @@ def delete_planet(planet_id): # Planet(8, "Neptune", "Blue ice giant" ,60190, 14 ) # ] -# planets_bp = Blueprint("planets", __name__,url_prefix="/planets") -# @planets_bp.route("", methods=["GET"]) -# def get_all_planets(): -# planets_response = [] -# for planet in planets: -# planets_response.append(planet.to_dict()) - -# return jsonify(planets_response),200 - -# @planets_bp.route("/", methods=["GET"]) -# def get_one_planet(planet_id): -# planet = validate_planet(planet_id) -# return jsonify(planet.to_dict()) - -# def validate_planet(planet_id): -# try: -# planet_id = int(planet_id) -# except: -# abort(make_response({"message":f"planet {planet_id} is invalid"}, 400)) - -# for planet in planets: -# if planet.id == planet_id: -# return planet - -# abort(make_response({"message":f"planet {planet_id} is not found"}, 404)) \ No newline at end of file From 0604d4230c9807eb5cf1e25eb0f2d6250c3aaed1 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Wed, 4 Jan 2023 00:38:59 -0800 Subject: [PATCH 15/36] configure tests in conftest.py, added tests to read and create planet data. --- app/__init__.py | 9 ++++--- app/routes.py | 8 +++--- tests/__init__.py | 0 tests/conftest.py | 39 +++++++++++++++++++++++++++++ tests/test_routes.py | 59 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_routes.py diff --git a/app/__init__.py b/app/__init__.py index 6eaa9ec34..c2910f631 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,14 +11,15 @@ def create_app(test_config=None): app = Flask(__name__) - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False - app.config['JSON_SORT_KEYS'] = False - app.url_map.strict_slashes = False - if not test_config: app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') else: + app.config["TESTING"] = True app.config['SQLALCHEMY_TEST_DATABASE_URI'] = os.environ.get('SQLALCHEMY_TEST_DATABASE_URI') + + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['JSON_SORT_KEYS'] = False + app.url_map.strict_slashes = False db.init_app(app) migrate.init_app(app, db) diff --git a/app/routes.py b/app/routes.py index 0fed1436b..2a1fa7792 100644 --- a/app/routes.py +++ b/app/routes.py @@ -31,7 +31,7 @@ def create_planet_data(): ) db.session.add(new_planet) db.session.commit() - return make_response(jsonify(f"Planet {new_planet.name} successfully created", 201)) + return make_response(jsonify(f"Planet {new_planet.name} successfully created"), 201) @planets_bp.route("", methods=["GET"]) def read_all_planets(): @@ -66,13 +66,13 @@ def read_all_planets(): @planets_bp.route("/", methods=["GET"]) def read_one_planet(planet_id): planet = validate_planet(planet_id) - return { + return jsonify({ "id": planet.id, "name": planet.name, "description": planet.description, "orbit_days": planet.orbit_days, "num_moons": planet.num_moons - } + }) @planets_bp.route("/", methods=["PUT"]) def update_planet(planet_id): @@ -87,7 +87,7 @@ def update_planet(planet_id): db.session.commit() - return make_response(f"Planet #{planet.id} successfully updated") + return make_response(jsonify(f"Planet #{planet.id} successfully updated")) @planets_bp.route("/", methods=["DELETE"]) def delete_planet(planet_id): 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..183f6befd --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,39 @@ +import pytest +from app import create_app +from app import db +from flask.signals import request_finished +from app.models.planet import Planet + +@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 + + with app.app_context(): + db.drop_all() + + +@pytest.fixture +def client(app): + return app.test_client() + + +@pytest.fixture +def one_saved_planet(app): + earth = Planet( + name="Earth", + description="Our home planet.", + orbit_days=365, + num_moons=1 + ) + db.session.add(earth) + db.session.commit() + db.session.refresh(earth, ["id"]) + return earth \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..cf30e947b --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,59 @@ +def test_read_all_planets_with_no_records(client): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] + +def test_read_one_planet_with_one_record(client, one_saved_planet): + # Act + response = client.get(f"/planets/{one_saved_planet.id}") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body["id"] == one_saved_planet.id + assert response_body["name"] == one_saved_planet.name + assert response_body["description"] == one_saved_planet.description + assert response_body["orbit_days"] == one_saved_planet.orbit_days + assert response_body["num_moons"] == one_saved_planet.num_moons + +def test_read_one_planet_with_no_records(client): + # Act + response = client.get(f"/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body["message"] == "planet 1 not found" + +def test_read_all_planets_with_one_record(client, one_saved_planet): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 1 + assert response_body[0]["id"] == one_saved_planet.id + assert response_body[0]["name"] == one_saved_planet.name + assert response_body[0]["description"] == one_saved_planet.description + assert response_body[0]["orbit_days"] == one_saved_planet.orbit_days + assert response_body[0]["num_moons"] == one_saved_planet.num_moons + +def test_create_one_planet(client): + # Act + json_request_body = { + "name": "Mars", + "description": "Also known as Red planet.", + "orbit_days": 687, + "num_moons": 2 + } + response = client.post("/planets", json=json_request_body) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Planet Mars successfully created" \ No newline at end of file From c7de5995667a171ae22111e939504a086bcdfd52 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Wed, 4 Jan 2023 00:40:03 -0800 Subject: [PATCH 16/36] fix pytest warning --- app/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index c2910f631..ca7f3509c 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,7 @@ def create_app(test_config=None): app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') else: app.config["TESTING"] = True - app.config['SQLALCHEMY_TEST_DATABASE_URI'] = os.environ.get('SQLALCHEMY_TEST_DATABASE_URI') + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_TEST_DATABASE_URI') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['JSON_SORT_KEYS'] = False From bb771ec4ce87f7d13d30e93e6c7d36e97c0a42a2 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 05:44:12 -0800 Subject: [PATCH 17/36] Added tests for update and delete --- tests/test_routes.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index cf30e947b..2cb99cf2d 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -56,4 +56,30 @@ def test_create_one_planet(client): # Assert assert response.status_code == 201 - assert response_body == "Planet Mars successfully created" \ No newline at end of file + assert response_body == "Planet Mars successfully created" + +def test_update_planet(client, one_saved_planet): + # Arrange + json_request_body = { + "name": "Mars", + "description": "Known as Red planet.", + "orbit_days": 687, + "num_moons": 2 + } + + # Act + response = client.put("/planets/1", json=json_request_body) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == "Planet #1 successfully updated" + +def test_delete_planet(client, one_saved_planet): + # Act + response = client.delete("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == "Planet #1 successfully deleted" \ No newline at end of file From 4cb75a007790f0ce8f3ae8605837b40cebcf4ddc Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 06:14:44 -0800 Subject: [PATCH 18/36] Added tests for edge cases for update and delete --- tests/test_routes.py | 54 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index 2cb99cf2d..9fbb631b4 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -75,6 +75,40 @@ def test_update_planet(client, one_saved_planet): assert response.status_code == 200 assert response_body == "Planet #1 successfully updated" +def test_update_planet_missing_record(client, one_saved_planet): + # Arrange + json_request_body = { + "name": "Earth", + "description": "The best planet.", + "orbit_days": 365, + "num_moons": 1 + } + + # Act + response = client.put("/planets/2", json=json_request_body) + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == {"message": "planet 2 not found"} + +def test_update_planet_invalid_id(client, one_saved_planet): + # Arrange + json_request_body = { + "name": "Mars", + "description": "Known as Red planet.", + "orbit_days": 687, + "num_moons": 2 + } + + # Act + response = client.put("/planets/mars", json=json_request_body) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == {"message": "planet mars invalid"} + def test_delete_planet(client, one_saved_planet): # Act response = client.delete("/planets/1") @@ -82,4 +116,22 @@ def test_delete_planet(client, one_saved_planet): # Assert assert response.status_code == 200 - assert response_body == "Planet #1 successfully deleted" \ No newline at end of file + assert response_body == "Planet #1 successfully deleted" + +def test_delete_planet_missing_record(client, one_saved_planet): + # Act + response = client.delete("/planets/2") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == {"message": "planet 2 not found"} + +def test_delete_book_invalid_id(client, one_saved_planet): + # Act + response = client.delete("/planets/mars") + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == {"message": "planet mars invalid"} \ No newline at end of file From 672c77380663b8c53293912cab6bcb6a7aa2472e Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 10:29:10 -0800 Subject: [PATCH 19/36] Refactors and adds tests for to_dict() helper --- app/models/planet.py | 12 ++++- app/routes.py | 18 +------ tests/test_models.py | 123 +++++++++++++++++++++++++++++++++++++++++++ tests/test_routes.py | 5 +- 4 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 tests/test_models.py diff --git a/app/models/planet.py b/app/models/planet.py index 88d502440..d46f29c6a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,4 +4,14 @@ class Planet(db.Model): name = db.Column(db.String()) description = db.Column(db.String()) orbit_days = db.Column(db.Integer()) - num_moons = db.Column(db.Integer()) \ No newline at end of file + num_moons = db.Column(db.Integer()) + + def to_dict(self): + planet_as_dict = {} + planet_as_dict["id"] = self.id + planet_as_dict["name"] = self.name + planet_as_dict["description"] = self.description + planet_as_dict["orbit_days"] = self.orbit_days + planet_as_dict["num_moons"] = self.num_moons + + return planet_as_dict diff --git a/app/routes.py b/app/routes.py index 2a1fa7792..9b9ac6ef6 100644 --- a/app/routes.py +++ b/app/routes.py @@ -52,27 +52,13 @@ def read_all_planets(): planets = planet_query.all() for planet in planets: - planets_response.append( - { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "orbit_days": planet.orbit_days, - "num_moons": planet.num_moons - } - ) + planets_response.append(planet.to_dict()) return jsonify(planets_response) @planets_bp.route("/", methods=["GET"]) def read_one_planet(planet_id): planet = validate_planet(planet_id) - return jsonify({ - "id": planet.id, - "name": planet.name, - "description": planet.description, - "orbit_days": planet.orbit_days, - "num_moons": planet.num_moons - }) + return planet.to_dict() @planets_bp.route("/", methods=["PUT"]) def update_planet(planet_id): diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 000000000..78a000a65 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,123 @@ +from app.models.planet import Planet +import pytest + +def test_to_dict_no_missing_data(): + # Arrange + planet_data = Planet( + id = 1, + name = "Mars", + description = "Also known as Red planet.", + orbit_days = 687, + num_moons = 2 + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == 1 + assert result["name"] == "Mars" + assert result["description"] == "Also known as Red planet." + assert result["orbit_days"] == 687 + assert result["num_moons"] == 2 + +def test_to_dict_missing_id(): + # Arrange + planet_data = Planet( + name = "Mars", + description = "Also known as Red planet.", + orbit_days = 687, + num_moons = 2 + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == None + assert result["name"] == "Mars" + assert result["description"] == "Also known as Red planet." + assert result["orbit_days"] == 687 + assert result["num_moons"] == 2 + +def test_to_dict_missing_name(): + # Arrange + planet_data = Planet( + id = 1, + description = "Also known as Red planet.", + orbit_days = 687, + num_moons = 2 + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == 1 + assert result["name"] is None + assert result["description"] == "Also known as Red planet." + assert result["orbit_days"] == 687 + assert result["num_moons"] == 2 + +def test_to_dict_missing_description(): + # Arrange + planet_data = Planet( + id = 1, + name = "Mars", + orbit_days = 687, + num_moons = 2 + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == 1 + assert result["name"] == "Mars" + assert result["description"] is None + assert result["orbit_days"] == 687 + assert result["num_moons"] == 2 + +def test_to_dict_missing_orbit_days(): + # Arrange + planet_data = Planet( + id = 1, + name = "Mars", + description = "Also known as Red planet.", + num_moons = 2 + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == 1 + assert result["name"] == "Mars" + assert result["description"] == "Also known as Red planet." + assert result["orbit_days"] is None + assert result["num_moons"] == 2 + +def test_to_dict_missing_num_moons(): + # Arrange + planet_data = Planet( + id = 1, + name = "Mars", + description = "Also known as Red planet.", + orbit_days = 687, + ) + + # Act + result = planet_data.to_dict() + + # Assert + assert len(result) == 5 + assert result["id"] == 1 + assert result["name"] == "Mars" + assert result["description"] == "Also known as Red planet." + assert result["orbit_days"] == 687 + assert result["num_moons"] is None \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index 9fbb631b4..a11d180cf 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,3 +1,6 @@ +from app.models.planet import Planet +import pytest + def test_read_all_planets_with_no_records(client): # Act response = client.get("/planets") @@ -134,4 +137,4 @@ def test_delete_book_invalid_id(client, one_saved_planet): # Assert assert response.status_code == 400 - assert response_body == {"message": "planet mars invalid"} \ No newline at end of file + assert response_body == {"message": "planet mars invalid"} From f75313f100cc89ce235d25d467afacfe09ce18a1 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 12:03:38 -0800 Subject: [PATCH 20/36] Adds tests for from_dict --- tests/test_models.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index 78a000a65..b5cd02487 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -120,4 +120,23 @@ def test_to_dict_missing_num_moons(): assert result["name"] == "Mars" assert result["description"] == "Also known as Red planet." assert result["orbit_days"] == 687 - assert result["num_moons"] is None \ No newline at end of file + assert result["num_moons"] is None + +def test_from_dict_returns_planet(): + # Arrange + planet_data = { + "name": "Mars", + "description": "Also known as Red planet.", + "orbit_days": 687, + "num_moons": 2 + } + + # Act + new_planet = Planet.from_dict(planet_data) + + # Assert + assert new_planet.name == "Mars" + assert new_planet.description == "Also known as Red planet." + assert new_planet.orbit_days == 687 + assert new_planet.num_moons == 2 + From abde75a969ea7425dcc2f4e37f93433515372078 Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 12:04:19 -0800 Subject: [PATCH 21/36] Refactors validate_planet to validate_model --- app/models/planet.py | 10 ++++++++++ app/routes.py | 27 +++++++++++-------------- tests/test_models.py | 47 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_routes.py | 36 ++++++++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 21 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index d46f29c6a..26717b5ed 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -15,3 +15,13 @@ def to_dict(self): planet_as_dict["num_moons"] = self.num_moons return planet_as_dict + + @classmethod + def from_dict(cls, planet_data): + new_planet = Planet( + name=planet_data["name"], + description=planet_data["description"], + orbit_days=planet_data["orbit_days"], + num_moons=planet_data["num_moons"] + ) + return new_planet diff --git a/app/routes.py b/app/routes.py index 9b9ac6ef6..b60c872e1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -4,18 +4,18 @@ planets_bp = Blueprint("planets_bp", __name__,url_prefix="/planets") -def validate_planet(planet_id): +def validate_model(cls, model_id): try: - planet_id = int(planet_id) + model_id = int(model_id) except: - abort(make_response({"message":f"planet {planet_id} invalid"}, 400)) + abort(make_response({"message":f"{cls.__name__} {model_id} invalid"}, 400)) - planet = Planet.query.get(planet_id) + model = cls.query.get(model_id) - if not planet: - abort(make_response({"message":f"planet {planet_id} not found"}, 404)) + if not model: + abort(make_response({"message":f"{cls.__name__} {model_id} not found"}, 404)) - return planet + return model @planets_bp.route("", methods=["POST"]) def create_planet_data(): @@ -23,12 +23,7 @@ def create_planet_data(): if "name" not in request_body: return make_response("Invalid Request", 400) - new_planet = Planet( - name=request_body["name"], - description=request_body["description"], - orbit_days =request_body["orbit_days"], - num_moons = request_body["num_moons"] - ) + new_planet = Planet.from_dict(request_body) db.session.add(new_planet) db.session.commit() return make_response(jsonify(f"Planet {new_planet.name} successfully created"), 201) @@ -57,12 +52,12 @@ def read_all_planets(): @planets_bp.route("/", methods=["GET"]) def read_one_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) return planet.to_dict() @planets_bp.route("/", methods=["PUT"]) def update_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) request_body = request.get_json() @@ -77,7 +72,7 @@ def update_planet(planet_id): @planets_bp.route("/", methods=["DELETE"]) def delete_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) db.session.delete(planet) db.session.commit() diff --git a/tests/test_models.py b/tests/test_models.py index b5cd02487..74c4d6637 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -140,3 +140,50 @@ def test_from_dict_returns_planet(): assert new_planet.orbit_days == 687 assert new_planet.num_moons == 2 +def test_from_dict_with_no_name(): + # Arrange + planet_data = { + "description": "Also known as Red planet.", + "orbit_days": 687, + "num_moons": 2 + } + + # Act & Assert + with pytest.raises(KeyError, match = 'name'): + new_planet = Planet.from_dict(planet_data) + +def test_from_dict_with_no_description(): + # Arrange + planet_data = { + "name": "Mars", + "orbit_days": 687, + "num_moons": 2 + } + + # Act & Assert + with pytest.raises(KeyError, match = 'description'): + new_planet = Planet.from_dict(planet_data) + +def test_from_dict_with_no_orbit_days(): + # Arrange + planet_data = { + "name": "Mars", + "description": "Also known as Red planet.", + "num_moons": 2 + } + + # Act & Assert + with pytest.raises(KeyError, match = 'orbit_days'): + new_planet = Planet.from_dict(planet_data) + +def test_from_dict_with_no_num_moons(): + # Arrange + planet_data = { + "name": "Mars", + "description": "Also known as Red planet.", + "orbit_days": 687, + } + + # Act & Assert + with pytest.raises(KeyError, match = 'num_moons'): + new_planet = Planet.from_dict(planet_data) \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index a11d180cf..dc823db1b 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,4 +1,6 @@ +from werkzeug.exceptions import HTTPException from app.models.planet import Planet +from app.routes import validate_model import pytest def test_read_all_planets_with_no_records(client): @@ -30,7 +32,7 @@ def test_read_one_planet_with_no_records(client): # Assert assert response.status_code == 404 - assert response_body["message"] == "planet 1 not found" + assert response_body["message"] == "Planet 1 not found" def test_read_all_planets_with_one_record(client, one_saved_planet): # Act @@ -93,7 +95,7 @@ def test_update_planet_missing_record(client, one_saved_planet): # Assert assert response.status_code == 404 - assert response_body == {"message": "planet 2 not found"} + assert response_body == {"message": "Planet 2 not found"} def test_update_planet_invalid_id(client, one_saved_planet): # Arrange @@ -110,7 +112,7 @@ def test_update_planet_invalid_id(client, one_saved_planet): # Assert assert response.status_code == 400 - assert response_body == {"message": "planet mars invalid"} + assert response_body == {"message": "Planet mars invalid"} def test_delete_planet(client, one_saved_planet): # Act @@ -128,7 +130,7 @@ def test_delete_planet_missing_record(client, one_saved_planet): # Assert assert response.status_code == 404 - assert response_body == {"message": "planet 2 not found"} + assert response_body == {"message": "Planet 2 not found"} def test_delete_book_invalid_id(client, one_saved_planet): # Act @@ -137,4 +139,28 @@ def test_delete_book_invalid_id(client, one_saved_planet): # Assert assert response.status_code == 400 - assert response_body == {"message": "planet mars invalid"} + assert response_body == {"message": "Planet mars invalid"} + +def test_validate_model(one_saved_planet): + # Act + result_planet = validate_model(Planet, 1) + + # Assert + assert result_planet.id == one_saved_planet.id + assert result_planet.description == one_saved_planet.description + assert result_planet.orbit_days == one_saved_planet.orbit_days + assert result_planet.num_moons == one_saved_planet.num_moons + +def test_validate_model_missing_record(one_saved_planet): + # Act & Assert + # Calling `validate_model` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, "2") + +def test_validate_model_invalid_id(one_saved_planet): + # Act & Assert + # Calling `validate_model` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, "mars") \ No newline at end of file From 706d1231f5a4ef5f9455b13a791430665b5a415b Mon Sep 17 00:00:00 2001 From: kelly Date: Wed, 4 Jan 2023 12:39:05 -0800 Subject: [PATCH 22/36] Corrects typo in create_planet --- app/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index b60c872e1..2f27283af 100644 --- a/app/routes.py +++ b/app/routes.py @@ -18,7 +18,7 @@ def validate_model(cls, model_id): return model @planets_bp.route("", methods=["POST"]) -def create_planet_data(): +def create_planet(): request_body = request.get_json() if "name" not in request_body: return make_response("Invalid Request", 400) From 5dce2e36f4c287157b5870b3230bd94137c8e17d Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 5 Jan 2023 01:12:07 -0800 Subject: [PATCH 23/36] adds moon.py and moon_bp blueprint. Also adds routes to create and read moons. --- app/__init__.py | 6 ++- app/models/moon.py | 24 +++++++++ app/models/planet.py | 1 + app/moon_routes.py | 83 +++++++++++++++++++++++++++++ app/{routes.py => planet_routes.py} | 13 ----- tests/test_routes.py | 2 +- 6 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 app/models/moon.py create mode 100644 app/moon_routes.py rename app/{routes.py => planet_routes.py} (78%) diff --git a/app/__init__.py b/app/__init__.py index ca7f3509c..b054b8d25 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -25,8 +25,12 @@ def create_app(test_config=None): migrate.init_app(app, db) from app.models.planet import Planet + from app.models.moon import Moon - from .routes import planets_bp + from .planet_routes import planets_bp app.register_blueprint(planets_bp) + from .moon_routes import moon_bp + app.register_blueprint(moon_bp) + return app diff --git a/app/models/moon.py b/app/models/moon.py new file mode 100644 index 000000000..de8575168 --- /dev/null +++ b/app/models/moon.py @@ -0,0 +1,24 @@ +from app import db +class Moon(db.Model): + id = db.Column(db.Integer,primary_key=True, autoincrement=True) + name = db.Column(db.String()) + #planet_id = db.Column(db.Integer, db.ForeignKey("planet.id"), nullable=False) + #planet = db.relationship("Planet", back_populates="Moon") + + def to_dict(self): + moon_as_dict = {} + moon_as_dict["id"] = self.id + moon_as_dict["name"] = self.name + moon_as_dict["planet_id"] = self.planet_id + + return moon_as_dict + + @classmethod + def from_dict(cls, moon_data): + new_moon = Moon( + name=moon_data["name"], + description=moon_data["description"], + orbit_days=moon_data["orbit_days"], + num_moons=moon_data["num_moons"] + ) + return new_moon diff --git a/app/models/planet.py b/app/models/planet.py index 26717b5ed..cfc23913a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -5,6 +5,7 @@ class Planet(db.Model): description = db.Column(db.String()) orbit_days = db.Column(db.Integer()) num_moons = db.Column(db.Integer()) + #moon = db.relationship("Moon", back_populates="Planet") def to_dict(self): planet_as_dict = {} diff --git a/app/moon_routes.py b/app/moon_routes.py new file mode 100644 index 000000000..f895a793b --- /dev/null +++ b/app/moon_routes.py @@ -0,0 +1,83 @@ +from app import db +from app.models.moon import Moon +from app.models.planet import Planet +from app.planet_routes import validate_model +from flask import Blueprint, jsonify, abort, make_response, request + +moon_bp = Blueprint("moon_bp", __name__, url_prefix="/moons") + +@moon_bp.route("", methods=["POST"]) +def create_one_moon(): + request_body = request.get_json() + new_moon = Moon(name=request_body["name"],) + + db.session.add(new_moon) + db.session.commit() + + return make_response(jsonify(f"Moon {new_moon.name} successfully created"), 201) + +@moon_bp.route("", methods=["GET"]) +def read_one_moon_by_name(): + + moons_query = Moon.query + name_query = request.args.get("name") + if name_query: + moons_query = moons_query.filter(Moon.name.ilike(f"%{name_query}%")) + moons = moons_query.all() + moons_response = [] + for moon in moons: + moons_response.append(moon.to_dict()) + return jsonify(moons_response) + +@moon_bp.route("/", methods=["GET"]) +def read_one_moon_by_id(moon_id): + + moon = validate_model(Moon, moon_id) + return moon.to_dict() + +@moon_bp.route("", methods=["GET"]) +def read_all_moons(): + + moons = Moon.query.all() + + moons_response = [] + for moon in moons: + moons_response.append( + { + "name": moon.name + } + ) + return jsonify(moons_response) + +@moon_bp.route("//moons", methods=["POST"]) +def create_one_moon_with_planet_id(planet_id): + + planet = validate_model(Planet, planet_id) + + request_body = request.get_json() + new_moon = Moon( + name=request_body["name"], + planet=planet + ) + db.session.add(new_moon) + db.session.commit() + + return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) + +@moon_bp.route("//moons", methods=["GET"]) +def read_all_moons_from_a_planet(planet_id): + + planet = validate_model(Planet, planet_id) + + moons_response = [] + for moon in planet.moons: + moons_response.append( + { + "id": moon.id, + "name": moon.title, + "planet_id": moon.planet_id + } + ) + return jsonify(moons_response) + + diff --git a/app/routes.py b/app/planet_routes.py similarity index 78% rename from app/routes.py rename to app/planet_routes.py index 2f27283af..fe1bace35 100644 --- a/app/routes.py +++ b/app/planet_routes.py @@ -79,16 +79,3 @@ def delete_planet(planet_id): return make_response(jsonify(f"Planet #{planet.id} successfully deleted")) - -# ---------------------------Hardcoded Data for Planet------------------------------ -# planets = [ -# Planet(1, "Mercury", "Mercury is the closest planet to the Sun.", 88, 0), -# Planet(2, "Venus", "Venus is the hottest planet in the solar system.",225 ,0 ), -# Planet(3, "Earth", "Our home planet.", 365,1), -# Planet(4, "Mars", "Also known as Red planet.",687, 2), -# Planet(5, "Jupiter","Largest planet in the solar system.",4333, 80), -# Planet(6, "Saturn", "Only planet to have rings made of ice and rock.",10759, 83), -# Planet(7, "Uranus", "Only planet with a 97 degree tilted axis.", 30687, 27), -# Planet(8, "Neptune", "Blue ice giant" ,60190, 14 ) -# ] - diff --git a/tests/test_routes.py b/tests/test_routes.py index dc823db1b..a5dfe70ff 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,6 +1,6 @@ from werkzeug.exceptions import HTTPException from app.models.planet import Planet -from app.routes import validate_model +from app.planet_routes import validate_model import pytest def test_read_all_planets_with_no_records(client): From b9e87617c5380c31cd72de2655d1c8a3dac53f8d Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 5 Jan 2023 01:25:56 -0800 Subject: [PATCH 24/36] adds moon model migration change. --- .../versions/b248cab7fbee_adds_moon_model.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 migrations/versions/b248cab7fbee_adds_moon_model.py diff --git a/migrations/versions/b248cab7fbee_adds_moon_model.py b/migrations/versions/b248cab7fbee_adds_moon_model.py new file mode 100644 index 000000000..5daaaa1d4 --- /dev/null +++ b/migrations/versions/b248cab7fbee_adds_moon_model.py @@ -0,0 +1,32 @@ +"""adds Moon model + +Revision ID: b248cab7fbee +Revises: 35df06ad1029 +Create Date: 2023-01-05 01:23:13.429343 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b248cab7fbee' +down_revision = '35df06ad1029' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('moon', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('moon') + # ### end Alembic commands ### From 653abf4499e360d50ea6100b65f24a8a1ac60d09 Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 5 Jan 2023 01:38:48 -0800 Subject: [PATCH 25/36] remove references to foreign key. tests pass and routes are working as expected. --- app/models/moon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/moon.py b/app/models/moon.py index de8575168..3474e15ec 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -9,7 +9,7 @@ def to_dict(self): moon_as_dict = {} moon_as_dict["id"] = self.id moon_as_dict["name"] = self.name - moon_as_dict["planet_id"] = self.planet_id + #moon_as_dict["planet_id"] = self.planet_id return moon_as_dict From e99dba2591603bc7ba2acb23981f6a0a4aab61ae Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 5 Jan 2023 08:03:20 -0800 Subject: [PATCH 26/36] Updates planet and moon models for FK relationship --- app/models/moon.py | 5 ++--- app/models/planet.py | 3 ++- tests/test_models.py | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 3474e15ec..d78a9e2c4 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -2,14 +2,13 @@ class Moon(db.Model): id = db.Column(db.Integer,primary_key=True, autoincrement=True) name = db.Column(db.String()) - #planet_id = db.Column(db.Integer, db.ForeignKey("planet.id"), nullable=False) - #planet = db.relationship("Planet", back_populates="Moon") + planet = db.relationship("Planet", back_populates="moon") def to_dict(self): moon_as_dict = {} moon_as_dict["id"] = self.id moon_as_dict["name"] = self.name - #moon_as_dict["planet_id"] = self.planet_id + moon_as_dict["planet_id"] = self.planet_id return moon_as_dict diff --git a/app/models/planet.py b/app/models/planet.py index cfc23913a..c729c931e 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -5,7 +5,8 @@ class Planet(db.Model): description = db.Column(db.String()) orbit_days = db.Column(db.Integer()) num_moons = db.Column(db.Integer()) - #moon = db.relationship("Moon", back_populates="Planet") + moon_id = db.Column(db.Integer, db.ForeignKey('moon.id')) + moon = db.relationship("Moon", back_populates="planet") def to_dict(self): planet_as_dict = {} diff --git a/tests/test_models.py b/tests/test_models.py index 74c4d6637..68c5b5935 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,4 +1,5 @@ from app.models.planet import Planet +from app.models.moon import Moon import pytest def test_to_dict_no_missing_data(): From b622107cd3f7de26f921673333fc8e05f6dd50fb Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 5 Jan 2023 08:12:52 -0800 Subject: [PATCH 27/36] Migrations to add/update Moon and Planet models --- migrations/versions/eeb3c9352af8_.py | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 migrations/versions/eeb3c9352af8_.py diff --git a/migrations/versions/eeb3c9352af8_.py b/migrations/versions/eeb3c9352af8_.py new file mode 100644 index 000000000..b87ebe4ee --- /dev/null +++ b/migrations/versions/eeb3c9352af8_.py @@ -0,0 +1,41 @@ +"""empty message + +Revision ID: eeb3c9352af8 +Revises: +Create Date: 2023-01-05 07:00:29.722468 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'eeb3c9352af8' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('moon', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + 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('orbit_days', sa.Integer(), 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') + op.drop_table('moon') + # ### end Alembic commands ### From 6856cda36b80bfd98b795ec5566d4c856135654c Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 5 Jan 2023 08:14:05 -0800 Subject: [PATCH 28/36] Removes old migration files --- .../35df06ad1029_adds_planet_model.py | 35 ------------------- .../versions/b248cab7fbee_adds_moon_model.py | 32 ----------------- 2 files changed, 67 deletions(-) delete mode 100644 migrations/versions/35df06ad1029_adds_planet_model.py delete mode 100644 migrations/versions/b248cab7fbee_adds_moon_model.py diff --git a/migrations/versions/35df06ad1029_adds_planet_model.py b/migrations/versions/35df06ad1029_adds_planet_model.py deleted file mode 100644 index 03081a331..000000000 --- a/migrations/versions/35df06ad1029_adds_planet_model.py +++ /dev/null @@ -1,35 +0,0 @@ -"""adds Planet model - -Revision ID: 35df06ad1029 -Revises: -Create Date: 2022-12-20 12:08:30.904434 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '35df06ad1029' -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('orbit_days', sa.Integer(), 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 ### diff --git a/migrations/versions/b248cab7fbee_adds_moon_model.py b/migrations/versions/b248cab7fbee_adds_moon_model.py deleted file mode 100644 index 5daaaa1d4..000000000 --- a/migrations/versions/b248cab7fbee_adds_moon_model.py +++ /dev/null @@ -1,32 +0,0 @@ -"""adds Moon model - -Revision ID: b248cab7fbee -Revises: 35df06ad1029 -Create Date: 2023-01-05 01:23:13.429343 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'b248cab7fbee' -down_revision = '35df06ad1029' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('moon', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('moon') - # ### end Alembic commands ### From b0a271d3950ef534723f014cc2d5e1f4f5c38aab Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Thu, 5 Jan 2023 12:07:15 -0800 Subject: [PATCH 29/36] adds additional details to moon model. --- app/models/moon.py | 16 ++++++--- app/models/planet.py | 10 ++++-- app/moon_routes.py | 34 +++++++++---------- .../{eeb3c9352af8_.py => ff811225ddeb_.py} | 21 +++++++----- tests/test_models.py | 13 +++---- 5 files changed, 55 insertions(+), 39 deletions(-) rename migrations/versions/{eeb3c9352af8_.py => ff811225ddeb_.py} (72%) diff --git a/app/models/moon.py b/app/models/moon.py index d78a9e2c4..b403d8fab 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -2,14 +2,21 @@ class Moon(db.Model): id = db.Column(db.Integer,primary_key=True, autoincrement=True) name = db.Column(db.String()) - planet = db.relationship("Planet", back_populates="moon") + size = db.Column(db.Integer()) + description = db.Column(db.String()) + distance_from_planet = db.Column(db.Integer()) + planet_id = db.Column(db.Integer(), db.ForeignKey('planet.id')) + planet = db.relationship("Planet", back_populates="moons") def to_dict(self): moon_as_dict = {} moon_as_dict["id"] = self.id moon_as_dict["name"] = self.name + moon_as_dict["size"] = self.size + moon_as_dict["description"] = self.description + moon_as_dict["distance_from_planet"] = self.distance_from_planet moon_as_dict["planet_id"] = self.planet_id - + return moon_as_dict @classmethod @@ -17,7 +24,8 @@ def from_dict(cls, moon_data): new_moon = Moon( name=moon_data["name"], description=moon_data["description"], - orbit_days=moon_data["orbit_days"], - num_moons=moon_data["num_moons"] + size=moon_data["size"], + distance_from_planet=moon_data["distance_from_planet"], + planet_id=moon_data["planet_id"] ) return new_moon diff --git a/app/models/planet.py b/app/models/planet.py index c729c931e..d0bf79fd7 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -5,8 +5,7 @@ class Planet(db.Model): description = db.Column(db.String()) orbit_days = db.Column(db.Integer()) num_moons = db.Column(db.Integer()) - moon_id = db.Column(db.Integer, db.ForeignKey('moon.id')) - moon = db.relationship("Moon", back_populates="planet") + moons = db.relationship("Moon", back_populates="planet") def to_dict(self): planet_as_dict = {} @@ -15,6 +14,10 @@ def to_dict(self): planet_as_dict["description"] = self.description planet_as_dict["orbit_days"] = self.orbit_days planet_as_dict["num_moons"] = self.num_moons + moons_list = [] + for moon in self.moons: + moons_list.append(moon.to_dict()) + planet_as_dict["moons"] = moons_list return planet_as_dict @@ -24,6 +27,7 @@ def from_dict(cls, planet_data): name=planet_data["name"], description=planet_data["description"], orbit_days=planet_data["orbit_days"], - num_moons=planet_data["num_moons"] + num_moons=planet_data["num_moons"], + ) return new_planet diff --git a/app/moon_routes.py b/app/moon_routes.py index f895a793b..79baf0ca4 100644 --- a/app/moon_routes.py +++ b/app/moon_routes.py @@ -9,8 +9,8 @@ @moon_bp.route("", methods=["POST"]) def create_one_moon(): request_body = request.get_json() - new_moon = Moon(name=request_body["name"],) - + new_moon = Moon.from_dict(request_body) + db.session.add(new_moon) db.session.commit() @@ -42,11 +42,7 @@ def read_all_moons(): moons_response = [] for moon in moons: - moons_response.append( - { - "name": moon.name - } - ) + moons_response.append(moon.to_dict()) return jsonify(moons_response) @moon_bp.route("//moons", methods=["POST"]) @@ -55,10 +51,8 @@ def create_one_moon_with_planet_id(planet_id): planet = validate_model(Planet, planet_id) request_body = request.get_json() - new_moon = Moon( - name=request_body["name"], - planet=planet - ) + new_moon = Moon.from_dict(request_body) + new_moon.planet = planet db.session.add(new_moon) db.session.commit() @@ -71,13 +65,17 @@ def read_all_moons_from_a_planet(planet_id): moons_response = [] for moon in planet.moons: - moons_response.append( - { - "id": moon.id, - "name": moon.title, - "planet_id": moon.planet_id - } - ) + moons_response.append(moon.to_dict()) + return jsonify(moons_response) +@moon_bp.route("/", methods=["DELETE"]) +def delete_moon_by_id(moon_id): + moon = validate_model(Moon,moon_id) + + db.session.delete(moon) + db.session.commit() + + return make_response(jsonify(f"Moon {moon.name} successfully deleted")) + diff --git a/migrations/versions/eeb3c9352af8_.py b/migrations/versions/ff811225ddeb_.py similarity index 72% rename from migrations/versions/eeb3c9352af8_.py rename to migrations/versions/ff811225ddeb_.py index b87ebe4ee..c468ce37f 100644 --- a/migrations/versions/eeb3c9352af8_.py +++ b/migrations/versions/ff811225ddeb_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: eeb3c9352af8 +Revision ID: ff811225ddeb Revises: -Create Date: 2023-01-05 07:00:29.722468 +Create Date: 2023-01-05 11:14:55.048062 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = 'eeb3c9352af8' +revision = 'ff811225ddeb' down_revision = None branch_labels = None depends_on = None @@ -18,17 +18,22 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('moon', + 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('orbit_days', sa.Integer(), nullable=True), + sa.Column('num_moons', sa.Integer(), nullable=True), sa.PrimaryKeyConstraint('id') ) - op.create_table('planet', + op.create_table('moon', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), sa.Column('name', sa.String(), nullable=True), + sa.Column('size', sa.Integer(), nullable=True), sa.Column('description', sa.String(), nullable=True), - sa.Column('orbit_days', sa.Integer(), nullable=True), - sa.Column('num_moons', sa.Integer(), nullable=True), + sa.Column('distance_from_planet', sa.Integer(), nullable=True), + sa.Column('planet_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['planet_id'], ['planet.id'], ), sa.PrimaryKeyConstraint('id') ) # ### end Alembic commands ### @@ -36,6 +41,6 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('planet') op.drop_table('moon') + op.drop_table('planet') # ### end Alembic commands ### diff --git a/tests/test_models.py b/tests/test_models.py index 68c5b5935..78cd95b3b 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -10,13 +10,14 @@ def test_to_dict_no_missing_data(): description = "Also known as Red planet.", orbit_days = 687, num_moons = 2 + ) # Act result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == 1 assert result["name"] == "Mars" assert result["description"] == "Also known as Red planet." @@ -36,7 +37,7 @@ def test_to_dict_missing_id(): result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == None assert result["name"] == "Mars" assert result["description"] == "Also known as Red planet." @@ -56,7 +57,7 @@ def test_to_dict_missing_name(): result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == 1 assert result["name"] is None assert result["description"] == "Also known as Red planet." @@ -76,7 +77,7 @@ def test_to_dict_missing_description(): result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == 1 assert result["name"] == "Mars" assert result["description"] is None @@ -96,7 +97,7 @@ def test_to_dict_missing_orbit_days(): result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == 1 assert result["name"] == "Mars" assert result["description"] == "Also known as Red planet." @@ -116,7 +117,7 @@ def test_to_dict_missing_num_moons(): result = planet_data.to_dict() # Assert - assert len(result) == 5 + assert len(result) == 6 assert result["id"] == 1 assert result["name"] == "Mars" assert result["description"] == "Also known as Red planet." From a6eb19c0ee7c8316a011fb296d1a961730abc117 Mon Sep 17 00:00:00 2001 From: kelly Date: Thu, 5 Jan 2023 12:52:52 -0800 Subject: [PATCH 30/36] Moved nested routes to planet_routes --- app/moon_routes.py | 32 ++++++++++++++++---------------- app/planet_routes.py | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/app/moon_routes.py b/app/moon_routes.py index 79baf0ca4..5be594d4a 100644 --- a/app/moon_routes.py +++ b/app/moon_routes.py @@ -45,29 +45,29 @@ def read_all_moons(): moons_response.append(moon.to_dict()) return jsonify(moons_response) -@moon_bp.route("//moons", methods=["POST"]) -def create_one_moon_with_planet_id(planet_id): +# @moon_bp.route("//moons", methods=["POST"]) +# def create_one_moon_with_planet_id(planet_id): - planet = validate_model(Planet, planet_id) +# planet = validate_model(Planet, planet_id) - request_body = request.get_json() - new_moon = Moon.from_dict(request_body) - new_moon.planet = planet - db.session.add(new_moon) - db.session.commit() +# request_body = request.get_json() +# new_moon = Moon.from_dict(request_body) +# new_moon.planet = planet +# db.session.add(new_moon) +# db.session.commit() - return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) +# return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) -@moon_bp.route("//moons", methods=["GET"]) -def read_all_moons_from_a_planet(planet_id): +# @moon_bp.route("//moons", methods=["GET"]) +# def read_all_moons_from_a_planet(planet_id): - planet = validate_model(Planet, planet_id) +# planet = validate_model(Planet, planet_id) - moons_response = [] - for moon in planet.moons: - moons_response.append(moon.to_dict()) +# moons_response = [] +# for moon in planet.moons: +# moons_response.append(moon.to_dict()) - return jsonify(moons_response) +# return jsonify(moons_response) @moon_bp.route("/", methods=["DELETE"]) def delete_moon_by_id(moon_id): diff --git a/app/planet_routes.py b/app/planet_routes.py index fe1bace35..18f2b6ebc 100644 --- a/app/planet_routes.py +++ b/app/planet_routes.py @@ -1,5 +1,6 @@ from app import db from app.models.planet import Planet +from app.models.moon import Moon from flask import Blueprint, jsonify, abort, make_response, request planets_bp = Blueprint("planets_bp", __name__,url_prefix="/planets") @@ -79,3 +80,26 @@ def delete_planet(planet_id): return make_response(jsonify(f"Planet #{planet.id} successfully deleted")) +@planets_bp.route("//moons", methods=["POST"]) +def create_one_moon_with_planet_id(planet_id): + + planet = validate_model(Planet, planet_id) + + request_body = request.get_json() + new_moon = Moon.from_dict(request_body) + new_moon.planet = planet + db.session.add(new_moon) + db.session.commit() + + return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) + +@planets_bp.route("//moons", methods=["GET"]) +def read_all_moons_from_a_planet(planet_id): + + planet = validate_model(Planet, planet_id) + + moons_response = [] + for moon in planet.moons: + moons_response.append(moon.to_dict()) + + return jsonify(moons_response) \ No newline at end of file From 4cf54b55427ccaa498e39a6bcf8379e4c30d46fb Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Fri, 6 Jan 2023 01:04:24 -0800 Subject: [PATCH 31/36] added Procfile. installed gunicorn and added it to requirements. --- Procfile | 0 requirements.txt | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..e69de29bb diff --git a/requirements.txt b/requirements.txt index fba2b3e38..f1c31b3f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,25 @@ alembic==1.5.4 +attrs==22.1.0 autopep8==1.5.5 blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 +coverage==6.5.0 Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 +gunicorn==20.1.0 idna==2.10 +iniconfig==1.1.1 itsdangerous==1.1.0 Jinja2==2.11.3 Mako==1.1.4 MarkupSafe==1.1.1 +packaging==22.0 +pluggy==1.0.0 psycopg2-binary==2.9.4 +py==1.11.0 pycodestyle==2.6.0 pytest==7.1.1 pytest-cov==2.12.1 @@ -23,5 +30,6 @@ requests==2.25.1 six==1.15.0 SQLAlchemy==1.3.23 toml==0.10.2 +tomli==2.0.1 urllib3==1.26.4 Werkzeug==1.0.1 From 0e2278ce20ed8ad99f90e3659ac83d82bb62723e Mon Sep 17 00:00:00 2001 From: Soumya Sah <85212732+smysh@users.noreply.github.com> Date: Fri, 6 Jan 2023 01:15:12 -0800 Subject: [PATCH 32/36] added web: gunicorn to Procfile. --- Procfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Procfile b/Procfile index e69de29bb..62e430aca 100644 --- a/Procfile +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn 'app:create_app()' \ No newline at end of file From c4eb47aa62aaff045a4f67688e10cd04b08154a0 Mon Sep 17 00:00:00 2001 From: kelly Date: Sun, 8 Jan 2023 07:44:49 -0800 Subject: [PATCH 33/36] Minor correction to test name --- tests/test_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index a5dfe70ff..9130df36a 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -132,7 +132,7 @@ def test_delete_planet_missing_record(client, one_saved_planet): assert response.status_code == 404 assert response_body == {"message": "Planet 2 not found"} -def test_delete_book_invalid_id(client, one_saved_planet): +def test_delete_planet_invalid_id(client, one_saved_planet): # Act response = client.delete("/planets/mars") response_body = response.get_json() From dd9750258562c5c87598ac1a714983ef025ac87a Mon Sep 17 00:00:00 2001 From: kelly Date: Sun, 8 Jan 2023 07:45:05 -0800 Subject: [PATCH 34/36] Adds Procfile --- Procfile | 1 + requirements.txt | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..62e430aca --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn 'app:create_app()' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fba2b3e38..3e19aa0b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,25 @@ alembic==1.5.4 +attrs==22.2.0 autopep8==1.5.5 blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 +coverage==7.0.3 Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 +gunicorn==20.1.0 idna==2.10 +iniconfig==1.1.1 itsdangerous==1.1.0 Jinja2==2.11.3 Mako==1.1.4 MarkupSafe==1.1.1 +packaging==22.0 +pluggy==1.0.0 psycopg2-binary==2.9.4 +py==1.11.0 pycodestyle==2.6.0 pytest==7.1.1 pytest-cov==2.12.1 @@ -23,5 +30,6 @@ requests==2.25.1 six==1.15.0 SQLAlchemy==1.3.23 toml==0.10.2 +tomli==2.0.1 urllib3==1.26.4 Werkzeug==1.0.1 From 591ce8f34ea79c2da89adbe9e53dfeece71da1c3 Mon Sep 17 00:00:00 2001 From: kelly Date: Mon, 9 Jan 2023 08:04:28 -0800 Subject: [PATCH 35/36] Removes commented-out code in moon_routes --- app/moon_routes.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/app/moon_routes.py b/app/moon_routes.py index 5be594d4a..bec975304 100644 --- a/app/moon_routes.py +++ b/app/moon_routes.py @@ -45,30 +45,6 @@ def read_all_moons(): moons_response.append(moon.to_dict()) return jsonify(moons_response) -# @moon_bp.route("//moons", methods=["POST"]) -# def create_one_moon_with_planet_id(planet_id): - -# planet = validate_model(Planet, planet_id) - -# request_body = request.get_json() -# new_moon = Moon.from_dict(request_body) -# new_moon.planet = planet -# db.session.add(new_moon) -# db.session.commit() - -# return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) - -# @moon_bp.route("//moons", methods=["GET"]) -# def read_all_moons_from_a_planet(planet_id): - -# planet = validate_model(Planet, planet_id) - -# moons_response = [] -# for moon in planet.moons: -# moons_response.append(moon.to_dict()) - -# return jsonify(moons_response) - @moon_bp.route("/", methods=["DELETE"]) def delete_moon_by_id(moon_id): moon = validate_model(Moon,moon_id) From 23a31a7d163dc2315a494ee4b15de7a200bee2f6 Mon Sep 17 00:00:00 2001 From: kelly Date: Mon, 9 Jan 2023 18:34:31 -0800 Subject: [PATCH 36/36] Updates moon creation and deletion routes --- app/moon_routes.py | 5 ++++- app/planet_routes.py | 1 + app/planet_seed.sql | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/moon_routes.py b/app/moon_routes.py index bec975304..a475e7815 100644 --- a/app/moon_routes.py +++ b/app/moon_routes.py @@ -45,11 +45,14 @@ def read_all_moons(): moons_response.append(moon.to_dict()) return jsonify(moons_response) + @moon_bp.route("/", methods=["DELETE"]) def delete_moon_by_id(moon_id): - moon = validate_model(Moon,moon_id) + moon = validate_model(Moon, moon_id) + planet = validate_model(Planet, moon.planet_id) db.session.delete(moon) + planet.num_moons = len(planet.moons) db.session.commit() return make_response(jsonify(f"Moon {moon.name} successfully deleted")) diff --git a/app/planet_routes.py b/app/planet_routes.py index 18f2b6ebc..41b49d366 100644 --- a/app/planet_routes.py +++ b/app/planet_routes.py @@ -89,6 +89,7 @@ def create_one_moon_with_planet_id(planet_id): new_moon = Moon.from_dict(request_body) new_moon.planet = planet db.session.add(new_moon) + planet.num_moons = len(planet.moons) db.session.commit() return make_response(jsonify(f"Moon {new_moon.name} by {new_moon.planet.name} successfully created"), 201) diff --git a/app/planet_seed.sql b/app/planet_seed.sql index 2207985d4..bf84fd042 100644 --- a/app/planet_seed.sql +++ b/app/planet_seed.sql @@ -1,4 +1,5 @@ ALTER SEQUENCE planet_id_seq RESTART WITH 1; +ALTER SEQUENCE moon_id_seq RESTART WITH 1; INSERT INTO planet VALUES (DEFAULT,'Mercury', 'Mercury is the closest planet to the Sun.', 88, 0); INSERT INTO planet VALUES (DEFAULT,'Venus', 'Venus is the hottest planet in the solar system.', 225 ,0); INSERT INTO planet VALUES (DEFAULT,'Earth', 'Our home planet.', 365,1); @@ -7,3 +8,6 @@ INSERT INTO planet VALUES (DEFAULT,'Jupiter','Largest planet in the solar system INSERT INTO planet VALUES (DEFAULT,'Saturn', 'Only planet to have rings made of ice and rock.', 10759, 83); INSERT INTO planet VALUES (DEFAULT,'Uranus', 'Only planet with a 97 degree tilted axis.', 30687, 27); INSERT INTO planet VALUES (DEFAULT,'Neptune', 'Blue ice giant',60190, 14); +INSERT INTO moon VALUES (DEFAULT,'The Moon', 2159, 'The moon of Earth.', 238855, 3); +INSERT INTO moon VALUES (DEFAULT,'Deimos', 428, 'The smaller of the two moons of Mars.', 14580, 4); +INSERT INTO moon VALUES (DEFAULT,'The Phobos', 2618, 'The larger moon of Mars.', 3700, 4); \ No newline at end of file