Browse Source

Melhora desempenho da migracao

pull/1477/head
Marcio Mazza 7 years ago
parent
commit
ac03224316
  1. 125
      sapl/legacy/migration.py

125
sapl/legacy/migration.py

@ -1,5 +1,6 @@
import re import re
from datetime import date from datetime import date
from functools import lru_cache
from subprocess import PIPE, call from subprocess import PIPE, call
import pkg_resources import pkg_resources
@ -11,7 +12,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group 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 ProgrammingError, connections, models from django.db import ProgrammingError, connections, models, transaction
from django.db.models import CharField, Count, Max, TextField from django.db.models import CharField, Count, Max, TextField
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from model_mommy import mommy from model_mommy import mommy
@ -122,17 +123,24 @@ class ForeignKeyFaltando(ObjectDoesNotExist):
pass pass
@lru_cache()
def _get_all_ids_from_model(model):
# esta função para uso apenas em get_fk_related
return set(model.objects.values_list('id', flat=True))
def get_fk_related(field, value, label=None): def get_fk_related(field, value, label=None):
if value is None and field.null: if value is None and field.null:
return None
# if field.related_model.objects.filter(id=value).exists():
if value in _get_all_ids_from_model(field.related_model):
return value return value
else: else:
try: msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % (
return field.related_model.objects.get(id=value) field.name, value, field.model.__name__, label or '---')
except ObjectDoesNotExist as ex: warn(msg)
msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( raise ForeignKeyFaltando(msg)
field.name, value, field.model.__name__, label or '---')
warn(msg)
raise ForeignKeyFaltando(msg)
def get_field(model, fieldname): def get_field(model, fieldname):
@ -410,37 +418,39 @@ class DataMigrator:
field_type = field.get_internal_type() field_type = field.get_internal_type()
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):
old_type = type(old) # not necessarily a model if field_type == 'ForeignKey':
if hasattr(old_type, '_meta') and \ # not necessarily a model
old_type._meta.pk.name != 'id': if hasattr(old, '_meta') and old._meta.pk.name != 'id':
label = old.pk label = old.pk
else: else:
label = '-- SEM PK --' label = '-- SEM PK --'
fk_field_name = '{}_id'.format(field.name)
value = get_fk_related(field, old_value, label) value = get_fk_related(field, old_value, label)
setattr(new, fk_field_name, value)
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 # TODO rever esse DateField após as mudança para datas com
# timezone # 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 # 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("O valor do campo %s (%s) do model %s " warn("O valor do campo %s (%s) do model %s "
"era inválido => %s" % ( "era inválido => %s" % (
field.name, field_type, field.name, field_type,
field.model.__name__, descricao)) 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 in ['CharField', 'TextField'] if (field_type in ['CharField', 'TextField']
and value in [None, 'None']): and value in [None, 'None']):
value = '' value = ''
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
@ -527,29 +537,32 @@ class DataMigrator:
ajuste_depois_salvar = AJUSTE_DEPOIS_SALVAR.get(model) ajuste_depois_salvar = AJUSTE_DEPOIS_SALVAR.get(model)
# convert old records to new ones # convert old records to new ones
for old in old_records: with transaction.atomic():
if getattr(old, 'ind_excluido', False): for old in old_records:
# não migramos registros marcados como excluídos if getattr(old, 'ind_excluido', False):
continue # não migramos registros marcados como excluídos
new = model() continue
try: new = model()
self.populate_renamed_fields(new, old) try:
if ajuste_antes_salvar: self.populate_renamed_fields(new, old)
ajuste_antes_salvar(new, old) if ajuste_antes_salvar:
except ForeignKeyFaltando: ajuste_antes_salvar(new, old)
# tentamos preencher uma FK e o ojeto relacionado não existe except ForeignKeyFaltando:
# então este é um objeo órfão: simplesmente ignoramos # tentamos preencher uma FK e o ojeto relacionado
continue # não existe
else: # então este é um objeo órfão: simplesmente ignoramos
save(new, old) continue
if ajuste_depois_salvar: else:
ajuste_depois_salvar(new, old) save(new, old)
if ajuste_depois_salvar:
ajuste_depois_salvar(new, old)
if self.data_mudada: if self.data_mudada:
with reversion.create_revision(): with reversion.create_revision():
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')
# 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)
@ -650,7 +663,7 @@ def adjust_parlamentar(new, old):
def adjust_participacao(new, old): def adjust_participacao(new, old):
composicao = Composicao() composicao = Composicao()
composicao.comissao, composicao.periodo = [ composicao.comissao_id, composicao.periodo_id = [
get_fk_related(Composicao._meta.get_field(name), value) get_fk_related(Composicao._meta.get_field(name), value)
for name, value in (('comissao', old.cod_comissao), for name, value in (('comissao', old.cod_comissao),
('periodo', old.cod_periodo_comp))] ('periodo', old.cod_periodo_comp))]

Loading…
Cancel
Save