-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Alembic migrations and mod many methods (#37)
* Added new ModelField to allow global import * Added new insert_many method for bulk inserts. Added delete_many for bulk deletions. Added ModelField to allow for sqlalchemy_type defitions in models. Improved default, unique, primary_key, optional/required detection when building sqlalchemy.Column's using new ModelField / Unique, PrimaryKey arguments * Enabled executate_many for use with insert/delete many querries. Improved automatic migrations of non-sqlite with alembic for removal of columns / adding columns / moding columns preventing full table swaps. Added support for alembic migrations which will strictly require require alembic driven migrations * replaced imp with -> importlib. Improved DatabaseModel.OR class method, capable of grouping conditionals via AND based on list grouping [[This,and,This],or,[This,and,]] * Added database helper method alembic_migrate which orchestrates what alembic env.py would be expected to into single callable. Database.create() can be used outside an event loop when use_alembic=True as migrations should be driven by alembic. Pydbantic driven migrations now leverage alembic to reduce lift-and-shifting operations as much as possible * added .inside() example usage * removed metadata drop at end of test * added delete_many test example * added tests for new OR group conditional support * removed staged models no longer used by migration tests * added docs for alembic setup * added docs examples for insert_many, delete_many methods * updated migration tests - models that migrate are visible in test and are better documented * updated migration test range * added alembic==1.8.1 * Added new ModelField to allow global import * Added new insert_many method for bulk inserts. Added delete_many for bulk deletions. Added ModelField to allow for sqlalchemy_type defitions in models. Improved default, unique, primary_key, optional/required detection when building sqlalchemy.Column's using new ModelField / Unique, PrimaryKey arguments * Enabled executate_many for use with insert/delete many querries. Improved automatic migrations of non-sqlite with alembic for removal of columns / adding columns / moding columns preventing full table swaps. Added support for alembic migrations which will strictly require require alembic driven migrations * replaced imp with -> importlib. Improved DatabaseModel.OR class method, capable of grouping conditionals via AND based on list grouping [[This,and,This],or,[This,and,]] * Added database helper method alembic_migrate which orchestrates what alembic env.py would be expected to into single callable. Database.create() can be used outside an event loop when use_alembic=True as migrations should be driven by alembic. Pydbantic driven migrations now leverage alembic to reduce lift-and-shifting operations as much as possible * added .inside() example usage * removed metadata drop at end of test * added delete_many test example * added tests for new OR group conditional support * removed staged models no longer used by migration tests * added docs for alembic setup * added docs examples for insert_many, delete_many methods * updated migration tests - models that migrate are visible in test and are better documented * updated migration test range * added alembic==0.8.1 * corrected mysql type setting on alembic.alter_column within automigration. Updated mysql / postgres credential config in tests * corrected mysql type setting on alembic.alter_column within automigration. Updated mysql / postgres credential config in tests * corrected mysql type setting on alembic.alter_column within automigration. Updated mysql / postgres credential config in tests * corrected mysql type setting on alembic.alter_column within automigration. Updated mysql / postgres credential config in tests * removed breakpoint Co-authored-by: Codemation <[email protected]>
- Loading branch information
1 parent
86e912c
commit 22f2908
Showing
25 changed files
with
657 additions
and
446 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
## Migrations Using Alembic | ||
Although Pydbantic can handle migrations automatically, alembic can also be used if preferred. Configuration can be done in a few easy steps | ||
|
||
### Install alembic | ||
```bash | ||
pip install alembic | ||
``` | ||
### Define Models & DB instance | ||
```python | ||
#models.py | ||
from pydbantic import DataBaseModel, PrimaryKey, Default | ||
|
||
def time_now_str(): | ||
return datetime.now().isoformat() | ||
|
||
def stringify_uuid(): | ||
return str(uuid.uuid4()) | ||
|
||
class Employee(DataBaseModel): | ||
id: str = PrimaryKey(default=stringify_uuid) | ||
salary: float | ||
is_employed: bool | ||
date_employed: str = Default(default=time_now_str) | ||
``` | ||
|
||
### Connect with Database | ||
```python | ||
#db.py | ||
from pydbantic import Database | ||
from models import Employee | ||
|
||
db = Database.create( | ||
'sqlite:///company.db', | ||
tables=[Employee], | ||
use_alembic=True | ||
) | ||
``` | ||
### Initialze alembic | ||
```bash | ||
alembic init migrations | ||
``` | ||
Within the current directory, alembic will create a `migrations` folder that will store `versions` and its `env.py` that will need to updated. We will remove most of the boiler plate code and simply `import db` and use `db.alembic_migrate()`. | ||
|
||
|
||
Upate `migrations/env.py` file | ||
```python | ||
#migrations/env.py | ||
from alembic import context | ||
from db import db | ||
|
||
def run_migrations_offline() -> None: | ||
db.alembic_migrate() | ||
|
||
def run_migrations_online() -> None: | ||
db.alembic_migrate() | ||
|
||
if context.is_offline_mode(): | ||
run_migrations_offline() | ||
else: | ||
run_migrations_online() | ||
``` | ||
|
||
### Creating the first migration file | ||
Until now, we have just told alembic where to store our migrations, and where our db is configured. We still have not created any database tables to match our `Employee` model. | ||
```bash | ||
alembic revision -m "init_migration" --autogenerate | ||
``` | ||
|
||
Alembic is capable of detecting schema changes and often can do most of the work to build your migrations. Notice the new file in `migrations/versions/` matching the `-m "init_migration"` commit message. | ||
|
||
|
||
### Trigger Migration | ||
The final step once we have created a migration file is to trigger the migration. The instructions defined in the latest `migrations/versions` will be followed. | ||
|
||
```bash | ||
alembic upgrade head | ||
``` | ||
|
||
### Run Application | ||
Now we are all set, we can Create new persistent instances of our model and trust they are safely stored. | ||
|
||
```python | ||
#app.py | ||
import asyncio | ||
from db import db | ||
from models import Employee | ||
|
||
async def main(): | ||
await Employee.create( | ||
salary=10000, | ||
is_employed=True | ||
) | ||
all_employees = await Employee.all() | ||
print(all_employees) | ||
|
||
asyncio.run(main()) | ||
``` | ||
|
||
### Adding a new Model | ||
|
||
```python | ||
# models.py | ||
import uuid | ||
from datetime import datetime | ||
from typing import Optional, Union | ||
from pydantic import BaseModel | ||
from pydbantic import DataBaseModel, PrimaryKey, Default | ||
|
||
def time_now_str(): | ||
return datetime.now().isoformat() | ||
|
||
def stringify_uuid(): | ||
return str(uuid.uuid4()) | ||
|
||
class Positions(DataBaseModel): | ||
name: str = PrimaryKey() | ||
level: int = 4 | ||
|
||
class Employee(DataBaseModel): | ||
id: str = PrimaryKey(default=stringify_uuid) | ||
salary: float | ||
is_employed: bool | ||
date_employed: str = Default(default=time_now_str) | ||
position: Union[Positions, None] = Positions(name='Manager') | ||
``` | ||
|
||
Connect to database | ||
|
||
```python | ||
#db.py | ||
from pydbantic import Database | ||
from models import Employee, Positions | ||
|
||
db = Database.create( | ||
'sqlite:///company.db', | ||
tables=[Employee, Positions], | ||
use_alembic=True | ||
) | ||
``` | ||
Create new revision | ||
|
||
```bash | ||
alembic revision -m "added Positions" --autogenerate | ||
``` | ||
Migrate! | ||
```bash | ||
alembic upgrade head | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
from .database import Database | ||
from .core import DataBaseModel, PrimaryKey, Default, Unique | ||
from .core import ( | ||
DataBaseModel, | ||
PrimaryKey, | ||
Default, | ||
Unique, | ||
ModelField, | ||
) |
Oops, something went wrong.