Skip to content

Commit

Permalink
massive refactor app structure and move to mongodb
Browse files Browse the repository at this point in the history
  • Loading branch information
eatyourpeas committed Mar 9, 2022
1 parent 8c4fa6d commit ee09ac1
Show file tree
Hide file tree
Showing 103 changed files with 254 additions and 245 deletions.
21 changes: 7 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,13 @@ foobar:~foo$ pip install -r requirements/development-requirements

### Running the database

We advise running the postgresql database from within Docker on port 5432, the default for Django

```command
foobar:~foo$ docker run --name [container_name] -e POSTGRES_USER=username -e POSTGRES_PASSWORD=[mysecretpassword] -p 5432:5432 -d postgres
```

## Connect to the docker container

```console
foobar:~foo$ docker exec -it [container_name] bash
root@175d895153ab:/# psql -U [username]
foobar:~foo$ docker run --name epilepsy12-mongo-docker -p 27017:27017 -d mongo:latest
```

## Create the database

```console
psql (14.0 (Debian 14.0-1.pgdg110+1))
Type "help" for help.

epilepsy12user=# CREATE DATABASE epilepsy12db;
```

## Prepare the database for use
Expand All @@ -103,6 +90,12 @@ you may need to allow permissions to run the bash script in that folder first:
foobar:~foo$ chmod +x ./s/runserver
```

## Create superuser to enable logging into admin section

```console
python manage.py createsuperuser
```

## Stated Aims of the Audit

* Continue to measure and improve care and outcomes for children and young people with
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
29 changes: 29 additions & 0 deletions epilepsy12/general_functions/postcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import re


def valid_postcode(postcode) -> bool:
"""
Validation function for UK postcodes
Returns either a regexp match or 'not matched'
ACKNOWLEDGEMENT: with thanks to https://kodey.co.uk/2020/09/03/a-uk-postcode-validation-script-in-python/
"""
pattern = 'not matched'
#e.g. W27XX
if len(postcode.replace(" ", "")) == 5:
pattern = re.compile("^[a-zA-Z]{1}[0-9]{2}[a-zA-Z]{2}")
#e.g. TW27XX
elif len(postcode.replace(" ", "")) == 6:
pattern = re.compile("^[a-zA-Z]{2}[0-9]{2}[a-zA-Z]{2}")
#e.g. TW218FF
elif len(postcode.replace(" ", "")) == 7:
pattern = re.compile("^[a-zA-Z]{2}[0-9]{3}[a-zA-Z]{2}")

return pattern


def validate_postcode(postcode: str) -> bool:
valid_postcode_regex = valid_postcode(postcode=postcode)
if(valid_postcode_regex.match('not matched')):
return False
else:
return True
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Generated by Django 4.0 on 2022-03-09 07:56
# Generated by Django 4.0 on 2022-03-09 13:11

import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import epilepsy12.general_functions.postcode
import uuid


Expand Down Expand Up @@ -48,21 +46,21 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Case',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('case_uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='Unique case identifier')),
('locked', models.BooleanField(default=False, verbose_name='Locked')),
('locked_at', models.DateTimeField(auto_now_add=True, verbose_name='Date record locked')),
('nhs_patient', models.BooleanField(verbose_name='Is an NHS patient?')),
('nhs_number', models.IntegerField(validators=[django.core.validators.MinLengthValidator(limit_value=10, message='The NHS number must be 10 digits long.')], verbose_name='NHS Number')),
('nhs_number', models.IntegerField(verbose_name='NHS Number')),
('first_name', models.CharField(max_length=100, verbose_name='first name')),
('surname', models.CharField(max_length=100, verbose_name='surname')),
('gender', models.CharField(choices=[(0, 'Not Known'), (1, 'Male'), (2, 'Female'), (9, 'Not Specified')], max_length=2, verbose_name='gender')),
('gender', models.IntegerField(choices=[(0, 'Not Known'), (1, 'Male'), (2, 'Female'), (9, 'Not Specified')])),
('date_of_birth', models.DateField(verbose_name='date of birth (YYYY-MM-DD)')),
('postcode', models.CharField(max_length=7, validators=[epilepsy12.general_functions.postcode.validate_postcode], verbose_name='postcode')),
('postcode', models.CharField(max_length=7, verbose_name='postcode')),
('ethnicity', models.CharField(choices=[('N', 'African'), ('L', 'Any other Asian background'), ('P', 'Any other Black background'), ('S', 'Any other ethnic group'), ('G', 'Any other mixed background'), ('C', 'Any other White background'), ('K', 'Bangladeshi or British Bangladeshi'), ('A', 'British, Mixed British'), ('M', 'Caribbean'), ('R', 'Chinese'), ('H', 'Indian or British Indian'), ('B', 'Irish'), ('NULL', 'Not Recorded'), ('Z', 'Not Stated'), ('J', 'Pakistani or British Pakistani'), ('F', 'White and Asian'), ('E', 'White and Black African'), ('D', 'White and Black Caribbean')], max_length=4)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created%(app_label)s_%(class)s_related', to='auth.user', verbose_name='record created by user in %(class)')),
('locked_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.user', verbose_name='locked by')),
('locked_by', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='auth.user', verbose_name='locked by')),
('updated_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='updated%(app_label)s_%(class)s_related', to='auth.user', verbose_name='record updated by user in %(class)')),
],
options={
Expand Down Expand Up @@ -419,8 +417,4 @@ class Migration(migrations.Migration):
model_name='hospitaltrust',
index=models.Index(fields=['hospital_trust_name'], name='epilepsy12__hospita_a838eb_idx'),
),
migrations.AddIndex(
model_name='case',
index=models.Index(fields=['case_uuid'], name='epilepsy12__case_uu_5b975e_idx'),
),
]
17 changes: 17 additions & 0 deletions epilepsy12/migrations/0002_alter_case_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.0 on 2022-03-09 13:36

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('epilepsy12', '0001_initial'),
]

operations = [
migrations.AlterModelOptions(
name='case',
options={'verbose_name': 'case', 'verbose_name_plural': 'cases'},
),
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
from django.contrib.auth.models import User
from django.core.validators import MinLengthValidator
import uuid

from django.forms import IntegerField
from ..constants import *
from ..general_functions import *
from .time_and_user_abstract_base_classes import *


class Case(TimeStampAbstractBaseClass, UserStampAbstractBaseClass):
"""
This class holds information about each child or young person
Expand All @@ -25,75 +28,76 @@ class Case(TimeStampAbstractBaseClass, UserStampAbstractBaseClass):
?analysis flag
"""
case_uuid=models.UUIDField(
"Unique case identifier",
primary_key=True,
default=uuid.uuid4,
editable=False
)
locked=models.BooleanField( # this determines if the case is locked from editing ? are cases or only registrations locked?
"Locked",
# case_uuid=models.UUIDField(
# "Unique case identifier",
# primary_key=True,
# default=uuid.uuid4,
# editable=False
# )
locked = models.BooleanField( # this determines if the case is locked from editing ? are cases or only registrations locked?
"Locked",
default=False
)
locked_at = models.DateTimeField(
"Date record locked",
auto_now_add=True
)
locked_by = models.ForeignKey(
User,
User,
on_delete=CASCADE,
verbose_name="locked by"
verbose_name="locked by",
default=None
)
nhs_patient = models.BooleanField(
"Is an NHS patient?"
)
nhs_number = models.IntegerField( # the NHS number for England and Wales - THIS IS NOT IN THE ORIGINAL TABLES
nhs_number = models.IntegerField( # the NHS number for England and Wales - THIS IS NOT IN THE ORIGINAL TABLES
"NHS Number",
validators=[MinLengthValidator( # should be other validation before saving - need to strip out spaces
limit_value=10,
message="The NHS number must be 10 digits long."
)]
) # TODO #13 NHS Number must be hidden - use case_uuid as proxy
first_name=CharField(
# validators=[MinLengthValidator( # should be other validation before saving - need to strip out spaces
# limit_value=10,
# message="The NHS number must be 10 digits long."
# )]
) # TODO #13 NHS Number must be hidden - use case_uuid as proxy
first_name = CharField(
"first name",
max_length=100
)
surname=CharField(
surname = CharField(
"surname",
max_length=100
)
gender=CharField(
"gender",
max_length=2,
gender = models.IntegerField(
choices=SEX_TYPE
)
date_of_birth=DateField(
date_of_birth = DateField(
"date of birth (YYYY-MM-DD)"
)
postcode=CharField(
postcode = CharField(
"postcode",
max_length=7,
validators=[validate_postcode]
# validators=[validate_postcode]
)
ethnicity=CharField(

ethnicity = CharField(
max_length=4,
choices=ETHNICITIES
)

def _imd_quintile_from_postcode(self)->int:
"index of multiple deprivation calculated from MySociety data.",
if (self.postcode):
postcode=validate_postcode(self.postcode)
imd_quintile=imd_for_postcode(postcode)
return imd_quintile
# This field requires the deprivare api to be running
# def _imd_quintile_from_postcode(self) -> int:
# "index of multiple deprivation calculated from MySociety data.",
# if (self.postcode):
# postcode = valid_postcode(self.postcode)
# imd_quintile = imd_for_postcode(postcode)
# return imd_quintile

index_of_multiple_deprivation_quintile=property(_imd_quintile_from_postcode)
# index_of_multiple_deprivation_quintile = property(
# _imd_quintile_from_postcode)

class Meta:
indexes=[models.Index(fields=['case_uuid'])]
verbose_name = 'child or young person'
verbose_name_plural = 'children and young people'
# indexes = [models.Index(fields=['case_uuid'])]
verbose_name = 'case'
verbose_name_plural = 'cases'

def __str__(self) -> str:
return self.hospital_trust_name
return self.first_name + " " + self.surname
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from django.db import models
from ..constants import *
from .time_and_user_abstract_base_classes import *


class ElectroClinicalSyndrome(TimeStampAbstractBaseClass, UserStampAbstractBaseClass):
"""
This class records information on electroclinical syndromes.
It references the episode class, since one episode can have features of a single electroclinical syndrome.
"""
electroclinical_syndrome=models.IntegerField(choices=ELECTROCLINICAL_SYNDROMES)
electroclinical_sydrome_other=models.CharField(
electroclinical_syndrome = models.IntegerField(
choices=ELECTROCLINICAL_SYNDROMES)
electroclinical_syndrome_other = models.CharField(
default=None,
max_length=250
)

class Meta:
verbose_name="electroclinical syndrome",
verbose_name_plural="electroclinical syndromes"
verbose_name = 'electroclinical syndrome'
verbose_name_plural = 'electroclinical syndromes'

def __str__(self) -> str:
return self.electroclinical_syndrome
return self.electroclinical_syndrome
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@

from datetime import date
from django.db import models
from django.db.models.deletion import CASCADE
from ..constants import *
from .time_and_user_abstract_base_classes import *

# other tables
from .case import Case

class EpilepsyContext(TimeStampAbstractBaseClass, UserStampAbstractBaseClass):
"""
This class records contextual information that defines epilepsy risk.
It references the InitialAssessment class, as each case optionally has a single epilepsy context.
"""
previous_febrile_seizure=models.CharField(
previous_febrile_seizure = models.CharField(
"has there been a previous febrile seizure?",
max_length=2,
choices=OPT_OUT_UNCERTAIN
)
previous_acute_symptomatic_seizure=models.CharField(
previous_acute_symptomatic_seizure = models.CharField(
"has there been a previous acute symptomatic seizure?",
max_length=2,
choices=OPT_OUT_UNCERTAIN
)
is_there_a_family_history_of_epilepsy=models.CharField(
is_there_a_family_history_of_epilepsy = models.CharField(
"is there a family history of epilepsy?",
max_length=3,
max_length=3,
choices=OPT_OUT_UNCERTAIN
)
previous_neonatal_seizures=models.CharField(
previous_neonatal_seizures = models.CharField(
"were there seizures in the neonatal period?",
max_length=2,
choices=OPT_OUT_UNCERTAIN
)
diagnosis_of_epilepsy_withdrawn=models.CharField(
diagnosis_of_epilepsy_withdrawn = models.CharField(
"has the diagnosis of epilepsy been withdrawn?",
max_length=2,
max_length=2,
choices=OPT_OUT
)
date_of_first_epileptic_seizure=models.DateField(
date_of_first_epileptic_seizure = models.DateField(
"What date was the first reported epileptic seizure?"
)

Expand All @@ -49,9 +46,10 @@ def calculate_epilepsy_years(self):
today = date.today()
days_between = abs(today-self.date_of_first_epileptic_seizure).days
return days_between

class Meta:
verbose_name = 'epilepsy context'
verbose_name_plural = 'epilepsy contexts'

def __str__(self) -> str:
return self.date_of_first_epileptic_seizure
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit ee09ac1

Please sign in to comment.