.. crate_anon/docs/source/website_using/archive.rst .. Copyright (C) 2015, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk). . This file is part of CRATE. . CRATE is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. . CRATE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with CRATE. If not, see . .. _CamCOPS: https://camcops.readthedocs.io/ .. _Django: https://docs.djangoproject.com/ .. _Django-Mako-Plus: http://doconix.github.io/django-mako-plus/index.html; .. _Mako: https://www.makotemplates.org/ .. _Mako Runtime Environment: https://docs.makotemplates.org/en/latest/runtime.html .. _Other template engines: https://wiki.python.org/moin/Templating#Templating_Engines .. _archive: Archive view ------------ Background ~~~~~~~~~~ This view provides an "archive" (read-only) view of an electronic health record (EHR). It has two potential purposes: - to provide a useful, configurable way in which researchers can explore the anonymised EHR of a single patient; - to act as an archive view onto an identifiable EHR, if so configured. It is *entirely* configurable by the local system administrators, though CRATE comes with some specimen archive views. How to customize the archive view ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Write your archive ^^^^^^^^^^^^^^^^^^ Within a directory tree of your choice, write Mako_ templates. Some specimen miniature web sites are provided to show you how, in: .. code-block:: none crate_anon/crateweb/specimen_archives/basic/ crate_anon/crateweb/specimen_archives/tree/ The "basic" one demonstrates basic layout, SQL queries, and downloading of binary attachments. The "tree" one uses a collapsible tree-style menu on the left and a range of specimen views onto the EHR on the right. This system gives you full use of HTML/Javascript and Python simultaneously. (Python code will run within the same interpreter and virtual environment used by CRATE.) There are assistance functions that you can import, such as those in :mod:`crate_anon.crateweb.research.archive_func`. .. _archive_mako_context: The archive's Python context ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Mako templates have a context, which is a collection of Python objects "visible" to template code (see `Mako Runtime Environment`_). In the CRATE archive, this context is built up as follows: #. The config file's :ref:`ARCHIVE_CONTEXT ` dictionary is shallow-copied with :func:`copy.copy`. You can use :ref:`ARCHIVE_CONTEXT ` to pass a set of custom variables to your templates. #. That copy is updated with a specific set of keys, described next, which become visible as Python objects. (Doing it in this order means that ARCHIVE_CONTEXT can't override the special CRATE keys.) #. Mako will later add a few special objects of its own (see `Mako Runtime Environment`_). The special objects provided by CRATE are: - ``CRATE_HOME_URL``: URL to your site's CRATE home page. Use this to escape from the archive view! - ``execute``: Function to run an SQL query (via the research database connection), or just execute raw SQL, and return a database cursor. Call it as .. code-block:: python cursor = execute(sql) cursor = execute(sql, args) Use question marks (``?``) in the SQL as argument placeholders. - ``get_attachment_url``: Function to generate a URL to a binary attachment. This function adds the referring patient ID (for audit purposes) and calls :func:`crate_anon.crateweb.research.views.archive_attachment_url` (see that for details). Call it like this: .. code-block:: python get_attachment_url(filename, ...) - ``get_static_url``: Function to generate a URL to a binary attachment, which is :func:`crate_anon.crateweb.research.views.archive_static_url` (see that for details). Call it like this: .. code-block:: python get_static_url(filename, ...) - ``get_patient_template_url``: Function to generate a URL to a template in another part of the archive, for the same patient. Call it as .. code-block:: python get_patient_template_url(template_name, **kwargs) You can pass any keyword parameters except: - ``patient_id`` - ``template`` - ``mtime`` (see :class:`crate_anon.crateweb.config.constants.UrlKeys`). - ``get_template_url``: Function to generate a URL to a template in another part of the archive, without (necessarily) passing a patient ID. Call it as .. code-block:: python get_template_url(template_name, **kwargs) You can pass any keyword parameters except: - ``template`` - ``mtime`` (see :class:`crate_anon.crateweb.config.constants.UrlKeys`). - ``patient_id``: The ID of this patient. (A string, but that will still work an an SQL parameter for integer fields. You can of course process it further if you wish; this is illustrated in the "tree" example.) - ``query_params``: The HTTP GET query parameters, as a Django :class:`django.http.request.QueryDict`. - ``request``: The Django HTTP request, a :class:`django.http.request.HttpRequest` object. These objects are directly accessible, e.g. as ``${patient_id}``, in Mako statements. In the more obvious Python blocks (e.g. within Mako's ``<% ... %>`` blocks), they are also accessible, as (in this example) any of ``patient_id``, ``context["patient_id"]``, or ``context[ArchiveContextKeys.patient_id]``. One use for :ref:`ARCHIVE_CONTEXT ` is to develop a set of templates that operate either with an original identified clinical records database or with a de-identified version with slightly different structure (but similar enough to want to avoid code redundancy). You could set a flag in :ref:`ARCHIVE_CONTEXT ` to tell your templates which one is currently in use. Point CRATE at your archive ^^^^^^^^^^^^^^^^^^^^^^^^^^^ See the relevant section of the :ref:`web config file `. Examples ~~~~~~~~ Here's part of the demonstration tree-style archive, with entirely fictional data (and de-identified to boot). .. figure:: screenshots/archive_progress_notes.png "Progress Notes" display. The template has fetched data for the current patient via an SQL query and reformatted it to look like a conventional EHR "progress notes" journal (though in this case without author information). .. figure:: screenshots/archive_clinical_documents.png "Clinical Documents" display, showing PDFs inline. .. figure:: screenshots/archive_nlp_crp.png View on a NLP table, created by CRATE through analysis of free text. A generic "query results" template is used. .. figure:: screenshots/archive_nlp_source.png The NLP results hyperlink through to their source data, if available. Here's the note that generated one of the CRP values. .. figure:: screenshots/archive_nlp_kcl_drugs.png Another NLP view, this time of drugs found via the :ref:`KCL GATE pharmacotherapy ` app. Design notes ~~~~~~~~~~~~ 2019-08-31: - HTML templates, written locally, stored on disk in a user-defined directory. - Any template engine would be reasonable, but the two obvious candidates are - Django_, because we use that for the CRATE web front end (but the template language is somewhat restricted); - Mako_, because the templates can include arbitrary Python, and because Django/Mako interoperability is possible (including via Django-Mako-Plus_ but also directly). - `Other template engines`_, but nothing is particularly compelling over those two. Let's use Mako. - A structure that is configurable by the local administrator (stored in a config file, a database, or on disk), mapping the templates. The best is probably to specify a single template as the root template in the config file. - A URL system to produce requests to other parts of the archive, with arbitrary parameters via HTTP GET URL parameters. - Pre-population of the template dictionary with useful objects (but not those that take much time to create). See :func:`crate_anon.crateweb.research.views.archive_template`. Not done: - consider Windows authentication to Django - optional launch page for archive (e.g. allowing JSON POST for patient ID)