KassORM
Gerenciamento de migrations, modelos, seeders e gerador de query
Criado com o intuito de abstratir toda uma modelagem de dados, de forma fácil. Sua criação é baseada na biblioteca Eloquent vista no Laravel, framework PHP. A principio, não há muitos ORMs para python que são intuitivos no uso, inicialemente, neste pacote, era utilizado o SqlAlchemy, mas seu uso e documentação são complicados, com uma curva grande para aprendizado, não desmerecendo ele, sabemos o quão robusto e estável está atualmente, mas precisavamos de algo mais direto e que entendessemos a fundo o uso.
Indice
- Criar e executar
- Configurando uma migration
- Lista de tipos de campos e outras ferramentas
- Relacionamentos
Migration
Uso de migrations são importantes para manter o versionamento do banco de dados. Veja abaixo como utilizar.
Criar e executar
Utilize o metodo 'make_file_migration()' informando o nome, diretório, nome da tabela e opcionalmente um comentário. O nome da migration tem como prefixos 'create_' e 'alter_', então gere o nome com eles para que as regras de cada tipo sejam setadas no arquivo gerado.
name_migration = "create_users"
dir_migration = "database"
table = "users"
comment = "criação da tabela de usuários"
Migration().make_file_migration(name_migration, dir_migration, table, comment)
Para executar as migrations informe apenas o local onde elas estão no método "migrate()", este comando também cria uma tabela ( migrations ) para gerenciamento de qual migration já foi executada.
dir_migration = "database"
Migration().migrate(dir_migration)
Drop
Para reiniciar o processo, fazendo o rollback das migrations, use o metodo 'drop_all_migrations()'
dir_migration = "database"
Migration().drop_all_migrations(dir_migration)
Configurando uma migration
O arquivo gerado terá a seguinte aparência:
from KassOrm import Migration
class migrate(Migration):
__type__ = 'create'
__table__ = 'users'
__comment__ = 'criação da tabela de usuários'
def up(self):
self.id().add()
self.datetime('created_at').add()
def down(self):
self.dropTableIfExists()
Um valor opcional __ conn __ pode ser passado na classe, para determinar qual conexão usar, essa conexão deverá estar configurada em configs/database. Não informando será usado a conexão padrão.
É aqui que será criado os campos da tabela e seus relacionamentos. o metodo up(), é executado quando a migration é executada para criar, nesse caso, uma tabela, o down(), é o metodo responsavel por fazer o inverso, no caso dropar a tabela.
Lista de tipos de campos e outras propriedades:
# colunas
id()
string(name, qnt)
bigInteger(name)
bigIntegerUnisigned(name)
text(name)
enum(name, values)
integer(name,qnt)
datetime(name)
# propriedades para as colunas
foreign(table, key, local_key)
nullable()
unsigned()
comment(comment)
unique(columns,name)
current_timestamp()
update_timestamp()
addColumn()
dropColumn(name)
after(column)
first(column)
dropTableIfExists()
Relacionamentos
Para relacionar duas tabelas, use foreign() como abaixo:
from KassOrm import Migration
class adresses(Migration):
__type__ = 'create'
__table__ = 'adress'
__comment__ = 'contem endereços'
def up(self):
self.id().add()
self.string('name').add()
self.string('number).add()
def down(self):
self.dropTableIfExists()
class migrate(Migration):
__type__ = 'create'
__table__ = 'users'
__comment__ = 'criação da tabela de usuários'
def up(self):
self.id().add()
self.datetime('created_at').add()
self.unsignedBigInteger('adress_id').add()
self.foreign(table="adress", key="id", local_key="adress_id").add()
def down(self):
self.dropTableIfExists()
Querier
Criador de querys para maior segurança e abstração de banco de dados.
Querier() recebe como parametro o nome da conexão (Querier('api')) que estará configurado dentro das configurações, caso não seja informada, será usada a conexão padrão (default).
Instanciar a classe e informar a tabela:
query = Querier('api').table("users")
Agora poderá usar a var query para fazer diversas buscas e filtros na mesma tabela.
query.get()
# SELECT * FROM users
query.where({"name":"kass"}).get()
# SELECT * FROM users WHERE (name = "kass")
Select
Selecionando os campos, caso o método select não for chamado, será sempre retornado todos os campos
query.select(["name","login"])
Selecionando os campos e pegando todos os dados, get() finaliza a query
query.select(["name","login"]).get()
Selecionando os campos e pegando somente o primeiro registro, first() finaliza a query
query.select(["name","login"]).first()
Retornando a query a executar, toSql() finaliza a query
query.select(["name","login"]).toSql()
Retornando a query separado dos parametros, toInfo() finaliza a query
query.select(["name","login"]).toInfo()
Limit e offset
query.limit(10).offset(2).get()
Where
Para filtrar os dados podemos usar vários metodos encadeados.
query.where({"name":"admin,"id":1}).get()
# SELECT * FROM users WHERE ( name = admin AND id = 1 )
query.where({"name":"admin,"id":1}).orWhere({"id":2}).get()
# SELECT * FROM users WHERE ( name = admin AND id = 1 ) OR ( id = 2 )
query.whereIn("name",["admin","kass"]).get()
# SELECT * FROM users WHERE (name IN ('admin', 'kass'))
query.whereIsNull("admin").get()
# SELECT * FROM users WHERE ( admin IS NULL )
query.whereIsNotNull("admin").get()
# SELECT * FROM users WHERE ( admin IS NOT NULL )
query.whereLike("name","%kass%").get()
# SELECT * FROM users WHERE ( name LIKE %kass% )
query.whereNotIn("name",["marcos","bee"]).get()
# SELECT * FROM users WHERE (name NOT IN ('marcos', 'bee'))
Group e Order
Para agrupar basta passar uma string com as colunas:
query.groupBy("name, login").get()
ou uma lista de colunas:
query.groupBy(["name","login"]).get()
Ordenação, pode-se passar uma string:
query.orderBy("name asc, login desc").get()
ou um dicionário informando a coluna e a direção:
query.orderBy({"name":"asc", "login":"desc"}).get()
Insert
Insere um ou mais registros
Querier().table("users").insert({"name":"kass"})
Querier().table("users").insert([{"name":"kass"},{"name":"admin"}])
Update
Atualizando um valor.
Querier().table("users").where({"id":1}).update({"name":"ADMINISTRADOR","login":"ADMIN"})
OBS: Não esqueça de sempre utilizar a clausula *where* quando for atualizar registros.
Delete
Exclua um ou mais registros definitivamente
Querier().table("users").whereIn("id",[1,2]).delete()
SoftDelete
Para trabalhar com softDelete, ou seja, não deletar um registro e sim desativar, você somente precisará configurar a classe Querier() com o parametro softDelete e informar nele qual a coluna que representa a desativação do registro, essa coluna deverá ser do tipo datetime, geralmente a coluna se chama deleted_at.
Querier(softDelete="deleted_at").table("users").where({"id":1}).delete()
O registro é atualizado na coluna determinada com a data e hora do delete.
Com essa configuração o select será afetado, não retornando os registros em que o campo determinado não for nulo.
Querier(softDelete="deleted_at").table("users").get()
# retorna tudo menos o id 1 que esta 'deletado'
Para retornar tudo, inclusive o que foi deletado, use o método withTrashed()
Querier(softDelete="deleted_at").table("users").withTrashed().get()
Utilize o método active(), para ativar um registro anteriormente deletado com softDelete. Este método só tem efeito utilizando o withTrashed().
Querier(softDelete="deleted_at").table("users").withTrashed().active()
OBS: Não esqueça de sempre utilizar a clausula *where* quando for excluir registros.
Modelr
Classe para abstrair a classe Querier() e facilitar o uso dos dados nas tabelas, relacionamentos e informações sobre as queries de forma facilitada.
Veja a estrutura básica de um modelo:
from KassOrm import Modelr
class User(Modelr)
__conn__ = 'api'
__table__ = 'users'
Sendo que foi necessário fazer o import da classe Modelr e a injeção do mesmo no modelo. Duas configurações apra o modelo são: qual a conexão (conn) e qual a tabela do banco (table) que o model representa. Se não informar a conexão, ele irá pegar a conexaõ padrão (default) configurada.
Select
Pegando todos os dados
User().get()
Pegando somente o primeiro registro
User().first()
Escolhendo colunas exibir
User().select(['name','login']).get()
Pegando todos os dados filtrados
User().where({"name":"admin,"id":1}).get()
Pegando sql e parametros
# exibe a query executada
User().where({"name":"admin,"id":1}).toSql()
# exibe a query e seus parametros separados
User().where({"name":"admin,"id":1}).toInfo()
Limit e offset
User().where({"name":"admin,"id":1}).limit(10).offset(2).get()
Where
Para filtrar os dados podemos usar vários metodos encadeados.
User().where({"name":"admin,"id":1}).get()
# SELECT * FROM users WHERE ( name = admin AND id = 1 )
User().where({"name":"admin,"id":1}).orWhere({"id":2}).get()
# SELECT * FROM users WHERE ( name = admin AND id = 1 ) OR ( id = 2 )
User().whereIn("name",["admin","kass"]).get()
# SELECT * FROM users WHERE (name IN ('admin', 'kass'))
User().whereIsNull("admin").get()
# SELECT * FROM users WHERE ( admin IS NULL )
User().whereIsNotNull("admin").get()
# SELECT * FROM users WHERE ( admin IS NOT NULL )
User().whereLike("name","%kass%").get()
# SELECT * FROM users WHERE ( name LIKE %kass% )
User().whereNotIn("name",["marcos","bee"]).get()
# SELECT * FROM users WHERE (name NOT IN ('marcos', 'bee'))
Relacionamentos
1 para 1
Para montar seus relacionamentos, crie métodos dentro do seu modelo como abaixo.
Pensando que cada User (campo id) tem um Phone (campo user_id) (1 para 1):
from KassOrm import Modelr
class Phone(Modelr)
__conn__ = 'api'
__table__ = 'phones'
class User(Modelr)
__conn__ = 'api'
__table__ = 'users'
def phone(self):
return self.hasOne(Phone, "user_id","id")
Usando o relacionamento.
User().related('phone').get()
O método "related()" recebe uma string ou uma lista de strings.
Retorno do relacionamento seria:
[
{
"id":1,
"name":"admin",
"phone":{
"id":1,
"user_id":1,
"number":"12334567"
}
}
]
Onde a chave 'phone' representa os dados do relacionamento de User com Phone.
O método "hasOne" recebe os parametros:
- Phone => (model) modelo a se relacionar
- user_id => (model_key) nome do campo dentro de Phone que representa o user
- id => (local_key) identificador de User
1 para N
Agora vamos exemplificar que cada User tem muitos endereços (Address).
from KassOrm import Modelr
class Phone(Modelr)
__conn__ = 'api'
__table__ = 'phones'
class Address(Modelr)
__conn__ = 'api'
__table__ = 'addresses'
class User(Modelr)
__conn__ = 'api'
__table__ = 'users'
def phone(self):
return self.hasOne(Phone, "user_id","id")
def addresses(self):
return self.hasMany(Address, "user_id","id")
Usando o relacionamento.
User().related(['phone','addresses']).get()
O método "related()" recebe uma string ou uma lista de strings. Retorno dos relacionamentos seria:
[
{
"id":1,
"name":"admin",
"phone":{
"id":1,
"user_id":1,
"number":"12334567"
},
"addresses":[
{
"id":1,
"user_id:1,
"address":"RUA 1"
},
{
"id":2,
"user_id:1,
"address":"RUA 2"
},
]
}
]
Onde a chave 'addresses' representa os dados do relacionamento de User com Address.
O método "hasMany" recebe os parametros:
- Address => (model) modelo a se relacionar
- user_id => (model_key) nome do campo dentro de Address que representa o user
- id => (local_key) identificador de User
N para N
Para casos que há muitos para muitos, devemos usar uma tabela intermediária. Segue como deria um relacionamento de User com Permission (permissões).
from KassOrm import Modelr
class Phone(Modelr)
__conn__ = 'api'
__table__ = 'phones'
class Address(Modelr)
__conn__ = 'api'
__table__ = 'addresses'
class Permission(Modelr)
__conn__ = 'api'
__table__ = 'permissions'
class User(Modelr)
__conn__ = 'api'
__table__ = 'users'
def phone(self):
return self.hasOne(Phone, "user_id","id")
def addresses(self):
return self.hasMany(Address, "user_id","id")
def permissions(self):
return self.hasManyToMany(Permission, 'id', 'permission_id', 'users_apps_permissions', 'user_id', 'id')
Usando o relacionamento.
User().related(['phone','addresses','permissions']).get()
O método "related()" recebe uma string ou uma lista de strings.
Retorno dos relacionamentos seria:
[
{
"id":1,
"name":"admin",
"phone":{
"id":1,
"user_id":1,
"number":"12334567"
},
"addresses":[
{
"id":1,
"user_id:1,
"address":"RUA 1"
},
{
"id":2,
"user_id:1,
"address":"RUA 2"
},
],
"permissions":[
{
"id":1,
"name":"acesso geral"
},
{
"id":2,
"name":"acesso a cadastrar"
},
{
"id":3,
"name":"acesso a excluir"
}
]
}
]
Onde a chave 'permissions' representa os dados do relacionamento de User com Permission.
O método "hasManyToMany" recebe os parametros:
- Permission => (model) modelo a se relacionar
- id => (model_key) identificador de Permission
- permission_id => (intermediate_model_key) identificador de Permission na tabela intermediária
- users_apps_permissions => (intermediate_table) nome da tabela intermediária
- user_id => (intermediate_local_key) identificador de User na tabela intermediária
- id => (local_key) identificador de User
Pegando dados da tabela intermediária
O metodo "hasManyToMany" ainda pode receber o encadeamento de "withPivot()", que pode receber uma lista de nomes dos campos a exibir da tabela intermediária, se não for passado a lista, será retornado todos os campos da tabela intermediária. Veja o exemplo:
from KassOrm import Modelr
.
.
.
class User(Modelr)
__conn__ = 'api'
__table__ = 'users'
def phone(self):
return self.hasOne(Phone, "user_id","id")
def addresses(self):
return self.hasMany(Address, "user_id","id")
def permissions(self):
return self.hasManyToMany(Permission, 'id', 'permission_id', 'users_apps_permissions', 'user_id', 'id')->withPivot()
Alterando o retorno da chave permissions para:
[
{
.
.
.
"permissions":[
{
"id":1,
"name":"acesso geral",
"pivot":{
"user_id":1,
"permission_id":1,
}
},
{
"id":2,
"name":"acesso a cadastrar",
"pivot":{
"user_id":1,
"permission_id":2,
}
},
{
"id":3,
"name":"acesso a excluir",
"pivot":{
"user_id":1,
"permission_id":3,
}
}
]
}
]
Passando, "->withPivot(["user_id"])", somente o campo user_id seria exibido
Group e Order
Para agrupar basta passar uma string com as colunas:
User().groupBy("name, login").get()
ou uma lista de colunas:
User().groupBy(["name","login"]).get()
Ordenação, pode-se passar uma string:
User().orderBy("name asc, login desc").get()
ou um dicionário informando a coluna e a direção:
User().orderBy({"name":"asc", "login":"desc"}).get()
Insert
id = User().insert({"name":"kass"})
print(id)
ids = User().insert([{"name":"admin"},{"name":"kass"}])
print(ids)
Update
Atualizando um registro.
User().where({"id":1}).update({"name":"admin"})
OBS: Não esqueça de sempre utilizar a clausula *where* quando for atualizar registros.
Delete
Para excluir um registro utilize o método delete().
User().where({"id":1}).delete()
SoftDelete
Para trabalhar com softDelete, ou seja, não deletar um registro e sim desativar, você somente precisará configurar o seu model com a constante sofDelete e informar nele qual a coluna que representa a desativação do registro, essa coluna deverá ser do tipo datetime, geralmente a coluna se chama deleted_at.
class User(Modelr):
__sofDelete__="deleted_at"
para excluir use normal o metodo delete.
User().where({"id":1}).delete()
O registro é atualizado na coluna determinada com a data e hora do delete.
Com essa configuração o select será afetado, não retornando os registros em que o campo determinado não for nulo.
User().get()
# retorna tudo menos o registro que esta 'deletado'
Para retornar tudo, inclusive o que foi deletado, use o método withTrashed()
User().withTrashed().get()
Utilize o método active(), para ativar um registro anteriormente deletado com softDelete. Este método só terá efeito utilizando o withTrashed().
User().where({"id":1}).withTrashed().active()
OBS: Não esqueça de sempre utilizar a clausula *where* quando for excluir registros.
Metadata
Release files for KassOrm 1.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kassorm-1.1.7.tar.gz | 17.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kassorm-1.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.4 kB
Release files / kassorm-1.1.7.tar.gz
| Download URL | kassorm-1.1.7.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3150bfe68e3f5067c4bfbf83243d2d585af9e424d9f6dee282eaea1cbf1b1eeb
|
|
BLAKE2b-256 checksum How to use checksums |
2fe4e3813f724d4a28cd08e8f2f93522b5a150f2f2a95f27a6ee2a732a5bd197
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.1 CPython/3.11.4 Windows/10
|
Release files / kassorm-1.1.7-py3-none-any.whl
| Download URL | kassorm-1.1.7-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2b890c83e99723e66051cbcca3bc38cb2bbedc344dd174e00d22a9fb085b084
|
|
BLAKE2b-256 checksum How to use checksums |
9e9f64ad4e1cc77c17e05997577dc005ed31ea492b3a97f17a7af34eb40f0e80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.1 CPython/3.11.4 Windows/10
|