diff --git a/Unit-01/04-flask-crud/app.py b/Unit-01/04-flask-crud/app.py index 249a96e..f55f68d 100644 --- a/Unit-01/04-flask-crud/app.py +++ b/Unit-01/04-flask-crud/app.py @@ -1,3 +1,77 @@ -from flask import Flask +from flask import Flask, render_template, url_for, redirect, request +from flask_modus import Modus +from flask_sqlalchemy import SQLAlchemy + +app=Flask(__name__) +modus=Modus(app) +app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/snacks-db' +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +db = SQLAlchemy(app) + +class Snack(db.Model): + __tablename__="snacks" + + id= db.Column(db.Integer, primary_key=True) + name = db.Column(db.Text) + kind = db.Column(db.Text) + + def __init__(self, name, kind): + self.name = name + self.kind = kind + + def __repr__(self): + return "Name: {self.name}; Kind: {self.kind}" + + + +@app.route("/snacks", methods=["GET", "POST"]) +def index(): + if request.method == "POST": + name = request.form.get('name') + kind = request.form.get('kind') + db.session.add(Snack(name, kind)) + db.session.commit() + return redirect(url_for('index')) + return render_template("index.html", snacks=Snack.query.order_by(Snack.id).all()) + +@app.route("/snacks/new") +def new(): + return render_template("new.html") + +@app.route("/snacks/", methods=["GET", "PATCH", "DELETE"]) +def show(id): + try: + individual_snack = Snack.query.get(id) + + if request.method == b"PATCH": + individual_snack.name = (request.form['name']) + individual_snack.kind = (request.form['kind']) + db.session.add(individual_snack) + db.session.commit() + + elif request.method == b"DELETE": + db.session.delete(individual_snack) + db.session.commit() + return redirect(url_for('index')) + + return render_template('show.html', snack = individual_snack) + except: + return redirect(url_for('not_found', id=id)) + +@app.route("/snacks//edit") +def edit(id): + try: + individual_snack = Snack.query.get(id) + return render_template('edit.html', snack=individual_snack) + except: + return redirect(url_for('not_found', id=id)) + + + +@app.route("/snacks//not-found") +def not_found(id): + return render_template('404.html') + +if __name__ == "__main__": + app.run(debug=True) -snack_list = [] \ No newline at end of file diff --git a/Unit-01/04-flask-crud/snack.py b/Unit-01/04-flask-crud/snack.py index ec42c28..67a97d0 100644 --- a/Unit-01/04-flask-crud/snack.py +++ b/Unit-01/04-flask-crud/snack.py @@ -1 +1,23 @@ -# Add a class for a snack here! \ No newline at end of file +# Add a class for a snack here! +class Snack(): + id = 1 + def __init__(self, name, kind): + self._name = name + self._kind = kind + self.id = Snack.id + Snack.id += 1 + def __repr__(self): + return "Name: {self.name}; Kind: {self.kind}" + @property + def name(self): + return self._name + @name.setter + def name(self, value): + self._name = value + + @property + def kind(self): + return self._kind + @kind.setter + def kind(self, value): + self._kind = value diff --git a/Unit-01/04-flask-crud/templates/404.html b/Unit-01/04-flask-crud/templates/404.html new file mode 100644 index 0000000..f181f59 --- /dev/null +++ b/Unit-01/04-flask-crud/templates/404.html @@ -0,0 +1,7 @@ +{% extends"base.html" %} +{% block content %} +
+

Page not found

+

This is not the snack you are looking for

+
+{% endblock %} \ No newline at end of file diff --git a/Unit-01/04-flask-crud/templates/base.html b/Unit-01/04-flask-crud/templates/base.html new file mode 100644 index 0000000..c65e762 --- /dev/null +++ b/Unit-01/04-flask-crud/templates/base.html @@ -0,0 +1,19 @@ + + + + + Flask CRUD + + + + + + {% block content %} + {% endblock %} + + + \ No newline at end of file diff --git a/Unit-01/04-flask-crud/templates/edit.html b/Unit-01/04-flask-crud/templates/edit.html new file mode 100644 index 0000000..70675df --- /dev/null +++ b/Unit-01/04-flask-crud/templates/edit.html @@ -0,0 +1,17 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+ + +
+
+ + +
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/04-flask-crud/templates/index.html b/Unit-01/04-flask-crud/templates/index.html new file mode 100644 index 0000000..af3969e --- /dev/null +++ b/Unit-01/04-flask-crud/templates/index.html @@ -0,0 +1,12 @@ +{% extends"base.html" %} +{% block content %} +
+

Snacks

+
    + {% for snack in snacks %} +
  • {{snack.name}} {{snack.kind}}
  • + {% endfor %} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/04-flask-crud/templates/new.html b/Unit-01/04-flask-crud/templates/new.html new file mode 100644 index 0000000..b16a3cb --- /dev/null +++ b/Unit-01/04-flask-crud/templates/new.html @@ -0,0 +1,17 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+ + +
+
+ + +
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/04-flask-crud/templates/show.html b/Unit-01/04-flask-crud/templates/show.html new file mode 100644 index 0000000..2516a27 --- /dev/null +++ b/Unit-01/04-flask-crud/templates/show.html @@ -0,0 +1,18 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+

{{snack.name}}

+
snack
+

name: {{snack.name}}

+

kind: {{snack.kind}}

+
+ +
+
+
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/app.py b/Unit-01/06-sql-alchemy-1/app.py new file mode 100644 index 0000000..33bb166 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/app.py @@ -0,0 +1,79 @@ +from flask import Flask, render_template, url_for, redirect, request +from flask_modus import Modus +from flask_sqlalchemy import SQLAlchemy + +app=Flask(__name__) +modus=Modus(app) +app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/snacks-db' +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +db = SQLAlchemy(app) + +class Snack(db.Model): + __tablename__="snacks" + + id= db.Column(db.Integer, primary_key=True) + name = db.Column(db.Text) + kind = db.Column(db.Text) + rating = db.Column(db.Text) + + def __init__(self, name, kind, rating): + self.name = name + self.kind = kind + self.rating = rating + + def __repr__(self): + return "Name: {self.name}; Kind: {self.kind}; Rating: {self.rating}" + + + +@app.route("/snacks", methods=["GET", "POST"]) +def index(): + if request.method == "POST": + name = request.form.get('name') + kind = request.form.get('kind') + db.session.add(Snack(name, kind)) + db.session.commit() + return redirect(url_for('index')) + return render_template("index.html", snacks=Snack.query.order_by(Snack.id).all()) + +@app.route("/snacks/new") +def new(): + return render_template("new.html") + +@app.route("/snacks/", methods=["GET", "PATCH", "DELETE"]) +def show(id): + try: + individual_snack = Snack.query.get(id) + + if request.method == b"PATCH": + individual_snack.name = (request.form['name']) + individual_snack.kind = (request.form['kind']) + db.session.add(individual_snack) + db.session.commit() + + elif request.method == b"DELETE": + db.session.delete(individual_snack) + db.session.commit() + return redirect(url_for('index')) + + return render_template('show.html', snack = individual_snack) + except: + return redirect(url_for('not_found', id=id)) + +@app.route("/snacks//edit") +def edit(id): + try: + individual_snack = Snack.query.get(id) + return render_template('edit.html', snack=individual_snack) + except: + return redirect(url_for('not_found', id=id)) + + + +@app.route("/snacks//not-found") +def not_found(id): + return render_template('404.html') + +if __name__ == "__main__": + app.run(debug=True) + diff --git a/Unit-01/06-sql-alchemy-1/manage.py b/Unit-01/06-sql-alchemy-1/manage.py new file mode 100644 index 0000000..44041b8 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/manage.py @@ -0,0 +1,14 @@ +from app import app,db + +from flask_script import Manager + +from flask_migrate import Migrate, MigrateCommand + +migrate = Migrate(app, db) + +manager = Manager(app) + +manager.add_command('db', MigrateCommand) + +if __name__ == '__main__': + manager.run() \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/migrations/README b/Unit-01/06-sql-alchemy-1/migrations/README new file mode 100755 index 0000000..98e4f9c --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/migrations/alembic.ini b/Unit-01/06-sql-alchemy-1/migrations/alembic.ini new file mode 100644 index 0000000..f8ed480 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/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/Unit-01/06-sql-alchemy-1/migrations/env.py b/Unit-01/06-sql-alchemy-1/migrations/env.py new file mode 100755 index 0000000..23663ff --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/migrations/env.py @@ -0,0 +1,87 @@ +from __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig +import logging + +# 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 +from flask import current_app +config.set_main_option('sqlalchemy.url', + current_app.config.get('SQLALCHEMY_DATABASE_URI')) +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) + + 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.') + + engine = engine_from_config(config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + connection = engine.connect() + context.configure(connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args) + + try: + with context.begin_transaction(): + context.run_migrations() + finally: + connection.close() + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/Unit-01/06-sql-alchemy-1/migrations/script.py.mako b/Unit-01/06-sql-alchemy-1/migrations/script.py.mako new file mode 100755 index 0000000..2c01563 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/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/Unit-01/06-sql-alchemy-1/migrations/versions/11cf88327c38_creating_snack_table.py b/Unit-01/06-sql-alchemy-1/migrations/versions/11cf88327c38_creating_snack_table.py new file mode 100644 index 0000000..c0c9648 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/migrations/versions/11cf88327c38_creating_snack_table.py @@ -0,0 +1,33 @@ +"""creating snack table + +Revision ID: 11cf88327c38 +Revises: +Create Date: 2017-11-28 15:17:27.380354 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '11cf88327c38' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('snacks', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.Text(), nullable=True), + sa.Column('kind', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('snacks') + # ### end Alembic commands ### diff --git a/Unit-01/06-sql-alchemy-1/migrations/versions/144b49d42899_adding_rating_column.py b/Unit-01/06-sql-alchemy-1/migrations/versions/144b49d42899_adding_rating_column.py new file mode 100644 index 0000000..391bb08 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/migrations/versions/144b49d42899_adding_rating_column.py @@ -0,0 +1,28 @@ +"""adding rating column + +Revision ID: 144b49d42899 +Revises: 11cf88327c38 +Create Date: 2017-11-28 15:27:37.943533 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '144b49d42899' +down_revision = '11cf88327c38' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('snacks', sa.Column('rating', sa.Text(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('snacks', 'rating') + # ### end Alembic commands ### diff --git a/Unit-01/06-sql-alchemy-1/requirements.txt b/Unit-01/06-sql-alchemy-1/requirements.txt new file mode 100644 index 0000000..42e4c3c --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/requirements.txt @@ -0,0 +1,31 @@ +alembic==0.9.6 +appnope==0.1.0 +click==6.7 +decorator==4.1.2 +Flask==0.12.2 +Flask-Migrate==2.1.1 +Flask-Modus==0.0.1 +Flask-Script==2.0.6 +Flask-SQLAlchemy==2.3.2 +ipython==6.2.1 +ipython-genutils==0.2.0 +itsdangerous==0.24 +jedi==0.11.0 +Jinja2==2.10 +Mako==1.0.7 +MarkupSafe==1.0 +parso==0.1.0 +pexpect==4.3.0 +pickleshare==0.7.4 +prompt-toolkit==1.0.15 +psycopg2==2.7.3.2 +ptyprocess==0.5.2 +Pygments==2.2.0 +python-dateutil==2.6.1 +python-editor==1.0.3 +simplegeneric==0.8.1 +six==1.11.0 +SQLAlchemy==1.1.15 +traitlets==4.3.2 +wcwidth==0.1.7 +Werkzeug==0.12.2 diff --git a/Unit-01/06-sql-alchemy-1/templates/404.html b/Unit-01/06-sql-alchemy-1/templates/404.html new file mode 100644 index 0000000..f181f59 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/404.html @@ -0,0 +1,7 @@ +{% extends"base.html" %} +{% block content %} +
+

Page not found

+

This is not the snack you are looking for

+
+{% endblock %} \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/templates/base.html b/Unit-01/06-sql-alchemy-1/templates/base.html new file mode 100644 index 0000000..c65e762 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/base.html @@ -0,0 +1,19 @@ + + + + + Flask CRUD + + + + + + {% block content %} + {% endblock %} + + + \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/templates/edit.html b/Unit-01/06-sql-alchemy-1/templates/edit.html new file mode 100644 index 0000000..70675df --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/edit.html @@ -0,0 +1,17 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+ + +
+
+ + +
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/templates/index.html b/Unit-01/06-sql-alchemy-1/templates/index.html new file mode 100644 index 0000000..af3969e --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/index.html @@ -0,0 +1,12 @@ +{% extends"base.html" %} +{% block content %} +
+

Snacks

+
    + {% for snack in snacks %} +
  • {{snack.name}} {{snack.kind}}
  • + {% endfor %} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/templates/new.html b/Unit-01/06-sql-alchemy-1/templates/new.html new file mode 100644 index 0000000..b16a3cb --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/new.html @@ -0,0 +1,17 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+ + +
+
+ + +
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/Unit-01/06-sql-alchemy-1/templates/show.html b/Unit-01/06-sql-alchemy-1/templates/show.html new file mode 100644 index 0000000..2516a27 --- /dev/null +++ b/Unit-01/06-sql-alchemy-1/templates/show.html @@ -0,0 +1,18 @@ +{% extends"base.html" %} +{% block content %} +
+
+
+

{{snack.name}}

+
snack
+

name: {{snack.name}}

+

kind: {{snack.kind}}

+
+ +
+
+
+
+
+ +{% endblock %} \ No newline at end of file