Banco de Dados: Criando um CRUD com Kivy e SQLite3 | Josiel Soares

CRUD Completo em SQLite3 e Kivy

Tutorial de programação para as principais operações de Base de Dados

Kivy é um framework multiplataforma para a linguagem de programação Python3

Trata-se de um app Organizador de Leituras, onde o usuário pode adicionar livros em que está atualmente lendo, para depois em outro dia ou hora este usuário possa continuar exatamente da página em que havia parado, por meio deste marcador digital de leituras você verá que é um app de produtividade em que agora você pode ler um livro em seu próprio ritmo do início até a última página.



Com este tutorial você estará apto a fazer algo único com estes princípios exibidos aqui na implementação deste projeto, aprendendo e evoluindo de acordo com sua disposição para absorver o conteúdo e aplicar em sua necessidade de programação.


Inicialmente precisamos acessar o diretório onde está instalado o ambiente virtual de programação em python e diretório de projetos do kivy, neste diretório crie um outro sub-diretório para nosso CRUD com um novo arquivo main.py, note que a extensão do arquivo deve ser .py que é o formato utilizado pelo interpretador da linguagem de programação Python.

As classes que vamos importar para o Kivy:

            # arquivo main.py
            import kivy
            kivy.require('2.0.0')
            import sqlite3
            from kivy.app import App
            from kivy.uix.label import Label
            from kivy.core.window import Window
            from kivy.lang import Builder
            from kivy.uix.button import Button
            from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
            from kivy.properties import ObjectProperty, ListProperty
            from kivy.uix.recycleview.views import RecycleDataViewBehavior
            from kivy.uix.recyclegridlayout import  RecycleGridLayout 
            from kivy.uix.behaviors import FocusBehavior
            from kivy.uix.recycleview.layout import LayoutSelectionBehavior
        

As classes vazias mas importantes para o projeto:

            # continuação do arquivo main.py
            class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
                pass
            class SelectableButton(RecycleDataViewBehavior, Button):
                pass
            class menu(Screen):
                pass
        

A classe da tela RecycleView onde vai receber os dados:

            # continuação do arquivo main.py
            class rv(Screen):
                col1 = ListProperty()
                col2 = ListProperty()
                conexao = sqlite3.connect("org_livros.db")
                def pegar_livros(self):
                    self.col1 = []
                    self.col2 = []
                    with self.conexao:
                        cursor = self.conexao.cursor()
                        cursor.execute("SELECT id, titulo  FROM tb_livros ORDER BY id ASC")
                        self.conexao.commit()
                        rows = cursor.fetchall()
                        for row in rows:
                            print(row)
                            self.col1.append(row[0])
                            self.col2.append(row[1])
        

A classe da tela com os campos para inserção de dados:

            # continuação do arquivo main.py
            class create_sc(Screen):
                txt_id = ObjectProperty(None)
                txt_tit = ObjectProperty(None)
                txt_aut = ObjectProperty(None)
                txt_pag = ObjectProperty(None)
                txt_dat = ObjectProperty(None)
                txt_npg = ObjectProperty(None)
                lbl_resposta = ObjectProperty(None)
        

A classe da tela de leitura de detalhes dos dados:

            # continuação do arquivo main.py
            class read_sc(Screen):
                titulo = ObjectProperty(None)
                autor = ObjectProperty(None)
                patual = ObjectProperty(None)
                datal = ObjectProperty(None)
                tpags = ObjectProperty(None)
                cid = ObjectProperty(None)
                def atualizar_form(self, t1, t2, t3, t4, t5):
                    self.ids.titulo.text = "Titulo: " + t1
                    self.ids.autor.text = "Autor: " + t2
                    self.ids.datal.text = "Data da Leitura: " + t3
                    self.ids.patual.text = "Página atual: "+ t4
                    self.ids.tpags.text = "Quant. de Páginas: " + t5
        

A classe da tela de atualização dos dados com método e parâmetros:

            # continuação do arquivo main.py
            class update_sc(Screen):
                upd_id = ObjectProperty(None)
                upd_tit = ObjectProperty(None)
                upd_aut = ObjectProperty(None)
                upd_dat = ObjectProperty(None)
                upd_pat = ObjectProperty(None)
                upd_tpg = ObjectProperty(None)
                lbl_resposta = ObjectProperty(None)
                def atualizar_form(self, t1, t2, t3, t4, t5):
                    self.ids.upd_tit.text = t1
                    self.ids.upd_aut.text = t2
                    self.ids.upd_dat.text = t3
                    self.ids.upd_pat.text = t4
                    self.ids.upd_tpg.text = t5
        

A classe da tela de exclusão de dados por determinado id:

            # continuação do arquivo main.py
            class delete_sc(Screen):
                del_id = ObjectProperty(None)
                del_tit = ObjectProperty(None)
                del_aut = ObjectProperty(None)
                lbl_resposta = ObjectProperty(None)
                def atualizar_form(self, t1, t2):
                    self.ids.del_tit.text = "Título: " + t1
                    self.ids.del_aut.text = "Autor: " + t2
        

Importação da interface gráfica e adição do ScreenManager:

            # continuação do arquivo main.py
            Builder.load_string(open("gui.kv", encoding="utf-8").read(), rulesonly=True)
            sm = ScreenManager(transition=WipeTransition())
            sm.add_widget(rv(name='rv'))
            sm.add_widget(menu(name='menu'))
            sm.add_widget(create_sc(name='create'))
            sm.add_widget(read_sc(name='read'))
            sm.add_widget(update_sc(name='update'))
            sm.add_widget(delete_sc(name='delete'))
            sm.current = "menu"
        

Estrutura da classe principal do projeto e sua execução:

            # continuação do arquivo main.py
            class CrudKivy(App):                    
                def criar_tabela(self):
                    pass
                def selecionar_todos_livros(self):        
                    pass
                def inserir_livro(self, txt_tit, txt_aut, txt_dat, txt_pag, txt_npg):
                    pass
                def selecionar_livro(self, cid, sc):
                    pass
                def atualizar_livro(self, upd_id, upd_tit, upd_aut, upd_dat, upd_pat, upd_tpg):
                    pass
                def deletar_livro(self, id):
                    pass
                def build(self):
                    App.title = "Organizador de Leituras"
                    Window.size = (320, 480)
                    self.criar_tabela()
                    return sm
            CrudKivy().run()


        

O Método criar_tabela() da classe CrudKivy()

            # continuação do arquivo main.py
            def criar_tabela(self):
                self.conexao = sqlite3.connect("org_livros.db")
                self.cursor = self.conexao.cursor()
                sql = """ CREATE TABLE IF NOT EXISTS tb_livros( id INTEGER PRIMARY KEY AUTOINCREMENT, titulo TEXT (50) NOT NULL, autor TEXT (50), data_leitura DATE, pagina_atual INTEGER, n_paginas INTEGER)"""
                self.cursor.execute(sql) 
        

O Método selecionar_todos_livros() da classe CrudKivy()

            # continuação do arquivo main.py
            def selecionar_todos_livros(self):        
                rv = sm.get_screen('rv')        
                rv.pegar_livros()
                sm.current = 'rv'   
        

O Método inserir_livro() da classe CrudKivy()

            # continuação do arquivo main.py
            def inserir_livro(self, txt_tit, txt_aut, txt_dat, txt_pag, txt_npg):
                edt = sm.get_screen('create')
                try:
                    if txt_tit != "" and txt_aut != "" and txt_dat != "" and txt_pag != "" and txt_npg != "":
                        self.cursor.execute("""INSERT INTO tb_livros (titulo, autor, data_leitura, pagina_atual, n_paginas) VALUES (?,?,?,?,?)""", (txt_tit, txt_aut, txt_dat, txt_pag, txt_npg))
                        self.conexao.commit()
                        edt.lbl_resposta.text = "Livro Cadastrado com Sucesso!"
                        print("Dados Inseridos com Sucesso!")
                    else:
                        edt.lbl_resposta.text = "Todos campos devem ser preenchidos."
                        print("Todos campos devem ser preenchidos")
                except sqlite3.Error as error:
                    edt.lbl_resposta.text = "Algum erro ocorreu"
                    print("Algum erro ocorreu", error)
                    self.conexao.rollback()
            
        

O Método selecionar_livro() da classe CrudKivy()

            # continuação do arquivo main.py
            def selecionar_livro(self, cid, sc):
                try:
                    self.cursor.execute("SELECT * FROM tb_livros WHERE id = ?", (cid))
                    self.conexao.commit()
                    records = self.cursor.fetchall()
                    slc = sm.get_screen('read')
                    upd = sm.get_screen('update')
                    dlt = sm.get_screen('delete')
                    for row in records:
                        if sc == 'selecionar':
                            slc.atualizar_form(str(row[1]), str(row[2]), str(row[3]), str(row[4]), str(row[5]))
                        elif sc == 'atualizar':
                            upd.atualizar_form(str(row[1]), str(row[2]), str(row[3]), str(row[4]), str(row[5]))
                        elif sc == 'excluir':
                            dlt.atualizar_form(str(row[1]), str(row[2]))
                except sqlite3.Error as error:
                    print("Algum erro ocorreu.", error)
            
        

O Método atualizar_livro() da classe CrudKivy()

            # continuação do arquivo main.py
            def atualizar_livro(self, upd_id, upd_tit, upd_aut, upd_dat, upd_pat, upd_tpg):
                upd = sm.get_screen('update')
                try:
                    if upd_tit != "" and upd_aut != "" and upd_dat != "" and upd_pat != "" and upd_tpg != "":
                        self.cursor.execute("UPDATE tb_livros SET (titulo, autor, data_leitura, pagina_atual, n_paginas) = (?,?,?,?,?) WHERE id = ?", (upd_tit, upd_aut, upd_dat, upd_pat, upd_tpg, upd_id,))
                        self.conexao.commit()
                        upd.lbl_resposta = "Livro Atualizado com Sucesso!"
                        print("Dados atualizados com Sucesso!")
                    else:
                        upd.lbl_resposta.text = "Todos campos devem ser preenchidos"
                except sqlite3.Error as error:
                    print("Algum erro ocorreu.", error)
            
        

O Método deletar_livro() da classe CrudKivy()

            # continuação do arquivo main.py
            def deletar_livro(self, id):
                if id != "":
                    sql = 'DELETE FROM tb_livros WHERE id = ?'
                    self.cursor.execute(sql, (id,))
                    self.conexao.commit()
                    dlt = sm.get_screen('delete')
                    dlt.lbl_resposta.text = 'Livro Excluído com Sucesso!'
                    print('Dados Excluído com Sucesso!')
            
        

Considerando que já fizemos toda esta parte lógica do projeto de aplicativo mobile, agora precisamos adicionar os espaços onde se manipulará os dados do banco em SQLite3, para isso precisamos criar o arquivo gui.kv no mesmo diretório onde está o arquivo main.py, código principal do projeto em que estamos editando.

O arquivo gui.kv está escrito na linguagem interna do framework Kivy na Kv Language para a nossa gui: Graphic User Interface.kv que significa em português: Interface Gráfica de Usuário. É onde podemos adicionar os widgets do Kivy que são Rótulos, Botões, Campos de Textos, Imagens entre outros.


Código da gui para o objeto que recebe os dados.

            # o arquivo gui.kv
            :
                viewclass: 'SelectableButton'
                    SelectableRecycleGridLayout:
                        cols: 1
                        default_size: None, dp(26)
                        default_size_hint: 1, None
                        size_hint_y: None
                        heigh: self.minimum_height 
            
        

Código da gui para a tela do RecycleView.

            # continuação do arquivo gui.kv
            :
                BoxLayout:
                    orientation: 'vertical'
                    GridLayout:
                        size_hint: 1, None
                        height: 25
                        cols: 2
                        Label:
                            size_hint_x: 0.2
                            text: 'ID'
                        Label:
                            size_hint_x: 0.8
                            text: 'Título do Livro'
                    BoxLayout:
                        MyRV:
                            size_hint_x: 0.2
                            data: [{'text': str(x)} for x in root.col1]
                        MyRV:
                            size_hint_x: 0.8
                            data: [{'text': str(x)} for x in root.col2]
                    Button:
                        size_hint_y: 0.2
                        text: 'Voltar ao Menu'
                        on_press: root.manager.current ='menu'

            
        

Código da gui para a tela de Menu com seus Widgets.

            # continuação do arquivo gui.kv
            
                BoxLayout:
                    orientation: 'vertical'
                    Label:
                        size_hint: (1, 0.4)
                        text: 'CRUD SQLite \nPrincipais Operações em \n Banco de Dados \n\n Organizador de Livros'
                        halign: 'center'
                    Button:
                        size_hint: (1, 0.2)
                        text: 'Todos os Livros'
                        on_press: app.selecionar_todos_livros()
                    Button:
                        size_hint: (1, 0.2)
                        text: 'Cadastrar Livro'
                        on_press: root.manager.current = 'create'
                    Button:
                        size_hint: (1, 0.2)
                        text: 'Selecionar Livro'
                        on_press: root.manager.current='read'
                    Button:
                        size_hint: (1, 0.2)
                        text: 'Atualizar Livro'
                        on_press: root.manager.current = 'update'
                    Button:
                        size_hint: (1, 0.2)
                        text: 'Excluir Livro'
                        on_press: root.manager.current ='delete'

            
        

Código da gui para a tela de Inserção de dados com seus Widgets.

            # continuação do arquivo gui.kv
            
                txt_id: txt_id
                txt_tit: txt_tit
                txt_aut: txt_aut
                txt_dat: txt_dat
                txt_pat: txt_pat
                txt_tpg: txt_tpg
                lbl_resposta: lbl_resposta
                BoxLayout:
                    orientation: 'vertical'
                    TextInput:
                        hint_text: 'ID'
                        id: txt_id
                    TextInput:
                        hint_text: 'Título do Livro'
                        id: txt_tit
                    TextInput:
                        hint_text: 'Autor do Livro'
                        id: txt_aut
                    TextInput:
                        hint_text: 'Data da Leitura'
                        id: txt_dat
                    TextInput:
                        hint_text: 'Página Atual'
                        id: txt_pat
                    TextInput:
                        hint_text: 'Total de Páginas'
                        id: txt_tpg
                    Label:
                        text: 'Esperando Interação...'
                        id: lbl_resposta
                    Button:
                        text: 'Cadastrar Livro'
                        on_press: app.inserir_livro(txt_tit.text, txt_aut.text, txt_dat.text, txt_pat.text, txt_tpg.text)
                    Button:
                        text: 'Voltar ao Menu'
                        on_press: root.manager.current = 'menu'

            
        

Código da gui para a tela de Leitura de dados com seus Widgets.

            # continuação do arquivo gui.kv
            :
                titulo: titulo
                autor: autor
                datal: datal
                cid: cid
                patual: patual
                tpags: tpags
                BoxLayout:
                    orientation: 'vertical'
                    TextInput:
                        id: cid
                        hint_text: 'ID'
                    Label:
                        id: titulo
                        text: 'Título do Livro'
                    Label:
                        id: autor
                        text: 'Autor do Livro'
                    Label:
                        id: datal
                        text: 'Data da Leitura'
                    Label:
                        id: patual
                        text: 'Página Atual'
                    Label:
                        id:tpags
                        text: 'Total de Páginas'
                    Button:
                        text: 'Selecionar Livro'
                        on_press: app.selecionar_livro(cid.text, 'selecionar')
                    Button:
                        text: 'Voltar ao Menu'
                        on_press: root.manager.current = 'menu'

            
        

Código da gui para a tela de Atualização de dados com seus Widgets.

            # continuação do arquivo gui.kv
            :
                upd_id: upd_id
                upd_tit: upd_tit
                upd_aut: upd_aut
                upd_dat: upd_dat
                upd_pat: upd_pat
                upd_tpg: upd_tpg
                lbl_resposta: lbl_resposta
                BoxLayout:
                    orientation: 'vertical'
                    Label:
                        text: 'ID'
                    TextInput:
                        id: upd_id
                        hint_text: 'ID'
                    TextInput:
                        id: upd_tit
                        hint_text: 'Título do Livro'
                    TextInput:
                        id: upd_aut
                        hint_text: 'Autor do Livro'
                    TextInput:
                        id: upd_dat
                        hint_text: 'Data Última Leitura'
                    TextInput:
                        id: upd_pat
                        hint_text: 'Página Atual'
                    TextInput:
                        id: upd_tpg
                        hint_text: 'Quantidade de Páginas'
                    Label:
                        id: lbl_resposta
                        text: 'Esperando Interação...'
                    Button:
                        text: 'Selecionar Livro'
                        on_press: app.selecionar_livro(upd_id.text, 'atualizar')
                    Button: 
                        text: 'Atualizar Livro'
                        on_press: app.atualizar_livro(upd_id.text, upd_tit.text, upd_aut.text, upd_dat.text, upd_pat.text, upd_tpg.text)
                    Button: 
                        text: 'Voltar ao Menu'
                        on_press: root.manager.current = 'menu'

            
        

Código da gui para a tela de Exclusão de dados com seus Widgets.

            # continuação do arquivo gui.kv
            :
                del_id: del_id
                del_tit: del_tit
                del_aut: del_aut
                lbl_resposta: lbl_resposta
                BoxLayout:
                    orientation: 'vertical'
                    TextInput:
                        id: del_id
                        hint_text: 'ID'
                    Label:
                        id: del_tit
                        text: 'Título do Livro'
                    Label:
                        id: del_aut
                        text: 'Autor do Livro'
                    Label: 
                        id: lbl_resposta
                        text: 'Esperando Interação...'
                    Button:
                        text: 'Selecionar Livro'
                        on_press: app.selecionar_livro(del_id.text, 'excluir')
                    Button:            
                        text: 'Excluir Livro'
                        on_press: app.deletar_livro(del_id.text)
                    Button:
                        text: 'Voltar ao Menu'
                        on_press: root.manager.current = 'menu'            
        

A live Hora do Código completo deste projeto em Vídeo no Youtube

Por favor consulte também este link do canal para acesso ao material completo, separado em dois vídeos.

Parte 1: Início



Parte 2: Complemento e Parte Final:


Portanto, caro leitor, neste projeto você pode observar vários elementos que compôem o aplicativo, são saberes específicos de funcionamento do framework Kivy, espero que com este projeto eu possa aguçar sua curiosidade sobre esta tecnologia, poupei linhas ao não comentar tudo pelo fato de que eu desejava disponibilizar o código fonte inteiro para sua consulta, e para que eu possa reler e revisar o projeto para quando eu mesmo for desenvolver outros projetos.

Este artigo serve tanto para você que está lendo agora como para mim mesmo autor, Josiel Soares, grato, se você é novo por aqui Seja Bem Vindo! se você já é chegado Fique à Vontade! Valeu e até em breve.