En esta plantilla, puede utilizar Postgres o SQLite como motor de base de datos. Verifique su archivo .env para especificar cuál desea utilizar. Puede utilizar la var env DATABASE_URL
para este propósito.
1$ psql
1\l
Nota: Si estás usando Gitpod, revisa el archivo
docs/assets/reset_migrations.bash
. Básicamente, estás creando una base de datos desde cero llamadaexample
.
1CREATE DATABASE example;
Nota: Asegúrese de actualizar DB_CONNECTION_STRING
en el archivo .env
con el nombre correcto de la base de datos.
Command
1\c example;
Result
1postgres=# \c example; 2Ahora estás conectado a la base de datos "example" como usuario "gitpod".
1\dt
users
:1select * from users;
Nota: Escriba
exit
si desea salir del terminal Postgres.
Para más comandos, puedes consultar este asombroso resumen.
La mayoría de las plantillas de 4Geeks Academy utilizan la librería SQLAlchemy para construir modelos, crear un modelo es muy sencillo:
1class Artist(db.Model): 2 id: Mapped[int] = mapped_column(primary_key=True) 3 name: Mapped[str] = mapped_column(String(80), nullable=False) 4 5 # Este es el aspecto que tendrá el artista en las respuestas JSON de la API 6 def serialize(self): 7 return { 8 "id": self.id, 9 "name": self.name 10 }
He aquí algunos ejemplos de los distintos tipos de relaciones.
Una relación uno a muchos coloca una clave foránea en la tabla del hijo que hace referencia al padre.
relationship()
se especifica en el padre, como referencia a una colección de elementos representados por el hijo:
1class Artist(db.Model): 2 id: Mapped[int] = mapped_column(primary_key=True) 3 name: Mapped[str] = mapped_column(String(80), nullable=False) 4 5 # Un artista puede tener muchas grabaciones, y llamaremos a esta lista "records" 6 # esta es una clave externa que apunta al Record.id 7 records: Mapped[List["Record"]] = relationship() 8 9 10 def serialize(self): 11 return { 12 "id": self.id, 13 "name": self.name, 14 "records": list(map(lambda x: x.serialize(), self.records)) 15 } 16 17class Record(db.Model): 18 id: Mapped[int] = mapped_column(primary_key=True) 19 name: Mapped[str] = mapped_column(String(80), nullable=False) 20 21 # un registro sólo puede tener un artista, esto apunta al Artist.id 22 artist_id: Mapped[int] = mapped_column(ForeignKey("parent.id"), nullable=False) 23 24 25 def serialize(self): 26 return { 27 "id": self.id, 28 "name": self.name 29 }
Muchos a Muchos añade una tabla de asociación entre dos clases. La tabla de asociación se indica mediante el argumento secundario de relationship()
.
Normalmente, la tabla utiliza el objeto MetaData asociado a la clase base declarativa, para que las directivas ForeignKey puedan localizar las tablas remotas con las que enlazar:
1association_table = db.Table('association', 2 Base.metadata, 3 Column("sister_id", ForeignKey("sister.id"), primary_key=True), 4 Column("brother_id", ForeignKey("brother.id"), primary_key=True) 5) 6 7class Sister(db.Model): 8 id: Mapped[int] = mapped_column(primary_key=True) 9 name: Mapped[str] = mapped_column(String(80), nullable=False) 10 brothers: Mapped[List[Brother]] = relationship( 11 secondary=association_table, back_populates="sisters" 12 ) # this line is so it updates the field when Sister is updated 13 14 15 def serialize(self): 16 return { 17 "id": self.id, 18 "name": self.name, 19 "brothers": list(map(lambda x: x.serialize(), self.brothers)) 20 } 21 22class Brother(db.Model): 23 id: Mapped[int] = mapped_column(primary_key=True) 24 name: Mapped[str] = mapped_column(String(80), nullable=False) 25 sisters: Mapped[List[Sister]] = relationship( 26 secondary=association_table, back_populates="brothers" 27 ) 28 29 30 def serialize(self): 31 return { 32 "id": self.id, 33 "name": self.name, 34 "sisters": list(map(lambda x: x.serialize(), self.sisters)) 35 }
Una vez que tu archivo models.py
esté listo, tienes que migrar
y actualizar
para poder sincronizar los cambios en tu motor de base de datos.
Este comando creará todos los archivos de migraciones en tu carpeta ./migrations
, de esta forma los tendremos confirmados en Github y todos los que trabajen en el proyecto tendrán exactamente la misma estructura de base de datos.
1$ pipenv run migrate
Nota: Es importante mencionar que el comando
migrate
no actualiza tu base de datos, tendrás queupgrade
si quieres realmente sincronizar los cambios en tu base de datos.
El comando de actualización echa un vistazo a los archivos de migraciones, y ejecuta todo lo que queda por ejecutar (fuera de sincronización) para asegurarse de que su base de datos está alineada con las migraciones.
1$ pipenv run upgrade
Al actualizar y migrar su base de datos, se encontrará con muchos errores. Aquí es donde resultan útiles los conocimientos de sintaxis SQL.
🛑 El botón del pánico: Hemos preparado este comando para ayudarte a poner a cero tu base de datos y tus migraciones.
1$ bash docs/assets/reset_migrations.bash
Hay muchas maneras de manipular bases de datos, pero hemos decidido utilizar Python y SQLAlchemy para hacerlo. Esto significa que no necesitas conocimientos de SQL, pero te recomendamos encarecidamente que aún así practiques y domines SQL con fines de depuración (la mayoría de los errores se muestran en lenguaje SQL)
Asumiendo que tienes un objeto Person en tu archivo models.py
.
1# coger a toda la gente 2stmt = select(Person) 3people_query = db.session.execute(stmt).scalars().all() 4 5# obtener sólo las que se llamen "Joe 6stmt = select(Person).where(Person.name == 'Joe') 7people_query = db.session.execute(stmt).scalars().all() 8 9# asigna los resultados y tu lista de personas dentro de la variable all_people 10all_people = list(map(lambda x: x.serialize(), people_query)) 11 12# obtener sólo una persona 13stmt = select(Person).where(Person.id == person_id) 14user1 = db.session.execute(stmt).scalars().first()
Asumiendo que tienes un objeto Person en tu fichero models.py
.
1user1 = Person(username="my_super_username", email="my_super@email.com") 2db.session.add(user1) 3db.session.commit()
1stmt = select(Person).where(Person.id == person_id) 2user1 = db.session.execute(stmt).scalars().first() 3 4if user1 is None: 5 raise APIException('User not found', status_code=404) 6 7if "username" in body: 8 user1.username = body["username"] 9if "email" in body: 10 user1.email = body["email"] 11db.session.commit()
1stmt = select(Person).where(Person.id == person_id) 2user1 = db.session.execute(stmt).scalars().first() 3 4if user1 is None: 5 raise APIException('User not found', status_code=404) 6db.session.delete(user1) 7db.session.commit()
Para más información, visite la siguiente página: https://flask-sqlalchemy.palletsprojects.com/en/stable/quickstart/#define-models