Criando uma aplicação básica com FastAPI (parte 2)
Stack: FastAPI, Uvicorn, SQLAlchemy, Pydantic, Alembic, React
\=============================================================
Chegou o momento de criar o banco de dados (BD), e isso vai ser mais simples do que você imagina. Instale o SQLite Studio no seu computador: [link].
Agora você precisa clicar em Add a database (terceiro botão, ou dê um CTRL + O). Vai aparecer uma janela onde você vai poder escolher o local do seu database (coloque dentro da pasta /db do projeto) e o nome - eu escolhi 'database'.
Dê um ok e checa se ele criou mesmo. É isso!
\=============================================================
1 = Conectar o SQLAlchemy ao BD
Basicamente, o SQLAlchemy é um ORM (Object Relational Mapper) através do qual vamos interagir com o BD sem precisar escrever SQL puro (pelo menos nas tarefas mais básicas). Significa que você pode criar as tabelas e editá-las apenas utilizando o Python.
Crie um arquivo connection.py dentro de sua pasta /db:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "sqlite:///database.db"
Session = sessionmaker(bind=create_engine(DATABASE_URL))
Engine = create_engine(DATABASE_URL)
Nesse código, importamos a Engine e a Session do SQLAlchemy. A Engine faz a conexão com o BD, e a Session manipula a interação com a Engine.
Também criamos uma variável para a localização do banco de dados e o inserimos na Session e na Engine. Essa é a configuração básica do SQLAlchemy.
\=============================================================
2 = Criar a model
Agora precisamos criar a model para a tabela de drogas (ou o tema que você escolher). Com o SQLAlchemy, podemos fazer isso apenas com o Python.
Dentro da pasta /db, crie um arquivo models.py:
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, Float, String
Base = declarative_base()
class Drug(Base):
__tablename__ = 'drug'
id = Column(Integer, nullable=False, primary_key=True)
name = Column(String, nullable=False)
price = Column(Float, nullable=False)
stock = Column(Integer, nullable=False)
Primeiro, o declarative_base do SQLAlchemy é importado - que é uma função que permite que uma classe Python corresponda a uma tabela do banco de dados. Essa função é instanciada como Base e colocada como parâmetro da classe Drug.
O __tablename__ é o nome da tabela no BD. Em cada coluna é definido o tipo de dado (Integer, String, Float...) através de funções importadas do SQLAlchemy.
\=============================================================
3 = Criar o schema
Agora é a hora de utilizar o Pydantic. Através dele vamos fazer a validação dos dados que serão retornados ou enviados ao banco de dados.
O schema só vai realmente fazer efeito mais tarde quando criarmos endpoints pro CRUD (não se preocupe com isso agora), mas já dá pra deixar ele feito.
Crie um arquivo schemas.py dentro da pasta /schemas:
from pydantic import BaseModel
class DrugSchema(BaseModel):
name: str
price: float
stock: int
class ConfigDict:
json_schema_extra = {
"example": {
"name": "Piroxicam",
"price": 20,
"stock": "50"
}
}
A função BaseModel do Pydantic faz algo parecido com o que declarative_base do SQLAlchemy faz, no sentido de servir como parâmetro da classe e "informar" o que essa classe está correspondendo. A diferença é que aqui se trata de um schema, que é uma estrutura que define como os dados devem ser tratados e validados.
Declaramos as mesmas colunas da model (o id não é necessário), e dentro da classe ConfigDict um exemplo de como o JSON vai ser gerado. Você pode colocar o valor que quiser nos exemplos, desde que seja correspondente ao tipo de dado esperado. Exemplo: "name": "Fluoxetina".
\=============================================================
4 = Configurar o alembic
Agora nós já temos os dados necessários para mexer no BD pela primeira vez. Temos que inserir a primeira tabela nele. Para isso, vamos utilizar o Alembic, que gerencia migrações no BD.
Abra o terminal, vá para a pasta do projeto e dê o comando:
alembic init app/alembic
Isso vai gerar um arquivo alembic.ini na pasta do projeto e uma pasta /alembic dentro de /app. Ao invés de alembic, você pode nomear a pasta como migrations, se quiser.
Vá no alembic.ini e altere o sqlalchemy.url (que fica mais ou menos na linha 63). Ele vai ficar assim:
sqlalchemy.url = sqlite:///app/db/database
Agora o Alembic sabe onde está o arquivo database e que se trata de um SQLite. Mas ele também precisa saber o que ele vai migrar para esse BD que você indicou.
Para isso, vá na pasta /alembic, onde tem um novo arquivo env.py. Faça a importação do Base (que é aquela função declarative_base() que "representa" uma tabela de banco de dados) que você criou no models.py:
from app.db.models import Base
Procure a variável target_metadata e a deixe assim:
target_metadata = Base.metadata
Está configurado.
\=============================================================
5 = Fazer a primeira migração
Agora podemos fazer a primeira migração! Por hora, isso significa efetivamente criar a tabela no banco de dados. Existem dois passos para isso.
Primeiro é gerar a revisão da migração. No terminal, rode:
alembic revision --autogenerate -m "first migration"
Isso vai criar, dentro da pasta /alembic/versions, um arquivo cheio de números e o título first_migration que tava no comando.
Nesse arquivo você pode revisar se as alterações no BD que o Alembic gerou automaticamente (porque você escreveu --autogenerate no comando) estão corretas. Elas vão ficar assim:
Mas elas ainda não aconteceram. Ainda é possível alterar alguma coisa, mas nesse caso não precisamos. Ele sempre gera uma função upgrade(), que são as alterações que vão ser feitas. E também o downgrade(), que é uma função que faz o contrário do upgrade(). Isso é necessário caso você queira voltar atrás numa migração.
Estando tudo certo, segue o último comando para efetivar:
alembic upgrade head
Tá feito! Você pode abrir o SQLite Studio e verificar a tabela lá - se não aparecer, botão direito e refresh.
No próximo post vamos começar a fazer o CRUD da aplicação. Coming soon.