Tutorial de Flask parte 4 (base de datos sqlite3)
Posted on lun 12 septiembre 2016 in Tutorial Python • 6 min read
Continuando con la serie de tutoriales sobre Flask, en este caso se tocará el tema de base de datos, usando sqlite3.
Este artículo se basa en el artículo en Inglés de The Flask Mega tutorial, Part IV: Database.
Los artículos anteriores son:
tutorial-flask/
├── app
│ ├── forms.py
│ ├── __init__.py
│ ├── models.py
│ ├── templates
│ │ ├── base.html
│ │ ├── index.html
│ │ └── login.html
│ └── views.py
├── config.py
├── db_create.py
├── db_downgrade.py
├── db_migrate.py
├── db_upgrade.py
├── docker-compose.yml
├── Dockerfile
├── README.md
├── run.py
└── tmp
Los archivos nuevos o modificados son los siguientes:
- config.py
.
- db_create.py
: Script para crear la base de datos.
- db_migrate.py
: Script para migrar la base de datos.
- db_upgrade.py
: Script para actualizar la base de datos.
- db_downgrade.py
: Script para revertir actulización de la base de datos.
- __init__.py
- models.py
: Módulo donde se define las tablas de la base de datos.
Archivo config.py
:
#Se importa os
import os
#Se define el directorio base del proyecto
basedir = os.path.abspath(os.path.dirname(__file__))
#Se habilita CSRF
CSRF_ENABLED = True
#Se define la clave secreta
SECRET_KEY = 'pruea'
PROVEEDORES_OPENID = [
{'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id'},
{'name': 'Yahoo', 'url': 'https://me.yahoo.com'}]
#Se define el uri de la base de datos sqlite app.db
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
#Se define el repositorio para migracion de la base de datos app.db
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
Archivo __init__.py
:
#Se importa Flask
from flask import Flask
#Se importa SQLALchemy
#from flask.ext.sqlalchemy import SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
#Se crea la instancia de flask
app = Flask(__name__)
#Se define la configuracion
app.config.from_object('config')
#SE instancia la base de datos
db = SQLAlchemy(app)
#Se importa views y models de app
from app import views, models
Archivo models.py
:
#de app se importa db
from app import db
#Se crea la tabla User que hereda de db.Model
class User(db.Model):
#Se crea la columna id como clave primaria e integer
id = db.Column(db.Integer, primary_key=True)
#Se crea la columna nickname como string de tamagn 64, como unico.
usuario = db.Column(db.String(64), index=True, unique=True)
#Columna correo, de 120 de tamagno del string y unico.
correo = db.Column(db.String(120), index=True, unique=True)
#Posts. que tiene relacion con la clase Post (tabla post),
posts = db.relationship('Post', backref='author', lazy='dynamic')
def __repr__(self):
return '<User %r>' % (self.usuario)
#Tabla Post que hereda de model
class Post(db.Model):
#Se crea el id del post como entero y clave primaria
id = db.Column(db.Integer, primary_key=True)
#Se crea la columna body como string de 140 caracteres
cuerpo = db.Column(db.String(140))
#Se define la marca de tiempo.
timestamp = db.Column(db.DateTime)
#Se define el id del usuario, es una clave foranea de la tabla usuario
#Columna id.
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Post %r>' % (self.cuerpo)
Archivo db_create.py
:
#!/usr/bin/env python
#de migrate.versioning se importa api
from migrate.versioning import api
#De config se importa el uri
from config import SQLALCHEMY_DATABASE_URI
#De config se importa el repo de migrate
from config import SQLALCHEMY_MIGRATE_REPO
#De app se importa db
from app import db
#Se importa os.path
import os.path
#Se crea la base de datos.
db.create_all()
#Si el directorio del migrate no existe se crea y se usa,
#Si no se usa.
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO,
api.version(SQLALCHEMY_MIGRATE_REPO))
Archivo db_migrate.py
:
#!/usr/bin/env python
#se importa api.
from migrate.versioning import api
#Se importa el uri y el migrate.
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
#se define la version de la db para las migraciones.
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se baja una version.
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
#Se vuelva a definir el uri y migrate de la vesion.
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se muestra en pantalla la version actual.
print('Current database version: ' + str(v))
Archivo db_upgrate.py
:
#!/usr/bin/env python
#Se importa api.
from migrate.versioning import api
#De config se importa URI y el repo.
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
#Se actualiza el api.
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se define la version del api.
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se muestra la nueva version.
print('Current database version: ' + str(v))
Archivo db_downgrade.py
:
#!/usr/bin/env python
#se importa api.
from migrate.versioning import api
#Se importa el uri y el migrate.
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
#se define la version de la db para las migraciones.
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se baja una version.
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
#Se vuelva a definir el uri y migrate de la vesion.
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
#Se muestra en pantalla la version actual.
print('Current database version: ' + str(v))
Construir la imagen docker por medio de docker-compose
:
docker-compose build
Ahora toca ejecutar el contenedor:
docker-compose up
Creating tutorialflask_web_1
Attaching to tutorialflask_web_1
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger pin code: 201-487-104
Ahora para crear la base de datos se usa docker desde otra consola en el mismo directorio del proyecto:
Primero un docker ps
:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52bf03d39d06 tutorialflask_web "/bin/sh -c 'python r" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp tutorialflask_web_1
Ya se tiene el ID del contenedor, ahora a ejecutar docker exec
:
docker exec -ti 52bf03d39d06 ./db_create.py
Ahora se ejecuta un ls -l
y se tiene lo siguiente:
drwxr-xr-x 4 ernesto ernesto 4096 sep 12 20:07 app
-rw-r--r-- 1 root root 7168 sep 12 22:31 app.db
-rw-r--r-- 1 ernesto ernesto 620 sep 12 22:14 config.py
-rwxr-xr-x 1 ernesto ernesto 773 sep 12 20:29 db_create.py
-rwxr-xr-x 1 ernesto ernesto 619 sep 12 20:31 db_downgrade.py
-rwxr-xr-x 1 ernesto ernesto 1530 sep 12 20:37 db_migrate.py
drwxr-sr-x 4 root root 4096 sep 12 22:31 db_repository
-rwxr-xr-x 1 ernesto ernesto 456 sep 12 20:52 db_upgrade.py
-rw-r--r-- 1 ernesto ernesto 67 sep 4 17:27 docker-compose.yml
-rw-r--r-- 1 ernesto ernesto 480 sep 4 17:27 Dockerfile
drwxr-xr-x 2 root root 4096 sep 12 22:29 __pycache__
-rw-r--r-- 1 ernesto ernesto 0 sep 4 17:27 README.md
-rw-r--r-- 1 ernesto ernesto 79 sep 4 17:27 run.py
drwxr-xr-x 2 ernesto ernesto 4096 sep 19 2014 tmp
Se crearon el archivo app.db
y el directorio __py__cache__
.
Ahora se ejecutará la primera migración:
docker exec -ti 52bf03d39d06 ./db_migrate.py
New migration saved as /code/db_repository/versions/001_migration.py
Current database version: 1
Se salvó la primera migración y el número de versión es 1. Al listar los archivos
y directorios se tiene lo siguiente:
drwxr-xr-x 4 ernesto ernesto 4096 sep 12 20:07 app
-rw-r--r-- 1 root root 7168 sep 12 22:33 app.db
-rw-r--r-- 1 ernesto ernesto 620 sep 12 22:14 config.py
-rwxr-xr-x 1 ernesto ernesto 773 sep 12 20:29 db_create.py
-rwxr-xr-x 1 ernesto ernesto 619 sep 12 20:31 db_downgrade.py
-rwxr-xr-x 1 ernesto ernesto 1530 sep 12 20:37 db_migrate.py
drwxr-sr-x 4 root root 4096 sep 12 22:31 db_repository
-rwxr-xr-x 1 ernesto ernesto 456 sep 12 20:52 db_upgrade.py
-rw-r--r-- 1 ernesto ernesto 67 sep 4 17:27 docker-compose.yml
-rw-r--r-- 1 ernesto ernesto 480 sep 4 17:27 Dockerfile
drwxr-xr-x 2 root root 4096 sep 12 22:29 __pycache__
-rw-r--r-- 1 ernesto ernesto 0 sep 4 17:27 README.md
-rw-r--r-- 1 ernesto ernesto 79 sep 4 17:27 run.py
drwxr-xr-x 2 ernesto ernesto 4096 sep 19 2014 tmp
Ahora se tiene el directorio db_repository
.
Ahora se trabajará con la base de datos de manera interactiva, se ejecuta docker exec
:
docker exec -ti 52bf03d39d06 python
Python 3.5.2 (default, Aug 22 2016, 21:04:27)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
De la aplicación se importa db y models:
>>> from app import db, models
Se crea un usuario:
>>> u = models.User(usuario='john', correo='john@email.com')
>>> db.session.add(u)
>>> db.session.commit()
Se crea otro usuario:
>>> u = models.User(usuario='jane', correo='jane@email.com')
>>> db.session.add(u)
>>> db.session.commit()
Se hace una consulta de los usuarios:
>>> users = models.User.query.all()
>>> users
[<User 'john'>, <User 'jane'>]
>>> for user in users:
... print (user)
...
<User 'john'>
<User 'jane'>
Obtener información del usuario con id 1:
>>> u = models.User.query.get(1)
>>> u
<User 'john'>
Ahora se agregarán unos posts:
>>> import datetime
>>> u = models.User.query.get(1)
>>> p = models.Post(cuerpo='mi primer post!', timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> db.session.commit()
```python
Se sale del interprete de comandos.
Ahora se usará `sqlitebrowser` para revisar la base de datos `app.db`:
En la figura se muestra la pantalla principal de la aplicación donde se ve las sentencias SQL para la
creación de las tablas:
![](./images/tutorialdeflask4-1.png)
Ahora se muestra los datos, la tabla usuario y la tabla de post:
![](./images/tutorialdeflask4-2.png)
![](./images/tutorialdeflask4-3.png)
Para detener el contenedor se ejecuta:
docker-compose down
```
El código fuente de este artículo se encuentra en gitlab en la rama articulo4.
¡Haz tu donativo! Si te gustó el artículo puedes realizar un donativo con Bitcoin (BTC) usando la billetera digital de tu preferencia a la siguiente dirección: 17MtNybhdkA9GV3UNS6BTwPcuhjXoPrSzV
O Escaneando el código QR desde la billetera: