Developing Pluggable Modules with AuShadha Open Source EMR – UI building with PyYAML – Tutorial – Part 3


Building the Dijit – UI with PyYAML markup and Django Templating

Get the PyYAML file from Git Hub Repo : get it here.

This is the file that generates the Patient Pane which is brought up after searching.

This is the UI it generates:

Patient Pane
This Patient Pane’s UI widgets, layout etc is partly generated from the PyYAML

This pane.yaml file is a Django template that leverages Django’s templating features as well as PyYAML‘s object mark up to generate a rendered JSON. This JSON is then returned on AJAX call to help the UI building. JSON is parsed by the Javascript file here to help build the Dijit UI, Widgets etc…

PyYAML file

Let us examine the PyYAML file markup

Comments and Verbatim Code

At the top, {% verbatim %} Django Template tag allow the developer to put some code / comments

 Declaring Variables

Variables that can be used all over the YAML file can be declared at the top. This is where PyYAML markup scores over Django Template. Django Template restricts variable naming and prevents you from doing Python stuff inside the template.  This is ok for most templates that output HTML where the relevent code can be put inside the views.py. However, for it is also convenient if the option exists on the template. PyYAML allows us to call random python objects, declare variables that can be used through the template, use aliases in YAML file and even instantiate Python objects. Coupled with Django Template, it can be used powerfully.

# VARS

Variables can be declared with the expected type just to be sure. Aliases created can be used like Variables throughout the YAML file. Of Course we can just use {{{<some_var>}} Django template variable to do the substitution as well without creating any alias. 

VARS:
  clinic_id: &CLINIC_ID
     !!int {{clinic_id}}
  patient_id: &PATIENT_ID
     !!int {{patient_id}}
URLS:

This calls the Django reverse method and allows calling with arguments. The results is stored as the PATIENT_PANE_URL alias. 

pane: &PATIENT_PANE_URL 
 !!python/object/apply:django.core.urlresolvers.reverse
 args: [ render_patient_pane_with_id ]
 kwds: { kwargs : { patient_id: *PATIENT_ID } }

Using Django {%url%} template tag, the code below can be rewritten more elegantlyas:

pane: &PATIENT_PANE_URL  # creates the Alias of PATIENT_PANE_URL    
    {% url 'render_patient_pane_with_id' *PATIENT_ID %}

 YAML Header and Describing the Layout of the UI, widgets inside each DOM

YAML Header describes which module the pane belongs to, what are requisite modules to be loaded before this loads and whether this loads on AuShadha start. This is something like a basicinformation about the pane.

# YAML

depends_on: [ search ] #Requires that the Search Module
load_after: search #Requires that Search UI should be loaded before this
load_first: !!bool False #Prevents loading this first explicitly

#Following markup start the description of the Patient UI Pane

id : PATIENT     #ID of the DOM Element

type : bc        # Type of Dijit Layout Widget this is bc = Dijit BorderContainer

title : Patient         #Title Attribute

url : *PATIENT_PANE_URL #The URL attribute which equals href of the widget

closable : !!bool True  #Whether the tab is closable

widgets: []             #Whether there are child widgets (exludes layout widgets)

panes:                  #Describes the child layout Panes / DOM Nodes

  - id: PATIENT_DETAIL_ACTIONS_ICONS #DOM Element Id of the pane
    type: dom                        #Says that this is only a DOM Node not Dijit
    domType: div                     #Specifies the DOM node type
    style:                           #Specifies the CSS styles 
      position: relative
      top: 10
      zIndex: 1000
      float: right
      width: 200px
      height: 1.8em
- id : PATIENT_TOP_CP            #Describes a Dijit Layout Widget DOM Id
 region: top                     #Region attribute of the widget
 type: cp                        #Type of widget cp = dijit ContentPane
 splitter: False                 #Splitter attibute
 url: *PATIENT_INFO_URL          #href attribute
 widgets: []                     #Contained non-layout widgets
 panes: []                       #Contained Dijit panes, DOM nodes
 class: topContentPane selected  #CSS class 
 style:                          #CSS styles
   height: 1.8em

The resulting PyYAML file can be parsed and UI created by the Javascript file. As you can see the method is easy and the markup is certainly more readable than an HTML file with Dijit declarative markup interspersed with Django template markup etc..

It can certainly be argued about the need for a PyYAML use when HTML can be used. However, to change a layout and to see switching layout / per -user customisation it is much easier to move the YAML blocks to and fro the nested levels than to switch HTML blocks with all the declarative markups. Of course we can use Django Template {% include %} to create a basic HTML file that will do the job. It is up to developer preference. I found this much easier on the eye.

The current limitation is regarding inline javascript. This can be solved through custom Dojo Modules using AMD loader. Dojo’s dojoConfig attribute allows runtime loading. The pane’sattribute can allow import of specifically needed JS modules / classes. This is a thought. I have not implemented this fully. However, the proof of concept of this exists at the Pluggable module aushadha_demographics_us tree.yaml file.

More on that on a later post.

Next Tutorial will be based on the core of AuShadha and its bundled apps

Advertisement

Developing Pluggable Modules with AuShadha Open Source EMR – Part 2


Creating a fresh application

For the purpose of this we will create a demographics application with data collection as done is USA.

The end result is available at http://github.com/dreaswar/Au-Pluggables

After activating the virtual environment run

$ python manage.py startapp aushadha_demographics_us --template AuShadha/app_template

This will generate the application scaffold and populate it with basic import stubs. The folder structure will be as described in the PART 1.

1. Creating the model, views and urls.py

The models will be derived based on the US Demographics requirements here:  Demographics

The model class inherits from AuShadhaBaseModel and the model form class will inherit from AuShadhaBaseModelForm class, which gives them some useful methods which they inherit.

Additionally, the AuShadhaModelForm class generates Dijits for display. The Dijits have to be configured in the dijit_widgets_constants.py file which is a python dictionary. This is will give the necessary Dijit declarative directives for generating the form widgets.

Once the models are done, the views and urls.py have nothing AuShadha specific about them. Basically we need views to add, edit, delete, view, json export the objects. The same can be represented in the urls.py

2. Determining the registration of roles

The aushadha.py  file registers the role of a particular class in the application. Roles are purely arbitrarily made up by the developer. However, if he needs to register a class for a particualr role that has already been registered, he will need to use the same name so as to override the preexisting class.

For eg> a PatientRegistration model may do the role of Patient Registration in the application. Hence this can be registered for that role. AuShadhaUI class generates an instance per server run and this registers the classes for a particular role on startup.

Registration can be accomplished inside aushadha.py as

UI.register(<class_name>, <role_name_as_string> )

3. Finalise the UI layout with PyYAML

Earlier in AuShadha developement, Django Template with HTML, CSS, and JS was used to generate the layout. This sometimes requires extensive Dijit declarative HTML markup that was not easy on the eye. Additionally interspersed JS and CSS didnt help.

Hence a method of returning the UI layout as a JSON was devised using PyYAML library. On JSON return, this is parsed and the UI dynamically generated using Javascript. This has dramatically reduced the JS files required.

The required PyYAML file is located in the dijit_widgets directory. The pane.yaml  and  pane.py  creates the necessary JSON

PyYAML directives are almost the same as Dijit declarative HTML markup except for the quotations and angled bracket distractions. I will devout an entire tutorial on this and how the JS file parses this. This is very early in AuShadha development so the markup, directive may change, but the principle is the same.

4. Study need for additional JS files

The add-on modules will have a media directory with sub-directories of js, styles, images  to house modules of JS, CSS and images. Dojo has the new AMD loader that encourages modular design and the dojoConfig variable can be changed at runtime allowing full flexibility to add modules as needed. This is demonstrated by the grids in the application (Contact, Phone and Guardian grid). The relevent module that should be called by the loader is specified in the pane.yaml under the grid directives as gridStrModule.

5. Integerate or install the application

The application itself needs to be added to the INSTALLED_APPS. Integrating the application (or installing ) requires changes in the settings.py to set the paths for templates, scripts, styles and media.  The Root urls.py needs to include the application as well. After the settings are done run syncdb to install the changes.

In case of Stock modules that clash with add-on modules, the stock modules will have to be removed, changes made to settings.py and urls.py to reflect this. This has to be done before syncdb is done.

The fully developed application for US demographics collection is at http://github.com/dreaswar/Au-Pluggables

Part 3 will deal with PyYAML and auto building the Dijit UI Widgets with PyYAML and Dojo

Dedicated Website for my Open Source Electronic Medical Records Project – AuShadha


AuShadha Website is live !

AuShadha Electronic Medical Records project written in Python using Django and Dojo Javascript library has now a dedicated website with integrated Wiki, Blog and Discussion Forum at http://www.aushadha.org/

Please visit and let me know the feedback.

Thanks,

Dr.Easwar

Categories
EMR Python

Django EMR , Dojo (OrthoDocx) – jQuery (OrthoEMR) comparative Interfaces


The entire application interface is basically a tabbed top and bottom container for Patient management.

Patient list grid is basically a list with Datagrid with a jsonRest store. The Django view will return the json. The row click will  fill the bottom tabbed panel with appropriate contact, phone numbers, email, guardian, admission and visit info for that patient.The double click will allow editions / deletion of the patient if the user has the permissions.

Application currently uses Django 1.4, PyYaml, PIL, ReportLab, PISA(html5lib) and Dojo 1.7.2

The icons currently being used are from KDE but that may change.

 

The second sreenshot is the comparative interface in jQuery. There is no bottom pane here. Left sidebar shows the context info on patient selection from the list. The Right sidebar is hidden if the screen resolution is below 1024 and shows itself on zooming out / clicking the icon at the top left.

This interface uses jQuery, jQuery UI and plugins for the table with heavy CSS and jQuery customisation.  The icons used are mostly from the tango project with a few from the silk collection for web. I have made some of my own. Some icons are just place holders and i need to work on them to make my own ones.

Image