PK!2dmelpo_api/__init__.py"""This is Melpo, version 0.0.1 init file.""" from flask import Flask, jsonify from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from flask_migrate import Migrate import os CONFIG = { 'DEBUG': True, 'ENV': 'development' } # init app app = Flask(__name__) app.config.from_mapping(**CONFIG) basedir = os.path.abspath(os.path.dirname(__file__)) # database config app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, '..', 'db.sqlite3') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # init db db = SQLAlchemy(app) # init migration engine migrate = Migrate(app, db) # init ma ma = Marshmallow(app) # index view @app.route("/") def index(): return "This is Melpo Flask Backend!" # json 404 view @app.errorhandler(404) def not_found(error): return jsonify({"error": str(error)}), 404 # register api # import here to avoid import conflict from .api import api app.register_blueprint(api) PK!κ ;melpo_api/__main__.py"""This is Melpo, version 0.0.1 main module file.""" from melpo_api import app if __name__ == '__main__': app.run(port=8000) PK!W melpo_api/api.pyfrom flask import Blueprint, request, jsonify, abort, Response from flask.views import MethodView from . import db from .models import Artist, Album, Song from .models import artist_schema, artists_schema, album_schema, albums_schema, song_schema, songs_schema api = Blueprint("api", __name__) @api.route("/") def index(): return "This is Melpo API's index." class BaseAPI(MethodView): """Base view for listing and posting instances of the given model. Derive this view to use it and give it your model. It will look for _schema object and use it as its schema (you must import it if it is not defined in the current module). Otherwise you can assign the schema object to schema variable. """ model = None # assign a model in derived view schema = None # optionally assign a schema in derived view schema_many = None # optionally assign a schema in derived view def __init__(self): if not self.schema: self.init_schema() if not self.schema_many: self.init_schema(many=True) def init_schema(self, many: bool = False): name = "schema_many" if many else "schema" schema_name = f"{self.model.__name__.lower()}" + ("s" if many else "") + "_schema" if schema_name in globals(): setattr(self, name, eval(schema_name)) else: raise AttributeError( f"You must provide a schema as {schema_name} was not found." ) def get(self, id): if not id: instances = self.model.query.all() return self.schema_many.jsonify(instances) else: instance = self.model.query.get_or_404(id) return self.schema.jsonify(instance) def post(self): try: deserialized_result = self.schema.load(request.json) db.session.add(deserialized_result.data) db.session.commit() except Exception as err: print(type(err), err) abort(400) return self.schema.jsonify(deserialized_result.data), 204 def patch(self, id): instance_to_patch = self.model.query.get_or_404(id) for name, value in request.json.items(): setattr(instance_to_patch, name, value) db.session.add(instance_to_patch) db.session.commit() return self.schema.jsonify(instance_to_patch) def delete(self, id): instance_to_delete = self.model.query.get_or_404(id) db.session.delete(instance_to_delete) db.session.commit() return jsonify({"success": f"<{self.model.__name__}: {id}> has been deleted from database."}) class ArtistAPI(BaseAPI): model = Artist class AlbumAPI(BaseAPI): model = Album class SongAPI(BaseAPI): model = Song # func from Flask docs to refactor def register_api(view, endpoint, url, pk='id', pk_type='int'): view_func = view.as_view(endpoint) api.add_url_rule(url, defaults={pk: None}, view_func=view_func, methods=['GET',]) api.add_url_rule(url, view_func=view_func, methods=['POST',]) api.add_url_rule('%s<%s:%s>' % (url, pk_type, pk), view_func=view_func, methods=['GET', 'PATCH', 'DELETE']) register_api(ArtistAPI, 'artist_api', '/artistes/') register_api(AlbumAPI, 'album_api', '/albums/') register_api(SongAPI, 'song_api', '/titres/') # Erreurs @api.errorhandler(400) def bad_request(error): return jsonify({"error": str(error)}), 400 PK!@melpo_api/models.pyfrom . import db from . import ma from marshmallow import fields, post_load # Modèles class Artist(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), unique=True, nullable=False) bio = db.Column(db.Text(200)) def __repr__(self): return f"Artist(name={self.name}, bio={self.bio})" def __str__(self): return self.name class Album(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), nullable=False) year = db.Column(db.Integer) artist_id = db.Column(db.Integer, db.ForeignKey("artist.id"), nullable=False) artist = db.relationship("Artist", backref=db.backref("albums", lazy=True)) def __repr__(self): return f"Album(name={self.name}, artist={self.artist}, year={self.year})" def __str__(self): return self.name class Song(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(256)) album_id = db.Column(db.Integer, db.ForeignKey("album.id"), nullable=False) album = db.relationship("Album", backref=db.backref("songs", lazy=True)) @property def artist(self): return self.album.artist @property def year(self): return self.album.year def __repr__(self): return f"Song(name={self.name}, album={repr(self.album)})" def __str__(self): return self.name class ArtistSchema(ma.ModelSchema): class Meta: model = Artist class AlbumSchema(ma.ModelSchema): artist = fields.String() class Meta: model = Album class SongSchema(ma.ModelSchema): year = fields.Integer() artist = fields.String() album = fields.String() class Meta: model = Song # init schema artist_schema = ArtistSchema(strict=True) artists_schema = ArtistSchema(many=True, strict=True) album_schema = AlbumSchema(strict=True) albums_schema = AlbumSchema(many=True, strict=True) song_schema = SongSchema(strict=True) songs_schema = SongSchema(many=True, strict=True) PK!HڽTU%melpo_api-0.0.2.post1.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HN(melpo_api-0.0.2.post1.dist-info/METADATASQk0~ׯ8j+v\0iYhYVv!m2[l~gH)|w}wt^‹Z'u˜NTBPɎɈG|̍v>fMU ۦ0[ހCu]{kug]ahDAƥQ!}٬ynQI7{̰v/a£3۽#5Y@jnf/8JHBHDS!߈Vi3ز>5Ң -X s+"wr#@c.=kBY+ѻ%|h /?"\kMOR:Ao{aDcV!?mΨ;6ZS$ Ds~PK!HJ÷V&melpo_api-0.0.2.post1.dist-info/RECORD;@߂-@@ d<]Y_6&\e1$_&M&!W!y27A{Vc XEw,Q"R;@y>)GX?=taAd;j0'b`68wW ^#̜cue(Ij4p(M]&D5Ë@Aeႌ.n!XB->mx-vn+u%1,U{Nr,cf9yLRBSwưs n^kuLshe"phpcW}ES|{2~-CCbV;litAW0?PK!2dmelpo_api/__init__.pyPK!κ ;melpo_api/__main__.pyPK!W melpo_api/api.pyPK!@melpo_api/models.pyPK!HڽTU%melpo_api-0.0.2.post1.dist-info/WHEELPK!HN(qmelpo_api-0.0.2.post1.dist-info/METADATAPK!HJ÷V&melpo_api-0.0.2.post1.dist-info/RECORDPKQ