{ "cells": [ { "cell_type": "markdown", "id": "8d981972-51c1-4f44-98fb-47abefacffb7", "metadata": { "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "# SQLAlchemy\n", "\n", "Simeon Simeonov @ Statnett\n", "\n", "\n", "## Agenda\n", "\n", "- Design & overview\n", "\n", "- A small practical example\n" ] }, { "cell_type": "markdown", "id": "19d6fced-434e-4604-bcb7-b71fadfe6dcb", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What is SQLAlchemy?\n", "\n", "SQLAlchemy is a Python library created by Mike Bayer to provide a high-level Pythonic interface to RDBMS such as PostgreSQL, SQLite, MySQL, Oracle, DB2.\n", "\n", "SQLAlchemy includes RDBMS-independent SQL expression language and an object-relational mapper (ORM).\n" ] }, { "cell_type": "markdown", "id": "fa5ad88f-d2ec-4d86-9982-73f7b9fe0e9b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Why use SQLAlchemy?\n", "\n", "- free software - free as in \"freedom\" (MIT licensed)\n", "\n", "- portability - the programming interface is independent of the type of RDBMS and connector used\n", "\n", "- security - no more SQL injections\n", "\n", "- abstraction - no need to bother with complex JOINs\n", "\n", "- object-orientation - you work with objects instead of tables and rows\n", "\n", "- performance - exploits the likehood of reusing a particular query\n", "\n", "- flexibility - you can override almost anything\n" ] }, { "cell_type": "markdown", "id": "d68798f0-de17-44f9-b677-d7ee06409a9c", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Basic architecture\n", "\n", "- Engine- manages the connection pool and the RDBMS-independent SQL dialect layer\n", "\n", "- MetaData - used to collect and organize information about your table layout (schema)\n", "\n", "- SQL expression language - provides an API to execute your queries and updates against your tables, all from Python, and all in a database-independent way (low-level interface)\n", "\n", "- ORM - provides a convenient way to add database persistence to your Python objects without requiring you to design your objects around the database, or the database around the objects (high-level interface)\n", "\n", "- Session - establishes all conversations with the RDBMS and represents a \"holding zone\" for all the objects which you've loaded or associated with it during its lifespan\n", "\n", "![title](images/sqla_arch.png)" ] }, { "cell_type": "code", "execution_count": 12, "id": "d1ea9f51-e3de-45a8-8302-b4a89b5d1689", "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "from sqlalchemy import create_engine\n", "\n", "# engine = create_engine(\"postgresql+psycopg2://user:zipassword@localhost/mydb\" , echo=True)\n", "# The string form of the URL is dialect+driver://user:password@host/d[?key=valuebname..],\n", "# where dialect is a database name such as mysql, oracle, postgresql, etc.,\n", "# and driver the name of a DBAPI, such as psycopg2, pyodbc, cx_oracle\n", "# The echo flag is a shortcut to setting up SQLAlchemy logging,\n", "# which is accomplished via Python’s standard logging module.\n", "\n", "# engine = create_engine(\"sqlite:///library.db\", echo=True)\n", "engine = create_engine(\"sqlite:///:memory:\", echo=True)" ] }, { "cell_type": "code", "execution_count": 13, "id": "3b4a777d-7d38-4149-8ab2-c876e2533766", "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2022-09-20 15:40:36,125 INFO sqlalchemy.engine.Engine BEGIN (implicit)\n", "2022-09-20 15:40:36,126 INFO sqlalchemy.engine.Engine PRAGMA main.table_info(\"production_types\")\n", "2022-09-20 15:40:36,126 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,127 INFO sqlalchemy.engine.Engine PRAGMA temp.table_info(\"production_types\")\n", "2022-09-20 15:40:36,128 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,129 INFO sqlalchemy.engine.Engine PRAGMA main.table_info(\"bidding_areas\")\n", "2022-09-20 15:40:36,129 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,130 INFO sqlalchemy.engine.Engine PRAGMA temp.table_info(\"bidding_areas\")\n", "2022-09-20 15:40:36,131 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,132 INFO sqlalchemy.engine.Engine PRAGMA main.table_info(\"production_plans\")\n", "2022-09-20 15:40:36,132 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,133 INFO sqlalchemy.engine.Engine PRAGMA temp.table_info(\"production_plans\")\n", "2022-09-20 15:40:36,134 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,136 INFO sqlalchemy.engine.Engine \n", "CREATE TABLE production_types (\n", "\tproduction_type_id INTEGER NOT NULL, \n", "\tcode VARCHAR(3) NOT NULL, \n", "\tdescription VARCHAR, \n", "\tPRIMARY KEY (production_type_id), \n", "\tUNIQUE (code)\n", ")\n", "\n", "\n", "2022-09-20 15:40:36,137 INFO sqlalchemy.engine.Engine [no key 0.00055s] ()\n", "2022-09-20 15:40:36,138 INFO sqlalchemy.engine.Engine \n", "CREATE TABLE bidding_areas (\n", "\tbidding_area_id INTEGER NOT NULL, \n", "\tcode VARCHAR(3) NOT NULL, \n", "\tname VARCHAR(32), \n", "\tPRIMARY KEY (bidding_area_id), \n", "\tUNIQUE (code)\n", ")\n", "\n", "\n", "2022-09-20 15:40:36,138 INFO sqlalchemy.engine.Engine [no key 0.00049s] ()\n", "2022-09-20 15:40:36,140 INFO sqlalchemy.engine.Engine \n", "CREATE TABLE production_plans (\n", "\trecord_created_time DATETIME NOT NULL, \n", "\tstart_time DATETIME NOT NULL, \n", "\tbidding_area_id INTEGER NOT NULL, \n", "\tproduction_type_id INTEGER NOT NULL, \n", "\tvalue NUMERIC NOT NULL, \n", "\tPRIMARY KEY (record_created_time, start_time, bidding_area_id, production_type_id), \n", "\tFOREIGN KEY(bidding_area_id) REFERENCES bidding_areas (bidding_area_id), \n", "\tFOREIGN KEY(production_type_id) REFERENCES production_types (production_type_id)\n", ")\n", "\n", "\n", "2022-09-20 15:40:36,141 INFO sqlalchemy.engine.Engine [no key 0.00068s] ()\n", "2022-09-20 15:40:36,142 INFO sqlalchemy.engine.Engine COMMIT\n" ] } ], "source": [ "from sqlalchemy import Column, Table\n", "from sqlalchemy import DateTime, ForeignKey, Integer, Numeric, String\n", "from sqlalchemy.orm import relationship\n", "\n", "from sqlalchemy.ext.declarative import declarative_base\n", "\n", "Base = declarative_base()\n", "\n", "\n", "class ProductionType(Base):\n", " __tablename__ = \"production_types\"\n", "\n", " production_type_id = Column(Integer, primary_key=True)\n", " code = Column(String(3), nullable=False, unique=True)\n", " description = Column(String)\n", "\n", " production_plans = relationship(\n", " \"ProductionPlan\", back_populates=\"production_type\", lazy=\"dynamic\"\n", " )\n", "\n", " def __init__(self, code, description):\n", " self.code = code\n", " self.description = description\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return self.code\n", "\n", "\n", "class BiddingArea(Base):\n", " __tablename__ = \"bidding_areas\"\n", "\n", " bidding_area_id = Column(Integer, primary_key=True)\n", " code = Column(String(3), nullable=False, unique=True)\n", " name = Column(String(32))\n", "\n", " production_plans = relationship(\n", " \"ProductionPlan\", back_populates=\"bidding_area\", lazy=\"dynamic\"\n", " )\n", "\n", " def __init__(self, code, name):\n", " self.code = code\n", " self.name = name\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return self.code\n", "\n", "\n", "class ProductionPlan(Base):\n", " __tablename__ = \"production_plans\"\n", "\n", " record_created_time = Column(DateTime(timezone=False), primary_key=True)\n", " start_time = Column(DateTime(timezone=False), primary_key=True)\n", " bidding_area_id = Column(Integer, ForeignKey(\"bidding_areas.bidding_area_id\"), primary_key=True)\n", " production_type_id = Column(Integer, ForeignKey(\"production_types.production_type_id\"), primary_key=True)\n", " value = Column(Numeric, nullable=False)\n", "\n", " # defining relationships.\n", " # the defined attributes will reference 'ProductionType' and 'BiddingArea' objects\n", " production_type = relationship(ProductionType, back_populates=\"production_plans\")\n", " bidding_area = relationship(BiddingArea, back_populates=\"production_plans\")\n", "\n", " def __init__(self, record_created_time, start_time, production_type, bidding_area, value):\n", " self.record_created_time = record_created_time\n", " self.start_time = start_time\n", " self.production_type = production_type # a 'ProductionType' object\n", " self.bidding_area = bidding_area # a 'BiddingArea' object\n", " self.value = value\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return (\n", " f\"{self.record_created_time} {self.start_time} \"\n", " f\"{self.production_type} {self.bidding_area} {self.value}\"\n", " )\n", "\n", "Base.metadata.create_all(engine) # create tables\n" ] }, { "cell_type": "markdown", "id": "ab7e9561-2780-4d85-843c-b217d15ee4c8", "metadata": {}, "source": [ "# Reflection\n", "\n", "*Table* object can be instructed to load information about itself from the corresponding database schema object already existing within the database.\n", "This process is called *reflection*.\n", "\n", "If the DB schema is already defined and maintained \"somewhere else\", it may be useful to \"reflect\" the schema instead of explicitly defining it." ] }, { "cell_type": "code", "execution_count": 14, "id": "70b0c5fa-35ae-44b5-b57b-2fa21b4f7da5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2022-09-20 15:40:36,151 INFO sqlalchemy.engine.Engine PRAGMA main.table_xinfo(\"production_types\")\n", "2022-09-20 15:40:36,152 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,153 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,153 INFO sqlalchemy.engine.Engine [raw sql] ('production_types',)\n", "2022-09-20 15:40:36,155 INFO sqlalchemy.engine.Engine PRAGMA main.foreign_key_list(\"production_types\")\n", "2022-09-20 15:40:36,156 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,157 INFO sqlalchemy.engine.Engine PRAGMA temp.foreign_key_list(\"production_types\")\n", "2022-09-20 15:40:36,158 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,160 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,160 INFO sqlalchemy.engine.Engine [raw sql] ('production_types',)\n", "2022-09-20 15:40:36,161 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"production_types\")\n", "2022-09-20 15:40:36,162 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,163 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"production_types\")\n", "2022-09-20 15:40:36,164 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,165 INFO sqlalchemy.engine.Engine PRAGMA main.index_info(\"sqlite_autoindex_production_types_1\")\n", "2022-09-20 15:40:36,166 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,168 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,169 INFO sqlalchemy.engine.Engine [raw sql] ('production_types',)\n", "2022-09-20 15:40:36,171 INFO sqlalchemy.engine.Engine PRAGMA main.table_xinfo(\"bidding_areas\")\n", "2022-09-20 15:40:36,172 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,173 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,174 INFO sqlalchemy.engine.Engine [raw sql] ('bidding_areas',)\n", "2022-09-20 15:40:36,175 INFO sqlalchemy.engine.Engine PRAGMA main.foreign_key_list(\"bidding_areas\")\n", "2022-09-20 15:40:36,176 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,176 INFO sqlalchemy.engine.Engine PRAGMA temp.foreign_key_list(\"bidding_areas\")\n", "2022-09-20 15:40:36,177 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,179 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,179 INFO sqlalchemy.engine.Engine [raw sql] ('bidding_areas',)\n", "2022-09-20 15:40:36,181 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"bidding_areas\")\n", "2022-09-20 15:40:36,181 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,182 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"bidding_areas\")\n", "2022-09-20 15:40:36,183 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,184 INFO sqlalchemy.engine.Engine PRAGMA main.index_info(\"sqlite_autoindex_bidding_areas_1\")\n", "2022-09-20 15:40:36,185 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,186 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,186 INFO sqlalchemy.engine.Engine [raw sql] ('bidding_areas',)\n", "2022-09-20 15:40:36,189 INFO sqlalchemy.engine.Engine PRAGMA main.table_xinfo(\"production_plans\")\n", "2022-09-20 15:40:36,189 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,191 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,191 INFO sqlalchemy.engine.Engine [raw sql] ('production_plans',)\n", "2022-09-20 15:40:36,193 INFO sqlalchemy.engine.Engine PRAGMA main.foreign_key_list(\"production_plans\")\n", "2022-09-20 15:40:36,194 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,195 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,196 INFO sqlalchemy.engine.Engine [raw sql] ('production_plans',)\n", "2022-09-20 15:40:36,197 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"production_plans\")\n", "2022-09-20 15:40:36,197 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,199 INFO sqlalchemy.engine.Engine PRAGMA main.index_list(\"production_plans\")\n", "2022-09-20 15:40:36,199 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,200 INFO sqlalchemy.engine.Engine PRAGMA main.index_info(\"sqlite_autoindex_production_plans_1\")\n", "2022-09-20 15:40:36,201 INFO sqlalchemy.engine.Engine [raw sql] ()\n", "2022-09-20 15:40:36,202 INFO sqlalchemy.engine.Engine SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'\n", "2022-09-20 15:40:36,202 INFO sqlalchemy.engine.Engine [raw sql] ('production_plans',)\n" ] } ], "source": [ "from sqlalchemy.ext.declarative import declarative_base\n", "\n", "Base = declarative_base()\n", "Base.metadata.bind = engine\n", "\n", "\n", "class ProductionType(Base):\n", " __tablename__ = \"production_types\"\n", " __table_args__ = {\"autoload\": True}\n", "\n", " # override the existing 'description'...\n", " description = Column(String(64))\n", "\n", " production_plans = relationship(\n", " \"ProductionPlan\", back_populates=\"production_type\", lazy=\"dynamic\"\n", " )\n", "\n", " def __init__(self, code, description):\n", " self.code = code\n", " self.description = description\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return self.code\n", "\n", "\n", "class BiddingArea(Base):\n", " __tablename__ = \"bidding_areas\"\n", " __table_args__ = {\"autoload\": True}\n", "\n", " production_plans = relationship(\n", " \"ProductionPlan\", back_populates=\"bidding_area\", lazy=\"dynamic\"\n", " )\n", "\n", " def __init__(self, code, name):\n", " self.code = code\n", " self.name = name\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return self.code\n", "\n", "\n", "class ProductionPlan(Base):\n", " __tablename__ = \"production_plans\"\n", " __table_args__ = {\"autoload\": True}\n", "\n", " production_type = relationship(ProductionType, back_populates=\"production_plans\")\n", " bidding_area = relationship(BiddingArea, back_populates=\"production_plans\")\n", "\n", " def __init__(self, record_created_time, start_time, production_type, bidding_area, value):\n", " self.record_created_time = record_created_time\n", " self.start_time = start_time\n", " self.production_type = production_type # a 'ProductionType' object\n", " self.bidding_area = bidding_area # a 'BiddingArea' object\n", " self.value = value\n", "\n", " def __repr__(self):\n", " return (\n", " f\"\"\n", " )\n", "\n", " def __str__(self):\n", " return (\n", " f\"{self.record_created_time} {self.start_time} \"\n", " f\"{self.production_type} {self.bidding_area} {self.value}\"\n", " )\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "1f18d9c1-bd39-4195-b868-114c3296eac2", "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2022-09-20 15:40:36,217 INFO sqlalchemy.engine.Engine BEGIN (implicit)\n", "2022-09-20 15:40:36,219 INFO sqlalchemy.engine.Engine INSERT INTO bidding_areas (code, name) VALUES (?, ?)\n", "2022-09-20 15:40:36,219 INFO sqlalchemy.engine.Engine [generated in 0.00067s] ('NO1', 'Elspot NO1')\n", "2022-09-20 15:40:36,221 INFO sqlalchemy.engine.Engine INSERT INTO bidding_areas (code, name) VALUES (?, ?)\n", "2022-09-20 15:40:36,221 INFO sqlalchemy.engine.Engine [cached since 0.002563s ago] ('NO2', 'Elspot NO2')\n", "2022-09-20 15:40:36,222 INFO sqlalchemy.engine.Engine INSERT INTO bidding_areas (code, name) VALUES (?, ?)\n", "2022-09-20 15:40:36,223 INFO sqlalchemy.engine.Engine [cached since 0.004114s ago] ('NO3', 'Elspot NO3')\n", "2022-09-20 15:40:36,224 INFO sqlalchemy.engine.Engine INSERT INTO bidding_areas (code, name) VALUES (?, ?)\n", "2022-09-20 15:40:36,224 INFO sqlalchemy.engine.Engine [cached since 0.0056s ago] ('NO4', 'Elspot NO4')\n", "2022-09-20 15:40:36,226 INFO sqlalchemy.engine.Engine INSERT INTO bidding_areas (code, name) VALUES (?, ?)\n", "2022-09-20 15:40:36,226 INFO sqlalchemy.engine.Engine [cached since 0.007587s ago] ('NO5', 'Elspot NO5')\n", "2022-09-20 15:40:36,228 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,228 INFO sqlalchemy.engine.Engine [generated in 0.00059s] ('B19', 'Wind Onshore')\n", "2022-09-20 15:40:36,229 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,230 INFO sqlalchemy.engine.Engine [cached since 0.002172s ago] ('B10', 'Hydro-electric pure pumped storage head installation')\n", "2022-09-20 15:40:36,231 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,232 INFO sqlalchemy.engine.Engine [cached since 0.003747s ago] ('B11', 'Hydro Run-of-river head installation')\n", "2022-09-20 15:40:36,233 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,233 INFO sqlalchemy.engine.Engine [cached since 0.00528s ago] ('B12', 'Hydro-electric storage head installation')\n", "2022-09-20 15:40:36,234 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,234 INFO sqlalchemy.engine.Engine [cached since 0.006383s ago] ('A04', 'Generation')\n", "2022-09-20 15:40:36,236 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,236 INFO sqlalchemy.engine.Engine [cached since 0.00839s ago] ('B37', 'Thermal unspecified')\n", "2022-09-20 15:40:36,237 INFO sqlalchemy.engine.Engine INSERT INTO production_types (code, description) VALUES (?, ?)\n", "2022-09-20 15:40:36,238 INFO sqlalchemy.engine.Engine [cached since 0.009993s ago] ('B30', 'Wind unspecified')\n", "2022-09-20 15:40:36,240 INFO sqlalchemy.engine.Engine INSERT INTO production_plans (record_created_time, start_time, bidding_area_id, production_type_id, value) VALUES (?, ?, ?, ?, ?)\n", "2022-09-20 15:40:36,241 INFO sqlalchemy.engine.Engine [generated in 0.00109s] (('2022-09-20 15:40:36.216893', '2022-11-02 01:00:00.000000', 1, 6, 80.5), ('2022-09-20 15:40:36.217038', '2022-11-02 02:00:00.000000', 1, 6, 90.5))\n", "2022-09-20 15:40:36,242 INFO sqlalchemy.engine.Engine COMMIT\n", "2022-09-20 15:40:36,243 INFO sqlalchemy.engine.Engine BEGIN (implicit)\n", "2022-09-20 15:40:36,245 INFO sqlalchemy.engine.Engine SELECT production_plans.record_created_time AS production_plans_record_created_time, production_plans.start_time AS production_plans_start_time, production_plans.bidding_area_id AS production_plans_bidding_area_id, production_plans.production_type_id AS production_plans_production_type_id \n", "FROM production_plans \n", "WHERE production_plans.record_created_time = ? AND production_plans.start_time = ? AND production_plans.bidding_area_id = ? AND production_plans.production_type_id = ?\n", "2022-09-20 15:40:36,246 INFO sqlalchemy.engine.Engine [generated in 0.00069s] ('2022-09-20 15:40:36.217038', '2022-11-02 02:00:00.000000', 1, 6)\n", "2022-09-20 15:40:36,248 INFO sqlalchemy.engine.Engine UPDATE production_plans SET value=? WHERE production_plans.record_created_time = ? AND production_plans.start_time = ? AND production_plans.bidding_area_id = ? AND production_plans.production_type_id = ?\n", "2022-09-20 15:40:36,248 INFO sqlalchemy.engine.Engine [generated in 0.00064s] (70.5, '2022-09-20 15:40:36.217038', '2022-11-02 02:00:00.000000', 1, 6)\n", "2022-09-20 15:40:36,249 INFO sqlalchemy.engine.Engine COMMIT\n" ] } ], "source": [ "# adding some data...\n", "import datetime\n", "import decimal\n", "\n", "from sqlalchemy.orm import sessionmaker\n", "\n", "Session = sessionmaker(bind=engine) # bound session\n", "session = Session()\n", "\n", "bidding_area1 = BiddingArea(\"NO1\", \"Elspot NO1\")\n", "session.add(bidding_area1),\n", "\n", "session.add_all(\n", " [\n", " BiddingArea(\"NO2\", \"Elspot NO2\"),\n", " BiddingArea(\"NO3\", \"Elspot NO3\"),\n", " BiddingArea(\"NO4\", \"Elspot NO4\"),\n", " BiddingArea(\"NO5\", \"Elspot NO5\"),\n", " ]\n", "),\n", "\n", "production_type_B37 = ProductionType(\"B37\", \"Thermal unspecified\")\n", "production_type_B30 = ProductionType(\"B30\", \"Wind unspecified\")\n", "\n", "session.add_all(\n", " [\n", " ProductionType(\"B19\", \"Wind Onshore\"),\n", " ProductionType(\"B10\", \"Hydro-electric pure pumped storage head installation\"),\n", " ProductionType(\"B11\", \"Hydro Run-of-river head installation\"),\n", " ProductionType(\"B12\", \"Hydro-electric storage head installation\"),\n", " ProductionType(\"A04\", \"Generation\"),\n", " production_type_B37,\n", " production_type_B30,\n", " ]\n", ")\n", "\n", "session.add(\n", " ProductionPlan(\n", " datetime.datetime.now(),\n", " datetime.datetime(2022, 11, 2, 1, 0),\n", " production_type_B37,\n", " bidding_area1,\n", " decimal.Decimal(\"80.5\"),\n", " )\n", ")\n", "\n", "production_plan2 = ProductionPlan(\n", " datetime.datetime.now(),\n", " datetime.datetime(2022, 11, 2, 2, 0),\n", " production_type_B37,\n", " bidding_area1,\n", " decimal.Decimal(\"90.5\"),\n", ")\n", "\n", "session.add(production_plan2)\n", "\n", "session.flush() # execute pending operations\n", "session.commit() # execute and commit pending operations (implicit flush)\n", "\n", "production_plan2.value = decimal.Decimal(\"70.5\")\n", "production_plan2 in session\n", "# Out: True\n", "\n", "session.commit()\n" ] }, { "cell_type": "markdown", "id": "86336aaa-540c-466d-b5c1-f3fc179bd1e3", "metadata": {}, "source": [ "# TODO\n", "\n", "- reflection\n" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 5 }