darkKnight
darkKnight

Reputation: 83

Integer range in Flask REST API using SQLAlchemy

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:

  1. Setting price value between 0 - 100
  2. Setting qty value between 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

Answers (2)

alim91
alim91

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

Klarner
Klarner

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

Related Questions