Skip to content
Snippets Groups Projects
Commit 43ee2a76 authored by Michael Kyriakou's avatar Michael Kyriakou
Browse files

Added "RunUpgradeMigration" and "RunDowngradeMigration". Improved

"README".
parent 597b3ddf
No related branches found
No related tags found
No related merge requests found
......@@ -47,65 +47,127 @@ You will also notice the lines `Environment: production` and `Debug mode: off` w
## Tutorial 3: Configuring a test environment
# Flask Migrations
# Flask Migrations and Databases
A table in flask is called a "Model", all models need to extend "db.Model". You have been provided with two models, "Person" and "PhoneNumber" which is a 1-many relationship; a "Person" can be many "PhoneNumber".
## Adding a new table
## Setup
1. Use an existing model as a guide.
It is very useful to have some view of your database as you develop to see whether migrations have actually been performed, and to view your data. We recommend "PgAdmin" if you are going to use PostgreSQL connection strings.
2. Modify the "models" package to import your model, otherwise flask will not see it and not be able to migrate it.
Download link: https://www.pgadmin.org/download/
3. Run a new migration when you're happy with your model.
### Tutorial: Setup remote connection to database with PgAdmin
1. Right-click on "Servers".
## Tutorial: connect to your database
You will need to specify the database connection strings for development ("debug" or "dev") and for production ("prod").
2. Create => Server...
4. Go to "Connection"
5. Enter for "Host" the IP address (or hostname) of the server which runs PostgreSQL Server.
6. Enter the "Port", default is `5432`.
7. Enter the "Username", default is `postgres`.
8. Enter the "Password", no default, the server should've been setup with one.
9. Hit "Save".
### Tutorial: Create a database remotely with PgAdmin
1. Click the server you remotely connected to in the previous tutorial.
2. Right-click on "Databases".
3. Create two new databases: one called "first_db_prod", and another called "first_db_debug".
4. Form two connection strings using the format below:
`postgresql://<username>:<password>@<host>:<port>/<db_name>`
Example: `postgresql://postgres:sAmPlE>@82.36.12.1:5432/first_db`
5. Go to the next tutorial below.
TIP: do not use SQLite if you plan to make use of flask migrations.
### Tutorial: connect to your database
You will need to specify the database connection strings for development ("debug" or "dev") and for production ("prod").
1. Navigate to: config/config.py
1. Navigate to: `config/config.py`
2. CTRL + F, then type in: db_configs
3. Within this array, modify the existing single entry.
3. You'll see a single entry with two specified environment variables.
4. For each environment variable, configure your computer to set these as user environment variables. In Windows do the following: Control Panel => Search: environment => Edit the environment variables for your account => "New" => ...
5. Reload your IDE so the environment variable take effect.
Notes
- To speed up development you may use the "force" optional parameter variants, however this is discouraged as it exposes your connection string in your git repository.
- The two connection strings must NOT be the same!
- Do not use SQLite if you plan to make use of flask migrations.
- If you do add another database, make sure you add a static variable as well under the "DB Bindings" region, as you'll need to be able to reference this binding from the outside when creating models for the database this binding will be for.
- All binding key names must be unique; they are the identifiers Flask uses to uniquely identify each database amongst all other databases in your application.
4. The "bind_key_name" is the identifier Flask uses to uniquely identify your database amongst all other databases in your application. Currently only one is used, however if, say, three were in use, then the "bind_key_name" is very important. As such, it must be unique. Change the value to something more descriptive.
5. Make sure you add a static variable as well under the "DB Bindings" region, as you'll need to be able to reference this binding from the outside when creating models for the database this binding will be for.
## Adding a new table
1. Navigate to: `models`; you're models should all be made here.
6. Change the "debug_env_var_key" and "prod_env_var_key" values to be the environment variable key values that contain your connection strings for the "debug" and "prod" databases respectively. NOTE: that to speed up development you may use the "force" optional parameter variants, however this is discouraged as it exposes your connection string in your git repository.
2. Modify the "models" `"__init__.py"` to import your model, otherwise flask will not see it and not be able to migrate it.
3. Run a new migration when you're happy with your model to auto add the table for you.
## Running a Migration
When you run a migration for the first time the "migrations" directory will be constructed.
When you run a migration for the first time the `migrations` directory will be constructed.
### Managing Migrations
The "migrations" directory contains all migrations you have performed on every database this app uses. It contains the subdirectories "dev" and "prod", then subdirectories identified by the binding keys used.
The `migrations` directory contains all migrations you have performed on every database this app uses. It contains the subdirectories `dev` and `prod`, then subdirectories identified by the binding keys used.
You have been provided with the binding "first_db". Running a migration will result in the following path being accessible:
You have been provided with the binding `first_db`. Running a migration will result in the following path being accessible:
migrations/dev/first_db/
`migrations/dev/first_db/`
It is very important that you do not delete anything from this directory, since flask migrate will also store a migration history in correspondance to the directory's contents in your database, under the "alembic" table.
It is very important that you do not delete anything from this directory, since flask migrate will also store a migration history in correspondance to the directory's contents in your database, under the `alembic` table.
### Tutorial: checking your migration script
### Tutorial: running an "upgrade" migration script
Flask migrate will automatically generate a migration script based on the differences between your database represented in flask (this application) and the actual database. It may be incorrect, or may not fully complete the migration you want. To resolve this, you should check the migration script, and verify it does what you want it to do.
1. Navigate to: models/first_db_models/phone_number.py
1. Navigate to: `models/first_db_models/phone_number.py`
2. It is very useful for rows in a database to have a `created_at` attribute so you know when the row was first inserted. Comment out the new under the TODO, and remove the TODO.
3. Edit the file: `RunUpgradeMigration`
4. Change the value of the 3rd argument to either `dev` or `prod`.
5. Change the value of the 4th argument to be the binding key name of the database you want to migrate. Since "PhoneNumber" is a model that exists in the database bound to the binding key name "first_db", change the value to "first_db".
6. Save the file, then run it.
7. Navigate to: `migrations/dev/first_db/versions`
8. You should see a new python file created in here under some hash code, open the file.
9. Verify the file is doing an `add_column` operation in the `upgrade` method.
10. Complete the migration by pressing ENTER.
2. It is very useful for rows in a database to have a "created_at" attribute so you know when the row was first inserted. Comment out the new under the TODO, and remove the TODO.
11. Repeat for the other database, i.e.: if you migrated on `dev`, then you should also migrate on `prod` at some point.
3. Run "RunMigration" depending on your Operating System.
### Tutorial: running an "downgrade" migration script
Example: you performed an "upgrade" migration but realize that it wasn't what you wanted, or could improve the column definition, for example you realize "phone_number" should not be a column part of "Person" but rather a separate table called "PhoneNumber" with a 1-many relation.
4. Navigate to: migrations/dev/first_db/versions
1. Edit `RunDowngradeMigration`.
5. You should see a new python file created in here under some hash code, open the file.
2. Change the value of the 3rd argument to either `dev` or `prod`.
6. Verify the file is doing an "add_column" operation.
3. Change the value of the 4th argument to be the binding key name of the database you want to migrate. Since `PhoneNumber` is a model that exists in the database bound to the binding key name `first_db`, change the value to `first_db`.
7. Complete the migration by pressing ENTER, calling the script's "upgrade" method.
4. Save the file, then run it.
## Troubleshooting
### Consistency violation, cannot find version
Delete/drop the "alembic" table for the database and delete the associated migration directory.
Delete/drop the `alembic` table from the database, and delete the associated migration directory for this table only.
set FLASK_APP=main.py
flask db downgrade
RunMigration.bat downgrade dev first_db
\ No newline at end of file
set ENV=dev
set ENV=%2
set FLASK_APP=app.py
set FLASK_DB_BINDING_TO_MIGRATE=first_db
set FLASK_DB_BINDING_TO_MIGRATE=%3
set migrations_dir_path=migrations/%ENV%/%FLASK_DB_BINDING_TO_MIGRATE%
flask db init --directory %migrations_dir_path%
flask db migrate -m "In this migration we did..." --directory %migrations_dir_path%
ECHO "Press enter 2 times to confirm and run the migration..."
ECHO "Press enter 2 times to confirm and %1 the migration..."
pause
pause
:upgrade
flask db upgrade --directory %migrations_dir_path%
pause
goto upgrade
\ No newline at end of file
flask db %1 --directory %migrations_dir_path%
pause
\ No newline at end of file
RunMigration.bat upgrade dev first_db
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment