Browse Source

Inicia simplificação

pull/1496/head
Marcio Mazza 8 years ago
parent
commit
1b5ee6cf22
  1. 179
      sapl/legacy/migration.py
  2. 7
      sapl/materia/models.py

179
sapl/legacy/migration.py

@ -12,7 +12,7 @@ from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import OperationalError, ProgrammingError, connections, models from django.db import OperationalError, ProgrammingError, connections, models
from django.db.models import CharField, Max, ProtectedError, TextField, Count from django.db.models import CharField, Count, Max, ProtectedError, TextField
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from model_mommy import mommy from model_mommy import mommy
@ -26,11 +26,11 @@ from sapl.materia.models import (AcompanhamentoMateria, DocumentoAcessorio,
StatusTramitacao, TipoDocumento, StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao, TipoMateriaLegislativa, TipoProposicao,
Tramitacao) Tramitacao)
from sapl.norma.models import (AssuntoNorma, NormaJuridica, from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoVinculoNormaJuridica, NormaRelacionada) TipoVinculoNormaJuridica)
from sapl.parlamentares.models import (Legislatura,Mandato, Parlamentar, from sapl.parlamentares.models import (Legislatura, Mandato, Parlamentar,
TipoAfastamento) TipoAfastamento)
from sapl.protocoloadm.models import (DocumentoAdministrativo,Protocolo, from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
StatusTramitacaoAdministrativo) StatusTramitacaoAdministrativo)
from sapl.sessao.models import ExpedienteMateria, OrdemDia, RegistroVotacao from sapl.sessao.models import ExpedienteMateria, OrdemDia, RegistroVotacao
from sapl.settings import PROJECT_DIR from sapl.settings import PROJECT_DIR
@ -119,63 +119,22 @@ def erro(msg):
print('ERRO: ' + msg) print('ERRO: ' + msg)
class ForeignKeyFaltando(ObjectDoesNotExist):
'Uma FK aponta para um registro inexistente'
pass
def get_fk_related(field, value, label=None): def get_fk_related(field, value, label=None):
if value is None and field.null is False: if value is None:
value = 0 return value
if value is not None: else:
try: try:
value = field.related_model.objects.get(id=value) return field.related_model.objects.get(id=value)
except ObjectDoesNotExist: except ObjectDoesNotExist as ex:
msg = 'FK [%s] não encontrada para valor %s ' \ msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % (
'(em %s %s)' % ( field.name, value, field.model.__name__, label or '---')
field.name, value, warn(msg)
field.model.__name__, label or '---') raise ForeignKeyFaltando(msg)
if value == 0:
if not field.null:
fields_dict = get_fields_dict(field.related_model)
# Cria stub ao final da tabela para evitar erros
pk = get_last_value(field.related_model)
with reversion.create_revision():
reversion.set_comment('Stub criado pela migração')
value = mommy.make(
field.related_model, **fields_dict,
pk=(pk + 1 or 1))
descricao = 'stub criado para campos não nuláveis!'
save_relation(value, [field.name], msg, descricao,
eh_stub=True)
warn(msg + ' => ' + descricao)
else:
value = None
else:
if field.model._meta.label == 'sessao.RegistroVotacao' and \
field.name == 'ordem':
return value
# Caso TipoProposicao não exista, um objeto será criado então
# com content_type=13 (ProblemaMigracao)
if field.related_model.__name__ == 'TipoProposicao':
tipo = TipoProposicao.objects.filter(descricao='Erro')
if not tipo:
with reversion.create_revision():
reversion.set_comment(
'TipoProposicao "Erro" criado')
ct = ContentType.objects.get(pk=13)
value = TipoProposicao.objects.create(
id=value, descricao='Erro', content_type=ct)
ultimo_valor = get_last_value(type(value))
alter_sequence(type(value), ultimo_valor+1)
else:
value = tipo[0]
else:
with reversion.create_revision():
reversion.set_comment('Stub criado pela migração')
value = make_stub(field.related_model, value)
descricao = 'stub criado para entrada orfã!'
warn(msg + ' => ' + descricao)
save_relation(value, [field.name], msg, descricao,
eh_stub=True)
else:
assert value
return value
def get_field(model, fieldname): def get_field(model, fieldname):
@ -252,7 +211,7 @@ def problema_duplicatas(model, lista_duplicatas, argumentos):
string_pks = "" string_pks = ""
problema = "%s de PK %s não é único." % (model.__name__, obj.pk) problema = "%s de PK %s não é único." % (model.__name__, obj.pk)
args_dict = {k: obj.__dict__[k] args_dict = {k: obj.__dict__[k]
for k in set(argumentos) & set(obj.__dict__.keys())} for k in set(argumentos) & set(obj.__dict__.keys())}
for dup in model.objects.filter(**args_dict): for dup in model.objects.filter(**args_dict):
pks.append(dup.pk) pks.append(dup.pk)
string_pks = "(" + ", ".join(map(str, pks)) + ")" string_pks = "(" + ", ".join(map(str, pks)) + ")"
@ -321,6 +280,7 @@ def recria_constraints():
(problema[0], problema[1])) (problema[0], problema[1]))
# TODO o que é isso? ####################################################
def obj_desnecessario(obj): def obj_desnecessario(obj):
relacoes = [ relacoes = [
f for f in obj._meta.get_fields() f for f in obj._meta.get_fields()
@ -335,7 +295,7 @@ def obj_desnecessario(obj):
def get_last_value(model): def get_last_value(model):
last_value = model.objects.all().aggregate(Max('pk')) last_value = model.objects.all().aggregate(Max('pk'))
return last_value['pk__max'] if last_value['pk__max'] else 0 return last_value['pk__max'] or 0
def alter_sequence(model, id): def alter_sequence(model, id):
@ -360,11 +320,11 @@ def save_relation(obj, nome_campo='', problema='', descricao='',
link.save() link.save()
# TODO NECESSÁRIO AINDA???????????
def make_stub(model, id): def make_stub(model, id):
fields_dict = get_fields_dict(model) fields_dict = get_fields_dict(model)
new = mommy.prepare(model, **fields_dict, pk=id) new = mommy.prepare(model, **fields_dict, pk=id)
save_with_id(new, id) save_with_id(new, id)
return new return new
@ -407,7 +367,7 @@ def fill_vinculo_norma_juridica():
'Julgada parcialmente inconstitucional')] 'Julgada parcialmente inconstitucional')]
lista_objs = [TipoVinculoNormaJuridica( lista_objs = [TipoVinculoNormaJuridica(
sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2]) sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2])
for item in lista] for item in lista]
TipoVinculoNormaJuridica.objects.bulk_create(lista_objs) TipoVinculoNormaJuridica.objects.bulk_create(lista_objs)
@ -452,8 +412,6 @@ class DataMigrator:
for field in new._meta.fields: for field in new._meta.fields:
old_field_name = renames.get(field.name) old_field_name = renames.get(field.name)
field_type = field.get_internal_type() field_type = field.get_internal_type()
msg = ("O valor do campo %s (%s) da model %s era inválido" %
(field.name, field_type, field.model.__name__))
if old_field_name: if old_field_name:
old_value = getattr(old, old_field_name) old_value = getattr(old, old_field_name)
if isinstance(field, models.ForeignKey): if isinstance(field, models.ForeignKey):
@ -466,38 +424,36 @@ class DataMigrator:
value = get_fk_related(field, old_value, label) value = get_fk_related(field, old_value, label)
else: else:
value = getattr(old, old_field_name) value = getattr(old, old_field_name)
# TODO rever esse DateField após as mudança para datas com
# timezone
if field_type == 'DateField' and \ if field_type == 'DateField' and \
not field.null and value is None: not field.null and value is None:
# TODO REVER ISSO
descricao = 'A data 1111-11-11 foi colocada no lugar' descricao = 'A data 1111-11-11 foi colocada no lugar'
problema = 'O valor da data era nulo ou inválido' problema = 'O valor da data era nulo ou inválido'
warn(msg + warn("O valor do campo %s (%s) do model %s "
' => ' + descricao) "era inválido => %s" % (
field.name, field_type,
field.model.__name__, descricao))
value = date(1111, 11, 11) value = date(1111, 11, 11)
self.data_mudada['obj'] = new self.data_mudada['obj'] = new
self.data_mudada['descricao'] = descricao self.data_mudada['descricao'] = descricao
self.data_mudada['problema'] = problema self.data_mudada['problema'] = problema
self.data_mudada.setdefault('nome_campo', []).\ self.data_mudada.setdefault('nome_campo', []).\
append(field.name) append(field.name)
if field_type == 'CharField' or field_type == 'TextField': if field_type in ['CharField', 'TextField'] \
if value is None or value == 'None': and value in [None, 'None']:
value = '' if value == 'None':
setattr(new, field.name, value) # TODO quero saber como é que pode ser 'None' !!!!
elif field.model.__name__ == 'TipoAutor' and \ import ipdb
field.name == 'content_type': ipdb.set_trace()
value = ''
model = normalize(new.descricao.lower()).replace(' ', '')
content_types = field.related_model.objects.filter(
model=model).exclude(app_label='legacy')
assert len(content_types) <= 1
value = content_types[0] if content_types else None
setattr(new, field.name, value) setattr(new, field.name, value)
def migrate(self, obj=appconfs, interativo=True): def migrate(self, obj=appconfs, interativo=True):
# warning: model/app migration order is of utmost importance # warning: model/app migration order is of utmost importance
exec_sql_file(PROJECT_DIR.child( exec_sql_file(PROJECT_DIR.child(
'sapl', 'legacy', 'scripts', 'fix_tables.sql'), 'legacy') 'sapl', 'legacy', 'scripts', 'fix_tables.sql'), 'legacy')
self.to_delete = []
# excluindo database antigo. # excluindo database antigo.
if interativo: if interativo:
@ -593,8 +549,17 @@ class DataMigrator:
# convert old records to new ones # convert old records to new ones
for old in old_records: for old in old_records:
if getattr(old, 'ind_excluido', False):
# não migramos registros marcados como excluídos
continue
new = model() new = model()
self.populate_renamed_fields(new, old) try:
self.populate_renamed_fields(new, old)
except ForeignKeyFaltando:
# tentamos preencher uma FK e o ojeto relacionado não existe
# então este é um objeo órfão: simplesmente ignoramos
continue
if ajuste_antes_salvar: if ajuste_antes_salvar:
ajuste_antes_salvar(new, old) ajuste_antes_salvar(new, old)
save(new, old) save(new, old)
@ -605,26 +570,10 @@ class DataMigrator:
save_relation(**self.data_mudada) save_relation(**self.data_mudada)
self.data_mudada.clear() self.data_mudada.clear()
reversion.set_comment('Ajuste de data pela migração') reversion.set_comment('Ajuste de data pela migração')
if getattr(old, 'ind_excluido', False):
self.to_delete.append(new)
# necessário para ajustar sequence da tabela para o ultimo valor de id # necessário para ajustar sequence da tabela para o ultimo valor de id
ultimo_valor = get_last_value(model) ultimo_valor = get_last_value(model)
alter_sequence(model, ultimo_valor+1) alter_sequence(model, ultimo_valor + 1)
def delete_ind_excluido(self):
excluidos = 0
for obj in self.to_delete:
if obj_desnecessario(obj):
try:
obj.delete()
except ProtectedError:
pass
else:
self.to_delete.remove(obj)
excluidos += 1
return excluidos
def delete_stubs(self): def delete_stubs(self):
excluidos = 0 excluidos = 0
@ -665,15 +614,15 @@ def adjust_documentoadministrativo(new, old):
except Exception: except Exception:
try: try:
protocolo = Protocolo.objects.get(numero=new.numero_protocolo, protocolo = Protocolo.objects.get(numero=new.numero_protocolo,
ano=new.ano+1) ano=new.ano + 1)
new.protocolo = protocolo new.protocolo = protocolo
except Exception: except Exception:
protocolo = mommy.make(Protocolo, numero=new.numero_protocolo, protocolo = mommy.make(Protocolo, numero=new.numero_protocolo,
ano=new.ano) ano=new.ano)
with reversion.create_revision(): with reversion.create_revision():
problema = 'Protocolo Vinculado [numero_protocolo=%s, '\ problema = 'Protocolo Vinculado [numero_protocolo=%s, '\
'ano=%s] não existe' % (new.numero_protocolo, 'ano=%s] não existe' % (new.numero_protocolo,
new.ano) new.ano)
descricao = 'O protocolo inexistente foi criado' descricao = 'O protocolo inexistente foi criado'
warn(problema + ' => ' + descricao) warn(problema + ' => ' + descricao)
save_relation(obj=protocolo, problema=problema, save_relation(obj=protocolo, problema=problema,
@ -751,7 +700,7 @@ def adjust_proposicao_antes_salvar(new, old):
def adjust_proposicao_depois_salvar(new, old): def adjust_proposicao_depois_salvar(new, old):
if not hasattr(old.dat_envio, 'year') or old.dat_envio.year == 1800: if not hasattr(old.dat_envio, 'year') or old.dat_envio.year == 1800:
msg = "O valor do campo data_envio (DateField) da model Proposicao"\ msg = "O valor do campo data_envio (DateField) da model Proposicao"\
" era inválido" " era inválido"
descricao = 'A data 1111-11-11 foi colocada no lugar' descricao = 'A data 1111-11-11 foi colocada no lugar'
problema = 'O valor da data era nulo ou inválido' problema = 'O valor da data era nulo ou inválido'
warn(msg + ' => ' + descricao) warn(msg + ' => ' + descricao)
@ -816,7 +765,6 @@ def adjust_tipoafastamento(new, old):
new.indicador = 'A' new.indicador = 'A'
def adjust_tipoproposicao(new, old): def adjust_tipoproposicao(new, old):
if old.ind_mat_ou_doc == 'M': if old.ind_mat_ou_doc == 'M':
new.tipo_conteudo_related = TipoMateriaLegislativa.objects.get( new.tipo_conteudo_related = TipoMateriaLegislativa.objects.get(
@ -844,6 +792,14 @@ def adjust_tramitacao(new, old):
new.turno = 'U' new.turno = 'U'
def adjust_tipo_autor(new, old):
model_apontado = normalize(new.descricao.lower()).replace(' ', '')
content_types = ContentType.objects.filter(
model=model_apontado).exclude(app_label='legacy')
assert len(content_types) <= 1
new.content_type = content_types[0] if content_types else None
def adjust_normajuridica_antes_salvar(new, old): def adjust_normajuridica_antes_salvar(new, old):
# Ajusta choice de esfera_federacao # Ajusta choice de esfera_federacao
# O 'S' vem de 'Selecionar'. Na versão antiga do SAPL, quando uma opção do # O 'S' vem de 'Selecionar'. Na versão antiga do SAPL, quando uma opção do
@ -870,7 +826,7 @@ def adjust_autor(new, old):
except Exception: except Exception:
with reversion.create_revision(): with reversion.create_revision():
msg = 'Um parlamentar relacionado de PK [%s] não existia' \ msg = 'Um parlamentar relacionado de PK [%s] não existia' \
% old.cod_parlamentar % old.cod_parlamentar
reversion.set_comment('Stub criado pela migração') reversion.set_comment('Stub criado pela migração')
value = make_stub(Parlamentar, old.cod_parlamentar) value = make_stub(Parlamentar, old.cod_parlamentar)
descricao = 'stub criado para entrada orfã!' descricao = 'stub criado para entrada orfã!'
@ -909,6 +865,7 @@ def adjust_comissao(new, old):
AJUSTE_ANTES_SALVAR = { AJUSTE_ANTES_SALVAR = {
Autor: adjust_autor, Autor: adjust_autor,
TipoAutor: adjust_tipo_autor,
AcompanhamentoMateria: adjust_acompanhamentomateria, AcompanhamentoMateria: adjust_acompanhamentomateria,
Comissao: adjust_comissao, Comissao: adjust_comissao,
DocumentoAdministrativo: adjust_documentoadministrativo, DocumentoAdministrativo: adjust_documentoadministrativo,
@ -939,15 +896,15 @@ AJUSTE_DEPOIS_SALVAR = {
# CHECKS #################################################################### # CHECKS ####################################################################
def get_ind_excluido(obj): def get_ind_excluido(new):
legacy_model = legacy_app.get_model(type(obj).__name__) legacy_model = legacy_app.get_model(type(new).__name__)
return getattr(legacy_model.objects.get( old = legacy_model.objects.get(**{legacy_model._meta.pk.name: new.id})
**{legacy_model._meta.pk.name: obj.id}), 'ind_excluido', False) return getattr(old, 'ind_excluido', False)
def check_app_no_ind_excluido(app): def check_app_no_ind_excluido(app):
for model in app.models.values(): for model in app.models.values():
assert not any(get_ind_excluido(obj) for obj in model.objects.all()) assert not any(get_ind_excluido(new) for new in model.objects.all())
print('OK!') print('OK!')
# MOMMY MAKE WITH LOG ###################################################### # MOMMY MAKE WITH LOG ######################################################

7
sapl/materia/models.py

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import reversion
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -8,7 +9,6 @@ from django.db import models
from django.utils import formats from django.utils import formats
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
import reversion
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
@ -19,7 +19,6 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SaplGenericForeignKey,
SaplGenericRelation, restringe_tipos_de_arquivo_txt, SaplGenericRelation, restringe_tipos_de_arquivo_txt,
texto_upload_path) texto_upload_path)
EM_TRAMITACAO = [(1, 'Sim'), EM_TRAMITACAO = [(1, 'Sim'),
(0, 'Não')] (0, 'Não')]
@ -620,6 +619,10 @@ class Proposicao(models.Model):
blank=True, blank=True,
on_delete=models.PROTECT) on_delete=models.PROTECT)
tipo = models.ForeignKey(TipoProposicao, on_delete=models.PROTECT, tipo = models.ForeignKey(TipoProposicao, on_delete=models.PROTECT,
# TODO PÓS MIGRACAO INICIAL (vide #1381)
# não nulo quando todas as
# bases tiverem sido corrigidas
null=True,
verbose_name=_('Tipo')) verbose_name=_('Tipo'))
# XXX data_envio was not null, but actual data said otherwise!!! # XXX data_envio was not null, but actual data said otherwise!!!

Loading…
Cancel
Save