Reputation: 83
I am creating a REST API using Flask, SQLAlchemy, and Marshmallow. I have defined my Product Model in app.py
as:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
# Initialize App
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
# Database Setup
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Init db
db = SQLAlchemy(app)
# Init marshmallow
ma = Marshmallow(app)
# Product Class/Model
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def __init__(self, price, qty):
self.price = price
self.qty = qty
# Product Schema
class ProductSchema(ma.Schema):
class Meta:
fields = ('id', 'price', 'qty')
# Init Schema
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
# Create Product
@app.route('/product', methods=['POST'])
def add_product():
price = request.json['price']
qty = request.json['qty']
new_product = Product(price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
I have to perform the following logic:
0 - 100
0 - 100
If success return 200
, if anything wrong return 500
.
I am not able to set Integer value between the given range by db.Integer([0, 100])
as its giving me error:
TypeError: Integer() takes no arguments
How do I implement the above logic?
Upvotes: 0
Views: 2039
Reputation: 546
since you have installed marshmallow, install the marmallow-sqlalchemy and use SQLAlchemyAutoSchema feature which will allow to you to refer directly to the model and create an instance after successful load of the json object sent in request body, plus you can define your own constraints in the schema class. the marshmallow conf. will look like:
from marshmallow import ValidationError, fields
from marshmallow.validate import Range
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
ma = Marshmallow(app)
# to return marshmallow parsing error
@app.errorhandler(ValidationError)
def handle_marshmallow_validation(err):
print(err)
return jsonify(err.messages), 400
# Product Schema
class ProductSchema(ma.SQLAlchemyAutoSchema):
id = fields.Integer(required=False)
price = fields.Integer(required=True, validate=[Range(max=100, error="Value must be 100 or less")])
qty = fields.Integer(required=True, validate=[Range(max=100, error="Value must be 100 or less")])
class Meta:
model = Product
load_instance = True
now the ressource will look like:
# Create Product
@app.route('/product', methods=['POST'])
def add_product():
# here we can check the payload validity, parse it and transform it directly to instance
product_json = request.get_json()
new_product = product_schema.load(product_json)
db.session.add(new_product)
db.session.commit()
return product_schema.dump(new_product)
now if you sent value outside the range you will receive response like this
{
"price": [
"Value must be 100 or less"
],
"qty": [
"Value must be 100 or less"
]
}
Upvotes: 0
Reputation: 76
Edit: I've misunderstood the question and made a new function.
def ExpectedRange(var1):
return 200 if var1 in range(0,100) else 500
# Create Product
@app.route('/product', methods=['POST'])
def add_product():
price = request.json['price']
qty = request.json['qty']
if ExpectedRange(price) and ExpectedRange(qty) == 200:
new_product = Product(price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
#else:
# Show error. I recommend you using the method 'flash' in flask.
I think the problem with your code by using db.Integer([0, 100])
as a way to find the value between 0 and 100, instead, what you should be doing is by using range with the help of a method called randrange
from the library random
. With all due respect, I actually don't know what you are trying to accomplish, if I am wrong, please correct me in the comments and I'll correct my post.
What I recommend you doing is to not set the price and qty in the model class, but rather, in an entirely different function and using your model class to create the elements within your database. For example:
from random import randrange
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def ProductRange(range1, range2):
return randrange(range1, range2)
print(ProductRange(1,100))
What the function ProductRange
will do is to choose the range between the variable range1
and range2
. As for returning 200
and 500
, I am not sure what you could use with this value, but I recommend doing boolean. If it is needed, 200
and 500
is simply a constant, and you could easily implement it via putting it in a function rather than using the returned value to calculate things. So, how would you use the ProductRange
function? Just follow the code below.
from random import randrange
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
product_name = db.Column(db.String) # Ignore this line, this just for the /addpost route to get the method POST
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def ProductRange(range1, range2):
return randrange(range1, range2)
# This route is just an example of how you would use the function ProductRange
@app.route('/addpost', methods=['POST'])
def addpost():
product_name = request.form['product_name']
price = ProductRange(1,100)
qty = ProductRange(1,100)
post = Product[product_name=product_name, price=price, qty=qty]
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
If it doesn't work, please comment down below for me to help you further with this question of yours. I wish you good luck.
Upvotes: 1