The interest of SqlAlchemy is so appealing that I decided to explore this approach with more consideration. With SqlAlchemy, you can make really advanced thing still while having the hand over the underlaying database. With SqlAlchemy, the ORM doesn't make decision for you... it is a tool, not a wizard.
If you did not yet have a look to the "Introduction to SqlAlchemy" YouTube Video (Mike Bayer, PyCon US 2013) I strongly encourage you to do so.
Hand Coded Applications with SQLAlchemy
While looking at the "SqlAlchemy Introduction" video, YouTube proposed me to view the "Hand Coded Applications with SQLAlchemy".
Behind this "strange video name", I did discover very pertinent information about "Polymorphic association" that I'm already using in my own databases. So, this new video should also be seen!
Source: Hand Coded Applications with SQLAlchemy (YouTube)
What's an Hand Coded Application and what's not?
The hand coded approach means:
- That we makes decisions
- We implement and automate those decision with tools.
- We retain control over the architecture
- We are best off when we design and control the database schema/query as well as our own object model and how the object model does interact with the database schema.
- We still need tool to help us day-by-day in automating our development process.
- Hand Coded = explicit decision + automation with tools.
- when we use tools that make schema design decision for us,
- when we use tools that hides the database schema and geometry
- when we use tools that give us a "pass" to comply to ACID.
Sometime, the best solution is not to be ACID compliant.
ACID should be the reference in any case... but we should be able to desobey (and follow our own design decision) - when we use tools that control the architecture of our software.
We give up the control of our architecture dans our software design to a third party software.
- Application written by "wizards"
- Application that heavily rely on third party applications or Plug-ins.
- Using API that makes implementation decision
When some critical development decisions are rules by an API, your are in the same situation than a "Wizards" created APP. Trouble will comes when you will need to change the API'ed software part.
- We do not use library
We should use them as much as possible to simplify the work.
Choose a stable, popular, well documented, well support library would be a good choice. - We don't use Framework
Framework are great if they don't make the things harder. - We don't use defaults.
Defaults are the results of past experiences. relying on experience is wiser when starting a new project.
All those points (coming from the SqlAlchemy video) are in mind of the Audacious Project.
This means that Audacious will be a "Hand Coded Application" and also that SqlAlchemy may be a good tool to help the project.
Polymorphic Association Pattern
A polymorphic association happens when the data of a table (or a list of object) have a one of many possible parent (record/object).
Polymorphic Association explained
In an inventory, you may have many inventory variation details for a given article.
Those details explains how many pieces has been added/removed for this given article, when and with a reference to the data that caused the inventory variation (let's call it "origin").
When pieces are removed from inventory, it is usually to server an order... so the "inventory variation" record will be attached to a "send note" (the origin of inventory variation is a send note).
But when the supplier deliver the product, we are refilling the inventory for that same article. So, the inventory variation will be positive and "inventory variation" will be attached to a "Sypply delivery Note" (this time, origin of inventory variation is another object / record of another table).
So allow those both usecase to cohabit, we do use the Polymorphic Association. The Inventory Variation receive an additional field named Origin_Type with allows you to identify the kind of parent (say "SUP" for supplier... so a Supplier Note and "SNO" for an order's Send Note).
The Origin field will then point-out the data corresponding in the appropriate table/object list
Polymorphic Association Excerpt
Here some excerpt coming from the YouTube video. This sample is based on FinancialTransaction that may be attached (may reference) either a BankAccount either a PortfolioAsset
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
- It add a "magic_" table in the schema
- There is some python code in the database (the module name and the class name)
- The storage of transaction record is made into a monolothic table... as opposed to one table per class.
- The constraint to portfolio and bank_account must be handled by the application layer (database cannot handle a conditional foreign to one table or another table depending on condition) --> it is not a very good implementation option.
- SQLAlchemy will encourage us to specify how the tables are designed and explicitely mapped to the classes.
- SqlAlchemy will encourage us to use regular python technique to elaborate composable patterns.
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
- Take care to give a __tablename__ derived from the class name (CamelCase --will becode--> camel_case)
- Associate/create an unique identifier "id" column to the class (if not done).
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
It is the base of a transaction which contains money.
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
- We use Type to create a typed object with our convention (eg:BankAccountTransaction)
which inherit from Base and TransactionBase (so have money information) - associate with a table name for storing the transation
- and having a parent_id to the parent row while using ForeignKey constraint
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
- bank_account
- portfolio_asset
- bank_account_transaction (with foreign-key to bank_account)
- portfolio_asset_transaction (with foreign-key to portfolio_asset)
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
That recipe is:
- Very elegant... totaly pythonic
- Normalized and Allows foreign key constraint
- Can easily been reused for any polymorphic Association
- Can be used with other model as well.
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
SQL Geometry inside SqlAlchemy
Now, if we want a "report of average balance per month across all accounts", we will have to use subqueries and/or window function to produce balances as sum of amounts.
If we have millions rows, we should take care about the database querying and the sql statement.
You cannot figure to load the data in memory and process it to generate the report.
Here to deal in between SqlAchemy and Sql Statement.
Start with a query that extract all the start/end dates of each month in the bank_account_transaction table
Source: Hand Coded Applications with SQLAlchemy (YouTube) |
Hand Coded Applications with SQLAlchemy (YouTube) |
Article to be continued.....