Tutorial: Aplicação em Python + SQLite (Parte 02)
Overview
Dando continuidade à nossa aventura no mundo do desenvolvimento de aplicações Python, na primeira parte cobrimos a construção do Frontend. Agora, é hora de mergulhar nos mistérios do Backend, especificamente no que diz respeito à interação com o banco de dados SQLite. Se você estava procurando um guia passo a passo sobre como criar, ler, atualizar e deletar dados, não procure mais! Nesta segunda parte do tutorial, vamos codificar juntos o comportamento que dará vida à nossa aplicação, transformando aqueles campos vazios em um registro dinâmico de clientes. Prepare-se, porque vamos aprender fazendo!
Na primeira parte deste tutorial nós fizemos o “Frontend”. A interface gráfica está pronta, agora precisamos codificar o comportamento que elemento (objeto/widget) terá. Nesta parte faremos a interação com o banco de dados (SQLite)…
Apenas para lembrar, queremos fazer uma aplicação parecida com esta:
Cadastro de Clientes em Python
Índice:
- Parte 01: Frontend;
- Parte 02: Backend <[Você está aqui];
- Parte 03: Ligando o Backend com o Frontend;
- Parte 04: Compilando para Windows/Mac.
Parte 02_ Backend;
Nesta parte, precisaremos criar o CRUD (Create, Read, Update e Delete) além, é claro, de criar o banco em si.
Para esta aplicação, precisamos apenas de uma tabela (que se chamará clientes), com os seguintes campos:
- Id
- Nome
- Sobrenome
- CPF
O SQLite faz esta tarefa ser bem simples…
import sqlite3
database = "clientes.db"
conn = sqlite3.connect(database)
cur = conn.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS cliente (id INTEGER PRIMARY KEY , nome TEXT, sobrenome TEXT, email TEXT, cpf TEXT)")
conn.commit()
conn.close()
O fonte acima se conecta ao banco de dados “clientes.db” e cria a tabela cliente, caso não exista. Neste exemplo, ele será um arquivo no diretório da aplicação.
Ao indicar que o campo id é uma PRIMARY KEY, ela já será definida como auto-increment.
Crie um arquivo chamado Backend.py e importe a biblioteca sqlite3:
import sqlite3 as sql
Sempre que utilizarmos o banco de dados, precisaremos repetir 4 linhas de código:
#Conectando ao bano de daods...
conn = sqlite3.connect(database)
cur = conn.cursor()
#... Ações usando o banco...
#Fazendo commit e desconecta do banco...
conn.commit()
conn.close()
Estas linhas vão ser sempre iguais e eu não sou muito fã de ficar repetindo código, então vamos encapsular estas lógicas…. mas temos um problema: Ao acessar o banco, temos duas variáveis: A de conexão (conn) e o cursor (cur).
Uma das maneiras de fazer isso é criar uma classe que contenha toda essa lógica… Existem formas mais elegantes de se fazer isso, mas quero manter as coisas simples para este tutorial. (Depois farei uma outra série de posts falando sobre Orientação a Objetos no Python…)
Nossa classe que cuidará da conexão com o banco e das operações será chamada de TransactionObject:
class TransactionObject():
database = "clientes.db"
conn = None
cur = None
connected = False
def connect(self):
TransactionObject.conn = sql.connect(TransactionObject.database)
TransactionObject.cur = TransactionObject.conn.cursor()
TransactionObject.connected = True
def disconnect(self):
TransactionObject.conn.close()
TransactionObject.connected = False
def execute(self, sql, parms = None):
if TransactionObject.connected:
if parms == None:
TransactionObject.cur.execute(sql)
else:
TransactionObject.cur.execute(sql, parms)
return True
else:
return False
def fetchall(self):
return TransactionObject.cur.fetchall()
def persist(self):
if TransactionObject.connected:
TransactionObject.conn.commit()
return True
else:
return False
Esta classe possui funções:
- connect(): realiza conexão com o banco de dados
- disconnect(): fecha a conexão com o banco de dados
- execute(self, sql, parms): executa um comando no banco de dados. recebe três parâmetros:
- self: referencia para o próprio objeto. não precisa ser informado;
- sql: comando SQL a ser executado;
- parms: vetor com os parâmetros do comando SQL. Pode ser omitido.
- fetchall(): recupera os valores recebidos de um comando select.
- persist(): realiza o commit das operações realizadas.
Quando a aplicação for executada pela primeira vez, precisaremos criar o banco de dados:
def initDB():
trans = TransactionObject()
trans.connect()
trans.execute("CREATE TABLE IF NOT EXISTS clientes (id INTEGER PRIMARY KEY , nome TEXT, sobrenome TEXT, email TEXT, cpf TEXT)")
trans.persist()
trans.disconnect()
initDB()
No fonte acima definimos a função initDB() e fazemos uma chamada a ela logo depois. Isso fará com que a aplicação chame esta função sempre que for iniciada. Ela se conecta ao banco de dados e cria a tabela de clientes, caso não exista. Desta forma, sempre que a aplicação for executada, ela irá verificar se o banco existe ou não e toma as providências necessárias. Isso de forma transparente para o usuário.
Agora vamos começar a construir as funções que serão utilizadas pelo Frontend. A primeira delas é a view(), a função que vai recuperar todos os dados do banco.
def view():
trans = TransactionObject()
trans.connect()
trans.execute("SELECT * FROM clientes")
rows = trans.fetchall()
trans.disconnect()
return rows
A próxima é a função que insere novos registros no banco:
def insert(nome, sobrenome, email, cpf):
trans = TransactionObject()
trans.connect()
trans.execute("INSERT INTO clientes VALUES(NULL, ?,?,?,?)", (nome, sobrenome, email, cpf))
trans.persist()
trans.disconnect()
Agora vamos fazer a função de busca, que será realizada utilizando o operador OR e todos os campos que não forem preenchidos pelo usuário na hora da busca serão considerados como strings vazias…
def search(nome="", sobrenome="", email="", cpf=""):
trans = TransactionObject()
trans.connect()
trans.execute("SELECT * FROM clientes WHERE nome=? or sobrenome=? or email=? or cpf=?", (nome,sobrenome,email, cpf))
rows = trans.fetchall()
trans.disconnect()
return rows
A função de atualização é a próxima a ser criada:
def update(id, nome, sobrenome, email, cpf):
trans = TransactionObject()
trans.connect()
trans.execute("UPDATE clientes SET nome =?, sobrenome=?, email=?, cpf=? WHERE id = ?",(nome, sobrenome,email, cpf, id))
trans.persist()
trans.disconnect()
Por último, vamos fazer a função para remover registros:
def delete(id):
trans = TransactionObject()
trans.connect()
trans.execute("DELETE FROM clientes WHERE id = ?", (id,))
trans.persist()
trans.disconnect()
As operações encapsuladas são todas bem simples, quase sempre seguindo a sequencia: operação no banco de dados, commit e desconecta. Uma aplicação do mundo real seria mais complexa e possuiria lógicas de tratamento de erros e rollbacks, quando necessário.
Nesta seção criamos as funções que serão utilizadas no Frontend. Elas já estão funcionais e podem ser utilizadas através de script, mas ainda não estão interagindo com a parte gráfica e este é o próximo passo.