Browse Source

Migra conteudo_gerado_related de Proposicao

pull/1847/head
Marcio Mazza 7 years ago
parent
commit
901c0ec043
  1. 140
      sapl/legacy/migracao_dados.py
  2. 4
      sapl/materia/models.py

140
sapl/legacy/migracao_dados.py

@ -1,6 +1,6 @@
import re
import traceback
from collections import OrderedDict, defaultdict
from collections import OrderedDict, defaultdict, namedtuple
from datetime import date
from functools import lru_cache, partial
from itertools import groupby
@ -8,18 +8,16 @@ from operator import xor
from subprocess import PIPE, call
import pkg_resources
import pytz
import reversion
import yaml
from django.apps import apps
from django.apps.config import AppConfig
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import connections, transaction
from django.db.models import Max, Q
from django.db.models.base import ModelBase
from pytz import timezone
from unipath import Path
from sapl.base.models import AppConfig as AppConf
@ -27,8 +25,8 @@ from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy.models import NormaJuridica as OldNormaJuridica
from sapl.legacy.models import TipoNumeracaoProtocolo
from sapl.materia.models import (AcompanhamentoMateria, Proposicao,
StatusTramitacao, TipoDocumento,
from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao,
Tramitacao)
from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada,
@ -117,12 +115,31 @@ models_novos_para_antigos = {
for model in field_renames}
models_novos_para_antigos[Composicao] = models_novos_para_antigos[Participacao]
content_types = {model: ContentType.objects.get(
app_label=model._meta.app_label, model=model._meta.model_name)
for model in field_renames}
campos_novos_para_antigos = {
model._meta.get_field(nome_novo): nome_antigo
for model, renames in field_renames.items()
for nome_novo, nome_antigo in renames.items()}
# campos de Composicao (de Comissao)
for nome_novo, nome_antigo in (('comissao', 'cod_comissao'),
('periodo', 'cod_periodo_comp')):
campos_novos_para_antigos[
Composicao._meta.get_field(nome_novo)] = nome_antigo
# campos virtuais de Proposicao para funcionarem com get_fk_related
CampoFalso = namedtuple('CampoFalso', ['model', 'related_model'])
CAMPOS_FALSOS_PROPOSICAO = {
TipoMateriaLegislativa: CampoFalso(Proposicao, MateriaLegislativa),
TipoDocumento: CampoFalso(Proposicao, DocumentoAdministrativo)
}
for campo_falso in CAMPOS_FALSOS_PROPOSICAO.values():
campos_novos_para_antigos[campo_falso] = 'cod_mat_ou_doc'
# MIGRATION #################################################################
@ -168,10 +185,14 @@ class ForeignKeyFaltando(ObjectDoesNotExist):
campo = campos_novos_para_antigos[self.field]
_, tabela, campos_pk = get_estrutura_legado(self.field.model)
pk = {c: getattr(self.old, c) for c in campos_pk}
sql = 'select * from {} where {}'.format(
tabela,
' and '.join(['{} = {}'.format(k, v) for k, v in pk.items()]))
return OrderedDict((('campo', campo),
('valor', self.valor),
('tabela', tabela),
('pk', pk)))
('pk', pk),
('sql', sql)))
@lru_cache()
@ -180,8 +201,8 @@ def _get_all_ids_from_model(model):
return set(model.objects.values_list('id', flat=True))
def get_fk_related(field, old, old_field_name):
valor = getattr(old, old_field_name)
def get_fk_related(field, old):
valor = getattr(old, campos_novos_para_antigos[field])
if valor is None and field.null:
return None
if valor in _get_all_ids_from_model(field.related_model):
@ -679,24 +700,20 @@ def dict_representer(dumper, data):
yaml.add_representer(OrderedDict, dict_representer)
class DataMigrator:
def __init__(self):
self.choice_valida = {}
# configura timezone de migração
self.nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', self.nome_banco_legado)
nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', nome_banco_legado)
sigla_casa = match.group(1)
with open(PATH_TABELA_TIMEZONES, 'r') as arq:
tabela_timezones = yaml.load(arq)
municipio, uf, nome_timezone = tabela_timezones[sigla_casa]
if nome_timezone:
self.timezone = timezone(nome_timezone)
timezone = pytz.timezone(nome_timezone)
else:
self.timezone = get_timezone(municipio, uf)
timezone = get_timezone(municipio, uf)
def populate_renamed_fields(self, new, old):
def populate_renamed_fields(new, old):
renames = field_renames[type(new)]
for field in new._meta.fields:
@ -706,7 +723,7 @@ class DataMigrator:
if field_type == 'ForeignKey':
fk_field_name = '{}_id'.format(field.name)
value = get_fk_related(field, old, old_field_name)
value = get_fk_related(field, old)
setattr(new, fk_field_name, value)
else:
value = getattr(old, old_field_name)
@ -722,15 +739,14 @@ class DataMigrator:
return (field_type == tipo
and value and not value.tzinfo)
if campo_tempo_sem_timezone('DateTimeField'):
value = self.timezone.localize(value)
value = timezone.localize(value)
if campo_tempo_sem_timezone('TimeField'):
value = value.replace(tzinfo=self.timezone)
value = value.replace(tzinfo=timezone)
setattr(new, field.name, value)
def migrar(self, obj=appconfs, interativo=True):
# warning: model/app migration order is of utmost importance
def migrar_dados(interativo=True):
uniformiza_banco()
# excluindo database antigo.
@ -754,19 +770,19 @@ class DataMigrator:
fill_vinculo_norma_juridica()
fill_dados_basicos()
info('Começando migração: %s...' % obj)
info('Começando migração: ...')
try:
ocorrencias.clear()
dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat())
dir_ocorrencias.mkdir(parents=True)
self._do_migrate(obj)
migrar_todos_os_models()
except Exception as e:
ocorrencias['traceback'] = str(traceback.format_exc())
raise e
finally:
# grava ocorrências
arq_ocorrencias = dir_ocorrencias.child(
self.nome_banco_legado + '.yaml')
nome_banco_legado + '.yaml')
with open(arq_ocorrencias, 'w') as arq:
dump = yaml.dump(dict(ocorrencias), allow_unicode=True)
arq.write(dump.replace('\n- ', '\n\n- '))
@ -775,34 +791,33 @@ class DataMigrator:
# recria tipos de autor padrão que não foram criados pela migração
cria_models_tipo_autor()
def _do_migrate(self, obj):
if isinstance(obj, AppConfig):
models = [model for model in obj.models.values()
if model in field_renames]
if obj.label == 'materia':
def move_para_depois_de(lista, movido, referencias):
indice_inicial = lista.index(movido)
lista.remove(movido)
indice_apos_refs = max(lista.index(r) for r in referencias) + 1
lista.insert(max(indice_inicial, indice_apos_refs), movido)
return lista
def migrar_todos_os_models():
models = [model for app in appconfs for model in app.models.values()
if model in field_renames]
# Devido à referência TipoProposicao.tipo_conteudo_related
# a migração de TipoProposicao precisa ser feita
# após TipoMateriaLegislativa e TipoDocumento
# (porém antes de Proposicao)
models.remove(TipoProposicao)
pos_tipo_proposicao = max(
models.index(TipoMateriaLegislativa),
models.index(TipoDocumento)) + 1
models.insert(pos_tipo_proposicao, TipoProposicao)
move_para_depois_de(models, TipoProposicao,
[TipoMateriaLegislativa, TipoDocumento])
assert models.index(TipoProposicao) < models.index(Proposicao)
move_para_depois_de(models, Proposicao,
[MateriaLegislativa, DocumentoAdministrativo])
self._do_migrate(models)
elif isinstance(obj, ModelBase):
self.migrate_model(obj)
elif hasattr(obj, '__iter__'):
for item in obj:
self._do_migrate(item)
else:
raise TypeError(
'Parameter must be a Model, AppConfig or a sequence of them')
for model in models:
migrar_model(model)
def migrate_model(self, model):
def migrar_model(model):
print('Migrando %s...' % model.__name__)
model_legado, tabela_legado, campos_pk_legado = \
@ -836,7 +851,7 @@ class DataMigrator:
for old in old_records:
new = model()
try:
self.populate_renamed_fields(new, old)
populate_renamed_fields(new, old)
if ajuste_antes_salvar:
ajuste_antes_salvar(new, old)
except ForeignKeyFaltando as e:
@ -878,11 +893,6 @@ class DataMigrator:
exec_legado(sql_delete_legado)
def migrar_dados(obj=appconfs, interativo=True):
dm = DataMigrator()
dm.migrar(obj, interativo)
# MIGRATION_ADJUSTMENTS #####################################################
def adjust_acompanhamentomateria(new, old):
@ -993,9 +1003,8 @@ def adjust_parlamentar(new, old):
def adjust_participacao(new, old):
comissao_id, periodo_id = [
get_fk_related(Composicao._meta.get_field(name), old, old_field_name)
for name, old_field_name in (('comissao', 'cod_comissao'),
('periodo', 'cod_periodo_comp'))]
get_fk_related(Composicao._meta.get_field(name), old)
for name in ('comissao', 'periodo')]
with reversion.create_revision():
composicao, _ = Composicao.objects.get_or_create(
comissao_id=comissao_id, periodo_id=periodo_id)
@ -1003,11 +1012,6 @@ def adjust_participacao(new, old):
new.composicao = composicao
def adjust_proposicao_antes_salvar(new, old):
if new.data_envio:
new.ano = new.data_envio.year
def adjust_normarelacionada(new, old):
new.tipo_vinculo = TipoVinculoNormaJuridica.objects.get(
sigla=old.tip_vinculo)
@ -1042,14 +1046,14 @@ def adjust_tipoafastamento(new, old):
new.indicador = 'F'
MODEL_TIPO_MATERIA_OU_DOCUMENTO = {'M': TipoMateriaLegislativa,
TIPO_MATERIA_OU_TIPO_DOCUMENTO = {'M': TipoMateriaLegislativa,
'D': TipoDocumento}
def adjust_tipoproposicao(new, old):
"Aponta para o tipo relacionado de matéria ou documento"
value = old.tip_mat_ou_doc
model_tipo = MODEL_TIPO_MATERIA_OU_DOCUMENTO[old.ind_mat_ou_doc]
model_tipo = TIPO_MATERIA_OU_TIPO_DOCUMENTO[old.ind_mat_ou_doc]
tipo = model_tipo.objects.filter(pk=value)
if tipo:
new.tipo_conteudo_related = tipo[0]
@ -1060,6 +1064,16 @@ def adjust_tipoproposicao(new, old):
label={'ind_mat_ou_doc': old.ind_mat_ou_doc})
def adjust_proposicao_antes_salvar(new, old):
if new.data_envio:
new.ano = new.data_envio.year
if old.cod_mat_ou_doc:
tipo_mat_ou_doc = type(new.tipo.tipo_conteudo_related)
campo_falso = CAMPOS_FALSOS_PROPOSICAO[tipo_mat_ou_doc]
new.content_type = content_types[campo_falso.related_model]
new.object_id = get_fk_related(campo_falso, old)
def adjust_statustramitacao(new, old):
if old.ind_fim_tramitacao:
new.indicador = 'F'

4
sapl/materia/models.py

@ -686,16 +686,12 @@ class Proposicao(models.Model):
texto_articulado = GenericRelation(
TextoArticulado, related_query_name='texto_articulado')
# FIXME - para a rotina de migração - este campo mudou
# retire o comentário quando resolver
materia_de_vinculo = models.ForeignKey(
MateriaLegislativa, blank=True, null=True,
on_delete=models.CASCADE,
verbose_name=_('Matéria anexadora'),
related_name=_('proposicao_set'))
# FIXME - para a rotina de migração - estes campos mudaram
# retire o comentário quando resolver
content_type = models.ForeignKey(
ContentType, default=None, blank=True, null=True,
verbose_name=_('Tipo de Material Gerado'))

Loading…
Cancel
Save