| Version 1 (modified by gustavo.fonseca, 22 months ago) |
|---|
Django-Fossil no OpenTrials
O django-fossil foi criado para atender primariamente ao OpenTrials, mas tomamos os cuidados para deixá-lo agnóstico a outros projetos. repository.serializers
O núcleo do uso do django-fossil no OpenTrials está no modulo repository.serializers, onde estão as funções de serialização e deserialização chamadas nas classes de modelo e managers do modulo repository.models. Apesar de estarem prontas, as funções "deserialize_" não são usadas efetivamente no OpenTrials devido às características do projeto, pois a deserialização que importa é feita para XML, com validação via DTD, etc. Outro motivo para isso é que no OpenTrials existe apenas um registro principal serializado, que é o ensaio clínico (classe repository.ClinicalTrial?) e nele estão contidos todos os objetos dos quais ele depende. Isso tem um pequeno conflito com a ideia de deserialização do django-fossil, que trabalha separado por entidade. repository.xml
Portanto, o outro pacote importante nesse processo é o repository.xml, especialmente os pacotes "validate", "generate" e "import". respository.xml.validate
Contém o método "validate_xml(filename_or_xmltree, dtd='opentrials.dtd')", responsável pela validação, usando DTD. respository.xml.generate
Contém funções para geração do XML de ensaios clínicos nos formatos WHO ICTRP "xml_ictrp(trial)" e OpenTrialsXML "xml_opentrials(trial, persons, include_translations=True)". Tem ainda a função "xml_opentrials_mod()" para gerar o arquivo de vocabulários "opentrials-vocabularies.mod" respository.xml.loading
Contém a classe OpenTrialsXMLImport, que é usada tanto para a importação de arquivos no formato WHO ICTRP quanto OpenTrials XML. A lógica de funcionamento dessa classe segue a seguinte ordem:
1. Criação da instância, recebendo o usuário "creator" desta importação. Ele será atribuído como "criador" para novos objetos de Contact ou Institution.
Exemplo:
from repository.xml.loading import OpenTrialsXMLImport imp = OpenTrialsXMLImport(creator=request.user)
2. Carregamento de uma instância de etree - classe raiz da biblioteca lxml - contendo o XML a importar.
Exemplo:
from repository.xml.loading import etree
tree = etree.parse('caminho_do_arquivo.xml')
3. Validação do etree, usando a função repository.xml.validate.validate_xml.
Exemplo:
from repository.xml.validate import validate_xml
from repository.xml.validate import InvalidOpenTrialsXML
from repository.xml.validate import ICTRP_DTD, DEFAULT_DTD
try:
validate_xml(tree)
xml_format = 'opentrials'
except InvalidOpenTrialsXML:
try:
validate_xml(tree, dtd=ICTRP_DTD)
xml_format = 'ictrp'
except InvalidOpenTrialsXML:
raise forms.ValidationError('Invalid file')
4. Chamada de um dos dois métodos de carregamento do XML: "parse_opentrials" ou "parse_ictrp". Ambos recebem a instância de etree como argumento. Esse carregamento ainda não efetiva a persistência dos ensaios, pois este é um momento oportuno para verificar se tais ensaios existem e confirmar a importação deles com o usuário;
Exemplo:
if xml_format == 'opentrials':
imp.parse_opentrials(tree)
else:
imp.parse_ictrp(tree)
5. Importação de fato, usando o método import_parsed, que recebe o argumento if_exists, sendo que este pode receber uma de três opções: UPDATE_IF_EXISTS - atualiza os ensaios existentes, e no caso dos campos não informados, mantém como estão; REPLACE_IF_EXISTS - substitui os ensaios existentes, ou seja, os campos não informados no XML receberão seus valores default; SKIP_IF_EXISTS - salto os ensaios existentes, ou seja, não faz nada com eles.
Exemplo:
imp.import_parsed(if_exists=REPLACE_IF_EXISTS)
O método "import_parsed" pode ser chamado independentemente dos demais, mas para isso, ele espera que exista um atributo "_parsed_trials" na classe, que é criado pelos métodos "parse_opentrials" e "parse_ictrp". Portanto, no OpenTrials, nosso formulário de importação guarda o valor desse atributo na sessão, para que o usuário possa visualizar os ensaios que foram carregados e marcar aqueles que deseja importar de fato.
Há ainda outro meio mais prático para fazer o parsing (carregamento) e importação em um mesmo momento, que é usar os métodos "import_opentrials(filename_or_xmltree, if_exists)" ou "import_ictrp(filename_or_xmltree, if_exists)"
Todo o procedimento acima pode ser conferido nos módulos reviewapp.views e reviewapp.forms, onde estão respectivamente a view e os forms usados para o upload de arquivos XML com ensaios. Classes FossilClinicalTrial? e FossilContact?
Como já citamos, a implementação do django-fossil no OpenTrials usa o máximo do que ele pode oferecer, e um desses recursos é o de customizar o objeto de proxy que será retornado quando um fossil for carregado e lido. É para isso que existem as classes FossilClinicalTrial? e FossilContact?, do módulo repository.serializers. Ambas trabalham retornando valores para os atributos requisitados e tratando alguns deles, especialmente no aspecto das traduções.
