106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
|
|
import os
|
||
|
|
import time
|
||
|
|
from django.core.files import File
|
||
|
|
from django.core.management.base import BaseCommand
|
||
|
|
from diarios.models import DiarioOficial
|
||
|
|
from diarios.signals import update_document, delete_document
|
||
|
|
from django.db.models.signals import post_save, post_delete
|
||
|
|
|
||
|
|
|
||
|
|
class Command(BaseCommand):
|
||
|
|
help = "Importa arquivos PDF de diários oficiais e associa aos objetos existentes no banco."
|
||
|
|
|
||
|
|
def add_arguments(self, parser):
|
||
|
|
parser.add_argument(
|
||
|
|
"pasta",
|
||
|
|
type=str,
|
||
|
|
help="Caminho para a pasta contendo os arquivos PDF (nomes devem conter o número do diário)",
|
||
|
|
)
|
||
|
|
|
||
|
|
def handle(self, *args, **options):
|
||
|
|
post_save.disconnect(update_document, sender=DiarioOficial)
|
||
|
|
post_delete.disconnect(delete_document, sender=DiarioOficial)
|
||
|
|
|
||
|
|
pasta = options["pasta"]
|
||
|
|
if not os.path.isdir(pasta):
|
||
|
|
self.stderr.write(
|
||
|
|
self.style.ERROR(f"A pasta fornecida não existe: {pasta}")
|
||
|
|
)
|
||
|
|
return
|
||
|
|
|
||
|
|
arquivos_pdf = [
|
||
|
|
f
|
||
|
|
for f in os.listdir(pasta)
|
||
|
|
if f.lower().endswith(".pdf") and "Diário_Oficial_Eletrônico_nº_" in f
|
||
|
|
]
|
||
|
|
|
||
|
|
if not arquivos_pdf:
|
||
|
|
self.stdout.write(
|
||
|
|
self.style.WARNING("Nenhum arquivo PDF válido encontrado na pasta.")
|
||
|
|
)
|
||
|
|
return
|
||
|
|
|
||
|
|
total = len(arquivos_pdf)
|
||
|
|
erros = []
|
||
|
|
atualizados = []
|
||
|
|
start_time = time.time()
|
||
|
|
|
||
|
|
# Mapeia os números aos nomes de arquivos
|
||
|
|
numero_para_arquivo = {
|
||
|
|
f.replace("Diário_Oficial_Eletrônico_nº_", "")
|
||
|
|
.replace(".pdf", "")
|
||
|
|
.strip("_-"): f
|
||
|
|
for f in arquivos_pdf
|
||
|
|
}
|
||
|
|
|
||
|
|
# Busca todos os objetos de uma vez
|
||
|
|
diarios_existentes = DiarioOficial.objects.in_bulk(
|
||
|
|
numero_para_arquivo.keys(), field_name="numero"
|
||
|
|
)
|
||
|
|
|
||
|
|
for idx, (numero, nome_arquivo) in enumerate(
|
||
|
|
numero_para_arquivo.items(), start=1
|
||
|
|
):
|
||
|
|
try:
|
||
|
|
diario = diarios_existentes.get(numero)
|
||
|
|
if not diario:
|
||
|
|
raise DiarioOficial.DoesNotExist()
|
||
|
|
|
||
|
|
caminho_pdf = os.path.join(pasta, nome_arquivo)
|
||
|
|
with open(caminho_pdf, "rb") as f:
|
||
|
|
diario.arquivo.save(nome_arquivo, File(f), save=True)
|
||
|
|
|
||
|
|
atualizados.append(diario.pk)
|
||
|
|
elapsed = time.time() - start_time
|
||
|
|
remaining = (elapsed / idx) * (total - idx)
|
||
|
|
self.stdout.write(
|
||
|
|
f"[{idx}/{total}] Atualizado: {nome_arquivo} | Estimativa restante: {remaining:.1f}s"
|
||
|
|
)
|
||
|
|
|
||
|
|
except DiarioOficial.DoesNotExist:
|
||
|
|
msg = f"Não encontrado no banco: {nome_arquivo}"
|
||
|
|
erros.append(msg)
|
||
|
|
self.stderr.write(self.style.WARNING(msg))
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
msg = f"Erro ao processar {nome_arquivo}: {str(e)}"
|
||
|
|
erros.append(msg)
|
||
|
|
self.stderr.write(self.style.ERROR(msg))
|
||
|
|
|
||
|
|
self.stdout.write(
|
||
|
|
self.style.SUCCESS(f"{len(atualizados)} arquivos importados com sucesso.")
|
||
|
|
)
|
||
|
|
self.stdout.write(self.style.WARNING(f"{len(erros)} arquivos com erro."))
|
||
|
|
|
||
|
|
if erros:
|
||
|
|
caminho_log = os.path.join(pasta, "erros_importacao.txt")
|
||
|
|
with open(caminho_log, "w", encoding="utf-8") as erro_file:
|
||
|
|
for linha in erros:
|
||
|
|
erro_file.write(f"{linha}\n")
|
||
|
|
self.stdout.write(
|
||
|
|
self.style.WARNING(f"Erros registrados em: {caminho_log}")
|
||
|
|
)
|
||
|
|
|
||
|
|
post_save.connect(update_document, sender=DiarioOficial)
|
||
|
|
post_delete.connect(delete_document, sender=DiarioOficial)
|