What is SQLAlchemy
SQLAlchemy is the Python SQL toolkit and Object Relational Mapper that gives application developers the full power and flexibility of SQL.
Object Relational Mapper (ORM):
![Object Relational Mapping PowerPoint Template | SketchBubble](https://azatai.s3.amazonaws.com/2020-08-09-141522.png) |
It provides a full suite of well known enterprise-level persistence patterns, designed for efficient and high-performing database access, adapted into a simple and Pythonic domain language.
QLAlchemy considers the database to be a relational algebra engine, not just a collection of tables. Rows can be selected from not only tables but also joins and other select statements; any of these units can be composed into a larger structure. SQLAlchemy’s expression language builds on this concept from its core.
SQLAlchemy is most famous for its object-relational mapper (ORM), an optional component that provides the data mapper pattern, where classes can be mapped to the database in open ended, multiple ways - allowing the object model and database schema to develop in a cleanly decoupled way from the beginning.
The main goal of SQLAlchemy is to change the way you think about databases and SQL!
Overview
The SQLAlchemy SQL Toolkit and Object Relational Mapper is a comprehensive set of tools for working with databases and Python.
Above, the two most significant front-facing portions of SQLAlchemy are the Object Relational Mapper and theSQL Expression Language. SQL Expressions can be used independently of the ORM. When using the ORM, the SQL Expression language remains part of the public facing API as it is used within object-relational configurations and queries.
Object Relational Tutorial
The SQLAlchemy Object Relational Mapper presents a method of associating user-defined Python classes with database tables, and instances of those classes (objects) with rows in their corresponding tables. It includes a system that transparently synchronizes all changes in state between objects and their related rows, called a unit of work, as well as a system for expressing database queries in terms of the user defined classes and their defined relationships between each other.
The ORM is in contrast to the SQLAlchemy Expression Language, upon which the ORM is constructed. Whereas the SQL Expression Language, introduced in SQL Expression Language Tutorial, presents a system of representing the primitive constructs of the relational database directly without opinion, the ORM presents a high level and abstracted pattern of usage, which itself is an example of applied usage of the Expression Language.
contrast:
SQL Expression Language:
While there is overlap among the usage patterns of the ORM and the Expression Language, the similarities are more superficial than they may at first appear. One approaches the structure and content of data from the perspective of a user-defined domain model which is transparently persisted and refreshed from its underlying storage model. The other approaches it from the perspective of literal schema and SQL expression representations which are explicitly composed into messages consumed individually by the database.
Overlap:
domain model:
A domain model in problem solving and software engineering is a conceptual model of all the topics related to a specific problem. It describes the various entities, their attributes, roles, and relationships, plus the constraints that govern the problem domain.
A successful application may be constructed using the Object Relational Mapper exclusively. In advanced situations, an application constructed with the ORM may make occasional usage of the Expression Language directly in certain areas where specific database interactions are required.
The following tutorial is in doctest format, meaning each >>>
line represents something you can type at a Python command prompt, and the following text represents the expected return value.
Version Check
import sqlalchemy
sqlalchemy.__version__
Connecting
from sqlalchemy import create_engine
engine = create_engine('sqlite:///:memory:',echo=True)
The echo
flag is a shortcut to setting up SQLAlchemy logging, which is accomplished via Python’s standard logging
module. With it enabled, we’ll see all the generated SQL produced.
The return value of create_engine()
is an instance of Engine
, and it represents the core interface to the database, adapted through a dialect that handles the details of the database and DBAPI in use. In this case the SQLite dialect will interpret instructions to the Python built-in sqlite3
module.
database storage engines:
DBAPI :
The first time a method like Engine.execute()
or Engine.connect()
is called, the Engine
establishes a real DBAPI connection to the database, which is then used to emit the SQL. When using the ORM, we typically don’t use the Engine
directly once created; instead, it’s used behind the scenes by the ORM as we’ll see shortly.
Lazy Connecting
The
Engine
, when first returned bycreate_engine()
, has not actually tried to connect to the database yet; that happens only the first time it is asked to perform a task against the database.
Declare a Mapping
When using the ORM, the configurational process starts by describing the database tables we’ll be dealing with, and then by defining our own classes which will be mapped to those tables. In modern SQLAlchemy, these two tasks are usually performed together, using a system known as Declarative, which allows us to create classes that include directives to describe the actual database table they will be mapped to.
Configurational process :
- Describing the database
- Defining the class that will be mapped to the database tables.
Classes mapped using the Declarative system are defined in terms of a base class which maintains a catalog of classes and tables relative to that base - this is known as the declarative base class. Our application will usually have just one instance of this base in a commonly imported module. We create the base class using the declarative_base()
function, as follows:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
Now that we have a “base”, we can define any number of mapped classes in terms of it. We will start with just a single table called users
, which will store records for the end-users using our application. A new class called User
will be the class to which we map this table. Within the class, we define details about the table to which we’ll be mapping, primarily the table name, and names and datatypes of columns:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)
A class using Declarative at a minimum needs a __tablename__
attribute, and at least one Column
which is part of a primary key 1. SQLAlchemy never makes any assumptions by itself about the table to which a class refers, including that it has no built-in conventions for names, datatypes, or constraints. But this doesn’t mean boilerplate is required; instead, you’re encouraged to create your own automated conventions using helper functions and mixin classes, which is described in detail at Mixin and Custom Base Classes.
The
User
class defines a__repr__()
method, but note that is optional;
Mixin:
When our class is constructed, Declarative replaces all the Column
objects with special Python accessors known as descriptors; this is a process known as instrumentation. The “instrumented” mapped class will provide us with the means to refer to our table in a SQL context as well as to persist and load the values of columns from the database.
![Declarative Sentence (statement) | Grammar | EnglishClub](https://azatai.s3.amazonaws.com/2020-08-09-155850.png) |
![Instrumentation database architecture. | Download Scientific Diagram](https://azatai.s3.amazonaws.com/2020-08-09-160223.png) |
Outside of what the mapping process does to our class, the class remains otherwise mostly a normal Python class, to which we can define any number of ordinary attributes and methods needed by our application.
Further information posted here:
Sample Python Code:
import sqlalchemy as sa
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
engine = create_engine("postgresql://sqlalchemy:sqlalchemy@localhost/sqlalchemy", echo=True)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
addresses = relationship("Address", back_populates="user")
def __repr__(self):
return f"<User(name = {self.name},fullname={self.fullname}, nickname={self.nickname})>"
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", back_populates='addresses')
def __repr__(self):
return f"<Address(email_address={self.email_address})>"
Base.metadata.create_all(engine)
jack = User(name='jack', fullname='Jack bean', nickname='jk')
print(jack.addresses)
jack.addresses = [
Address(email_address='[email protected]'),
Address(email_address='[email protected]')
]
print(jack.addresses[1])
session.add(jack)
# session.commit()
for instance in session.query(User).order_by(User.id):
print(instance.addresses)
for u, a in session.query(User, Address).filter(User.id == Address.user_id).filter(
Address.email_address == '[email protected]').all():
print(u, a)
# session.commit()
session.delete(jack)
session.commit()
session.close()