Usar ORM ao invés de SQL bruto
This commit is contained in:
parent
ad5aa0d69e
commit
bbfddcae56
|
@ -0,0 +1,12 @@
|
|||
#!/bin/python3
|
||||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_marshmallow import Marshmallow
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('api.config')
|
||||
db = SQLAlchemy(app)
|
||||
ma = Marshmallow(app)
|
||||
|
||||
import api.models.trainer
|
||||
import api.routes.routes
|
|
@ -0,0 +1,2 @@
|
|||
SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db'
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
@ -0,0 +1,44 @@
|
|||
from api.app import db, ma
|
||||
from werkzeug.security import generate_password_hash
|
||||
from enum import Enum
|
||||
|
||||
teams = (
|
||||
"Team Valor",
|
||||
"Team Instinct",
|
||||
"Team Mystic"
|
||||
)
|
||||
|
||||
class InvalidTeam(Exception):
|
||||
pass
|
||||
|
||||
# modelo do Trainer para o SQLAlchemy
|
||||
class Trainer(db.Model):
|
||||
__tablename__ = "trainers"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
|
||||
nickname = db.Column(db.String(20), nullable=False, index=True)
|
||||
first_name = db.Column(db.String(30), nullable=False)
|
||||
last_name = db.Column(db.String(30), nullable=False)
|
||||
email = db.Column(db.String(60), unique=True, nullable=False)
|
||||
password = db.Column(db.String(200), nullable=False)
|
||||
team = db.Column(db.String(10), nullable=False)
|
||||
pokemons_owned = db.Column(db.Integer, default=0)
|
||||
|
||||
def __init__(self, nickname, first_name, last_name, email, password, team):
|
||||
if team not in teams:
|
||||
raise InvalidTeam()
|
||||
self.nickname = nickname
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.email = email
|
||||
self.password = generate_password_hash(password)
|
||||
self.team = team
|
||||
|
||||
|
||||
# schema do Marshmallow
|
||||
class TrainerSchema(ma.Schema):
|
||||
class Meta:
|
||||
fields = ('id', 'nickname', 'first_name', 'last_name', 'email', 'team', 'pokemons_owned')
|
||||
|
||||
trainer_schema = TrainerSchema()
|
||||
trainer_schemas = TrainerSchema(many=True)
|
|
@ -0,0 +1,12 @@
|
|||
from flask import request
|
||||
from sqlite3 import ProgrammingError, IntegrityError
|
||||
from api.app import app, db
|
||||
from api.views import trainer
|
||||
|
||||
@app.route('/trainer', methods=['GET'])
|
||||
def route_get_trainers():
|
||||
return trainer.get_trainers()
|
||||
|
||||
@app.route('/trainer', methods=['POST'])
|
||||
def route_create_trainer():
|
||||
return trainer.post_trainer()
|
|
@ -0,0 +1,80 @@
|
|||
from sqlalchemy.exc import NoResultFound, IntegrityError
|
||||
from api.models.trainer import Trainer, trainer_schema, trainer_schemas, InvalidTeam
|
||||
from api.app import db
|
||||
from flask import request, jsonify
|
||||
|
||||
# função auxiliar
|
||||
def error(code, type, message, http_code=400):
|
||||
return ({
|
||||
"code": code,
|
||||
"type": type,
|
||||
"message": message
|
||||
}, http_code)
|
||||
|
||||
def get_trainers():
|
||||
args = request.args
|
||||
|
||||
try:
|
||||
limit = int(args.get("limit", -1))
|
||||
offset = int(args.get("offset", 0))
|
||||
except ValueError:
|
||||
return error(0, "ParsingError", "Couldn't parse parameter as integer")
|
||||
|
||||
if limit < -1 or offset < 0:
|
||||
return error(1, "ParsingError", "Expected positive integer as parameter")
|
||||
|
||||
nickname = args.get("nickname", "")
|
||||
nickname_contains = args.get("nickname_contains", "")
|
||||
|
||||
try:
|
||||
if nickname:
|
||||
if nickname_contains:
|
||||
return error(2, "ConflictingParameters", "nickname and nickname_contains are mutually exclusive")
|
||||
|
||||
query = Trainer.query.filter_by(nickname=nickname)
|
||||
return trainer_schemas.dumps(query.all())
|
||||
|
||||
else: # se nickname_contains também está vazio, retornará todos trainers
|
||||
pattern = '%'+nickname_contains+'%'
|
||||
query = Trainer.query.filter(Trainer.nickname.like(pattern))
|
||||
return trainer_schemas.dumps(query.all())
|
||||
|
||||
except NoResultFound:
|
||||
return jsonify([])
|
||||
|
||||
def post_trainer():
|
||||
try:
|
||||
json = request.get_json()
|
||||
except:
|
||||
return error(3, "ParsingError", "Failed to parse JSON content")
|
||||
|
||||
if type(json) is not dict:
|
||||
return error(4, "ParsingError", "Expected JSON object as content")
|
||||
|
||||
try:
|
||||
nickname = json["nickname"]
|
||||
first_name = json["first_name"]
|
||||
last_name = json["last_name"]
|
||||
email = json["email"]
|
||||
password = json["password"]
|
||||
team = json["team"]
|
||||
|
||||
trainer = Trainer(
|
||||
nickname=nickname,
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
email=email,
|
||||
password=password,
|
||||
team=team
|
||||
)
|
||||
|
||||
db.session.add(trainer)
|
||||
db.session.commit()
|
||||
|
||||
return trainer_schema.dump(trainer)
|
||||
except InvalidTeam:
|
||||
return error(5, "ParsingError", "Field team is invalid")
|
||||
except KeyError:
|
||||
return error(6, "ParsingError", "Missing JSON object fields")
|
||||
except IntegrityError:
|
||||
return error(7, "ConflictingResource", "Trainer with the same nickname or email already exists", http_code=500)
|
|
@ -1,7 +0,0 @@
|
|||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.debug = True
|
||||
|
||||
from .routes import routes
|
|
@ -1,55 +0,0 @@
|
|||
from .trainer import Trainer
|
||||
import sqlite3
|
||||
|
||||
class Database:
|
||||
def __init__(self, db_file):
|
||||
self.db_file = db_file
|
||||
|
||||
def create_trainers_table(self):
|
||||
con = sqlite3.connect(self.db_file)
|
||||
|
||||
con.execute("""
|
||||
CREATE TABLE IF NOT EXISTS Trainers
|
||||
(
|
||||
id INT UNSIGNED UNIQUE,
|
||||
nickname TINYTEXT PRIMARY KEY,
|
||||
first_name TINYTEXT,
|
||||
last_name TINYTEXT,
|
||||
email TINYTEXT,
|
||||
password TINYTEXT,
|
||||
team TINYTEXT,
|
||||
pokemons_owned INT UNSIGNED
|
||||
)
|
||||
""")
|
||||
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
def __get_trainers(self, sql):
|
||||
con = sqlite3.connect(self.db_file)
|
||||
trainers = []
|
||||
for row in con.execute(*sql):
|
||||
trainers.append(Trainer(*row).__dict__)
|
||||
con.close()
|
||||
return trainers
|
||||
|
||||
def get_trainer_by_nickname(self, nickname, limit, offset):
|
||||
return self.__get_trainers(("SELECT * FROM Trainers WHERE nickname = ? LIMIT ? OFFSET ?", (nickname, limit, offset)))
|
||||
|
||||
def get_trainers_by_nickname_contains(self, contains, limit, offset):
|
||||
return self.__get_trainers(("SELECT * FROM Trainers WHERE nickname LIKE ? LIMIT ? OFFSET ?", ("%" + contains + "%", limit, offset)))
|
||||
|
||||
def insert_trainer(self, trainer):
|
||||
con = sqlite3.connect(self.db_file)
|
||||
|
||||
con.execute("INSERT INTO Trainers VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(trainer.id, trainer.nickname,
|
||||
trainer.first_name, trainer.last_name,
|
||||
trainer.email, trainer.password,
|
||||
trainer.team, trainer.pokemons_owned)
|
||||
)
|
||||
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
db = Database("database.db")
|
|
@ -1,39 +0,0 @@
|
|||
from flask import request, jsonify
|
||||
from app import app
|
||||
from app.database import db
|
||||
|
||||
@app.route('/trainer', methods=['GET'])
|
||||
def route_get_trainers():
|
||||
args = request.args
|
||||
|
||||
try:
|
||||
limit = int(args.get("limit", -1))
|
||||
offset = int(args.get("offset", 0))
|
||||
except ValueError:
|
||||
return {
|
||||
"code": 1,
|
||||
"type": "Integer parsing error",
|
||||
"message": "Couldn't parse parameter as integer"
|
||||
}, 500
|
||||
|
||||
if limit < -1 or offset < 0:
|
||||
return {
|
||||
"code": 2,
|
||||
"type": "Integer parsing error",
|
||||
"message": "Expected positive integer as parameter"
|
||||
}, 500
|
||||
|
||||
nickname = args.get("nickname", "")
|
||||
nickname_contains = args.get("nickname_contains", "")
|
||||
|
||||
if nickname and nickname_contains:
|
||||
return {
|
||||
"code": 3,
|
||||
"type": "Invalid parameter",
|
||||
"message": "Parameters \"nickname\" and \"nickname_contains\" are mutually exclusive"
|
||||
}, 500
|
||||
|
||||
if nickname:
|
||||
return jsonify(db.get_trainer_by_nickname(nickname, limit, offset))
|
||||
else:
|
||||
return jsonify(db.get_trainers_by_nickname_contains(nickname_contains, limit, offset))
|
|
@ -1,18 +0,0 @@
|
|||
class Trainer:
|
||||
def __init__(self,
|
||||
id,
|
||||
nickname,
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
password,
|
||||
team,
|
||||
pokemons_owned):
|
||||
self.id = id
|
||||
self.nickname = nickname
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.email = email
|
||||
self.password = password
|
||||
self.team = team
|
||||
self.pokemons_owned = pokemons_owned
|
|
@ -1,5 +1,3 @@
|
|||
#!/bin/python3
|
||||
from app.database import db
|
||||
from app.trainer import Trainer
|
||||
|
||||
db.create_trainers_table()
|
||||
from api.app import db
|
||||
db.create_all()
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
flask_marshmallow==0.14.0
|
||||
Flask_SQLAlchemy==2.5.1
|
||||
Werkzeug==2.0.2
|
||||
Flask==2.0.2
|
||||
SQLAlchemy==1.4.25
|
||||
|
|
Loading…
Reference in New Issue