test_flask.py - Unit tests for flask.py - Provide extensions for Flask-SQLAlchemy¶
This file provide working examples and tests for flask.py - Provide extensions for Flask-SQLAlchemy.
Imports¶
These are listed in the order prescribed by PEP 8.
Standard library¶
None
Third-party imports¶
from flask import Flask
from sqlalchemy.sql.expression import func
Local imports¶
from pythonic_sqlalchemy_query.flask import SQLAlchemyPythonicQuery
from util import print_query
Setup¶
Create a basic Flask-SQLAlchemy application.
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemyPythonicQuery(app)
Model¶
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
fullname = db.Column(db.String)
password = db.Column(db.String)
Define a default query which assumes the key is a User’s name if given a string.
@classmethod
def default_query(cls, key):
if isinstance(key, str):
return cls.name == key
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
class Address(db.Model):
__tablename__ = 'addresses'
id = db.Column(db.Integer, primary_key=True)
email_address = db.Column(db.String, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
user = db.relationship("User", back_populates="addresses")
Define a default query which assumes the key is an Address’s e-mail address.
@classmethod
def default_query(cls, key):
return cls.email_address == key
def __repr__(self):
return "<Address(email_address='%s')>" % self.email_address
User.addresses = db.relationship(
"Address", order_by=Address.id, back_populates="user")
Create all tables.
db.create_all()
Test data¶
jack = User(name='jack', fullname='Jack Bean', password='gjffdd')
jack.addresses = [
Address(email_address='jack@google.com'),
Address(email_address='j25@yahoo.com')]
db.session.add(jack)
db.session.commit()
Demonstration and unit tests¶
Traditional versus Pythonic¶
def test_traditional_versus_pythonic():
Create a query to select the Address for ‘jack@google.com’ from User ‘jack’.
The Pythonic version of a query:
pythonic_query = "User['jack'].addresses['jack@google.com']"
print_query(pythonic_query, [jack.addresses[0]], globals())
The traditional approach:
traditional_query = (
Ask for the Address…
"Address.query."
by querying a User named ‘jack’…
"select_from(User).filter(User.name == 'jack')."
then joining this to the Address ‘jack@google.com’.
"join(Address).filter(Address.email_address == 'jack@google.com')"
)
print_query(traditional_query, [jack.addresses[0]], globals())
Examples¶
def test_more_examples():
Ask for the full User object for jack.
print_query("User['jack']", [jack], globals())
Ask only for Jack’s full name.
print_query("User['jack'].fullname", [(jack.fullname, )], globals())
Get all of Jack’s addresses.
print_query("User['jack'].addresses", jack.addresses, globals())
Get just the email-address of all of Jack’s addresses.
print_query("User['jack'].addresses.email_address", [(x.email_address, ) for x in jack.addresses], globals())
Get just the email-address j25@yahoo.com of Jack’s addresses.
print_query("User['jack'].addresses['j25@yahoo.com']", [jack.addresses[1]], globals())
Ask for the full Address object for j25@yahoo.com.
print_query("Address['j25@yahoo.com']", [jack.addresses[1]], globals())
Ask for the User associated with this address.
print_query("Address['j25@yahoo.com'].user", [jack], globals())
Use a filter criterion to select a User with a full name of Jack Bean.
print_query("User[User.fullname == 'Jack Bean']", [jack], globals())
Use two filter criteria to find the user named jack with a full name of Jack Bean.
print_query("User['jack'][User.fullname == 'Jack Bean']", [jack], globals())
Look for the user with id 1.
print_query("User[1]", [jack], globals())
Use an SQL expression in the query.
print_query("User[func.lower(User.fullname) == 'jack bean']", [jack], globals())
Ask for everything in User. (This is built in to Flask-SQLAlchemy and isn’t a part of this package. However, this seems like the cleanest syntax to me.)
print_query("User.query", [jack], globals())
Another syntax for the everything in User. This does use functionality from this package.
print_query("db.session(User)", [jack], globals())
Ask for the name of all Users. Note that User.name
can’t be used in this case – this refers to the name
attribute of the User
class.
print_query("db.session(User).name", [(jack.name, )], globals())
Query using the session. A bit longer, but it produces the same results. For comparison:
print_query( " User['jack'].addresses['jack@google.com']", [jack.addresses[0]], globals())
print_query("db.session(User)['jack'].addresses['jack@google.com']", [jack.addresses[0]], globals())
main¶
Run the example code. This can also be tested using pytest.
if __name__ == '__main__':
test_traditional_versus_pythonic()
test_more_examples()