implementação de

28
Implementação de Acesso a múltiplos Bancos de dados no Django. Rômulo Jales - [email protected]

Upload: romulo-jales

Post on 19-Jun-2015

601 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Implementação de

Implementação de Acesso a múltiplos Bancos de dados no Django.

Rômulo Jales - [email protected]

Page 2: Implementação de

Agenda

● O que é Django?● Um rápido Tutorial

● A necessidade● A solução

Page 3: Implementação de

O que é Django?

● Um framework web de alto nível● Escrito em Python● Estimula o desenvolvimento rápido e limpo● Implementa o conceito DRY

“Um framework para perfeccionistas com deadlines”

Page 4: Implementação de

O que é django?

Page 5: Implementação de

Um rápido tutorial

● Crie um projeto:● django-admin startproject NOME_PRJ● São criados 4 arquivos:

– __init__.py– settings.py– manage.py– urls.py

Page 6: Implementação de

Um rápido tutorial

● settings.py● Armazena as configurações do serviço● O banco de dados é configurado aqui!

● urls.py● Realiza o roteamento das urls para os métodos e

recursos

● manager.py● Gerenciador local do django.

Page 7: Implementação de

Um rápido tutorial

● ./manager startapp NOME_DA_APP● São criados 4 arquivos

– init.py – models.py– view.py– tests.py

Page 8: Implementação de

Um rápido tutorial

● models.py → acesso aos dados● views.py → Tratamento das requisições da

aplicação.

Page 9: Implementação de

Um rápido tutorial

● Código para models.py

from django.db import models

class Artigo(models.Model):

titulo = models.CharField(max_length=100)

conteudo = models.TextField()

publicacao = models.DateTimeField()

Page 10: Implementação de

Um rápido tutorial

● Crie um arquivo chamado admin.py

from django.contrib import admin

from models import Artigo

admin.site.register(Artigo)

● Edite a urls.py

(r'^$', 'django.views.generic.date_based.archive_index',

{'queryset': Artigo.objects.all(), 'date_field': 'publicacao'}),

(r'^admin/(.*)', admin.site.root),

Page 11: Implementação de

Um rápido tutorial

Page 12: Implementação de

Um rápido tutorial

● Sincronize o banco.● ./manager syncdb

Page 13: Implementação de

Um rápido tutorial

Page 14: Implementação de

Quem usa o django?

● globo.com● washingtonpost.com● E outros 3575 cadastrados no

http://www.djangosites.org/!

Page 15: Implementação de

A necessidade

● Acessar vários banco de dados usando a versão em produção 1.1 do cliente.

Page 16: Implementação de

A necessidade

● Solução de acesso atual (na view.py)

mssql = _mssql.connect('IP_DO_SERVER','linux','SENHA')

query = "SELECT OP FROM CONSULTA_OP WHERE NUMEROSERIE = '"+serial+"'"

mssql.query(query)

Page 17: Implementação de

A necessidade

● Solução quebra a arquitetura!!!!!!● Não é DRY!● Não é simples!● Se o IP do banco mudar?● Se o backend do banco mudar?

Page 18: Implementação de

A solução

● Premissas e restrições:● Não pode mudar o que já funciona!● Usar o conceito de DRY● Funcionar com todos os backends nativos do

Django (mysql, postgres, sqlite3) e o **SQL SERVER**

Page 19: Implementação de

A solução - análise

connection = backend.DatabaseWrapper({

‘DATABASE_HOST’: settings.DATABASE_HOST,

‘DATABASE_NAME’: settings.DATABASE_NAME,

‘DATABASE_OPTIONS’: settings.DATABASE_OPTIONS,

‘DATABASE_PASSWORD’: settings.DATABASE_PASSWORD,

‘DATABASE_PORT’: settings.DATABASE_PORT,

‘DATABASE_USER’: settings.DATABASE_USER,

‘TIME_ZONE’: settings.TIME_ZONE,

})

Page 20: Implementação de

A solução - análise

● Models● Tem um atributo _default_manager (Manager)

● Manager● Tem um método central get_query_set (QuerySet).

Método que acessa o backend

● QuerySet● Tem um atributo query do tipo Query, que é

instancia de DataBaseWrapper, que é uma classe abstrata definida pela parametrização contida em settings.py

Page 21: Implementação de

A solução

● Permitir indexação dos parâmetros DATABASE_*● Modificar a classe QuerySet!!

Page 22: Implementação de

A soluçãofrom django.db.models import sqlfrom django.db.models.sql.where import WhereNodefrom utils import getConnection

class MultiBdQuery(sql.Query): def __init__(self, model, banco): self.banco = banco self.connection = getConnection(self.banco) super(MultiBdQuery, self).__init__(model, self.connection, WhereNode) def __setstate__(self, obj_dict): obj_dict['select_fields'] = [ name is not None and obj_dict['model']._meta.get_field(name) or None for name in obj_dict['select_fields'] ] self.__dict__.update(obj_dict) self.connection = getConnection(self.banco)

Page 23: Implementação de

A soluçãofrom django.conf import settingsfrom django.db import load_backend

def getConnection(banco): engine = settings.SECONDARY_DB[banco]['DATABASE_ENGINE'] if engine == "sql_server.pyodbc": backend = __import__(engine+'.base', {}, {}, ['base']) else: backend = load_backend(engine) return backend.DatabaseWrapper(settings.SECONDARY_DB[banco])

Page 24: Implementação de

A soluçãofrom django.db.models import sqlfrom django.db.models.manager import Managerfrom django.db.models.query import QuerySetfrom query import MultiBdQuery

class MultiBdManager(Manager):

use_for_related_fields = True def __init__(self, banco, *args, **kwargs): super(MultiBdManager, self).__init__(*args, **kwargs) self.banco = banco def get_query_set(self): #Obtem um novo query a partir das configuracoes de banco query = MultiBdQuery(self.model, self.banco) return QuerySet(self.model, query)

Page 25: Implementação de

A solução – visão do usuário

● Adicionar no settings.py um dicionário chamadoSECONDARY_DB contendo as configurações dos outros bancos

● Novos modelos● Modificar o Manager padrão, passando o nome do

banco de qual a classe está associada.

Page 26: Implementação de

Correção da gambiarra - antes

def get_op_from_scf(serial): import _mssql

mssql = _mssql.connect('IP_DO_SERVER','linux','SENHA')

query = "SELECT OP FROM CONSULTA_OP WHERE NUMEROSERIE = '"+serial+"'"

mssql.query(query) ret = mssql.fetch_array()

If ret[0][1] == 0: raise Exception("Nao existe nenhuma OP para o numero de serie informado: " + str(serial))

op = ret[0][2][0][0]

return op.strip()

Page 27: Implementação de

Correção da gambiarra - depois

class OPLEGADO(Model): class Meta: db_table = "CONSULTA_OP" managed = False _default_manager = MultiBdManager("scf") op = CharField(max_length=13,primary_key=True) numeroserie = CharField(max_length=26)

def get_op_from_scf(serial):op = OPLEGADO.objects.get(numeroserie=serial)If op:

return opelse:

raise Exception(“"Nao existe nenhuma OP para o numero de serie informado: " + str(serial))

Page 28: Implementação de

Limitações

● Não sincroniza todos os bancos simultaneamente!

● Inicialização mais demorada● Funciona apenas para versões >= 1.1 do

Django.