class GeneticSpecimen(models.Model, IndexableMixin): """ Class to describe a biosample used for genomics testing or analysis. """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.GENETIC_SPECIMEN, "id")) specimen_type = JSONField(validators=[ontology_validator], help_text=rec_help(d.GENETIC_SPECIMEN, "specimen_type")) collection_body = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.GENETIC_SPECIMEN, "collection_body")) laterality = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.GENETIC_SPECIMEN, "laterality")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.GENETIC_SPECIMEN, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class Variant(models.Model): """ Class to describe Individual variants or diagnosed causative variants FHIR: Observation ? Draft extension for Variant is in development """ ALLELE = ( ('hgvsAllele', 'hgvsAllele'), ('vcfAllele', 'vcfAllele'), ('spdiAllele', 'spdiAllele'), ('iscnAllele', 'iscnAllele'), ) allele_type = models.CharField(max_length=200, choices=ALLELE, help_text="One of four allele types.") allele = JSONField(validators=[JsonSchemaValidator(schema=ALLELE_SCHEMA)], help_text=rec_help(d.VARIANT, "allele")) zygosity = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.VARIANT, "zygosity")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.VARIANT, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id)
class Disease(models.Model, IndexableMixin): """ Class to represent a diagnosis and inference or hypothesis about the cause underlying the observed phenotypic abnormalities FHIR: Condition """ term = JSONField(validators=[ontology_validator], help_text=rec_help(d.DISEASE, "term")) # "ageOfOnset": { # "age": "P38Y7M" # } # OR # "ageOfOnset": { # "id": "HP:0003581", # "label": "Adult onset" # } onset = JSONField(blank=True, null=True, validators=[JsonSchemaValidator(schema=PHENOPACKET_DISEASE_ONSET_SCHEMA)], help_text=rec_help(d.DISEASE, "onset")) disease_stage = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.DISEASE, "disease_stage")) tnm_finding = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.DISEASE, "tnm_finding")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.DISEASE, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id)
class LabsVital(models.Model, IndexableMixin): """ Class to record tests performed on patient. """ # TODO Should this class be a part of Patients app? patient related metadata id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.LABS_VITAL, "id")) individual = models.ForeignKey(Individual, on_delete=models.CASCADE, help_text=rec_help(d.LABS_VITAL, "individual")) # TODO Change CodeableConcept to Ontology class tumor_marker_code = JSONField(validators=[ontology_validator], help_text=rec_help(d.LABS_VITAL, "tumor_marker_code")) tumor_marker_data_value = JSONField( blank=True, null=True, validators=[tumor_marker_data_value_validator], help_text=rec_help(d.LABS_VITAL, "tumor_marker_data_value")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.LABS_VITAL, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class ExperimentResult(models.Model, IndexableMixin): """ Class to represent information about analysis of sequencing data in a file format. """ # TODO identifier assigned by lab (?) identifier = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "identifier")) description = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "description")) filename = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "filename")) genome_assembly_id = CharField(max_length=50, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "genome_assembly_id")) file_format = CharField(max_length=50, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "file_format")) data_output_type = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "data_output_type")) usage = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "usage")) creation_date = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "creation_date")) created_by = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "created_by")) extra_properties = JSONField(blank=True, default=dict, validators=[key_value_validator], help_text=rec_help(d.EXPERIMENT_RESULT, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.identifier)
class Instrument(models.Model, IndexableMixin): """ Class to represent information about instrument used to perform a sequencing experiment. """ # TODO identifier assigned by lab (?) identifier = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "identifier")) platform = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.INSTRUMENT, "platform")) description = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.INSTRUMENT, "description")) model = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.INSTRUMENT, "model")) extra_properties = JSONField(blank=True, default=dict, validators=[key_value_validator], help_text=rec_help(d.INSTRUMENT, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id)
class CancerCondition(models.Model, IndexableMixin): """ Class to record the history of primary or secondary cancer conditions. """ CANCER_CONDITION_TYPE = (('primary', 'primary'), ('secondary', 'secondary')) id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.CANCER_CONDITION, "id")) condition_type = models.CharField(choices=CANCER_CONDITION_TYPE, max_length=200, help_text=rec_help( d.CANCER_CONDITION, "condition_type")) body_site = JSONField(null=True, validators=[ontology_list_validator], help_text=rec_help(d.CANCER_CONDITION, 'body_site')) laterality = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_CONDITION, "laterality")) clinical_status = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_CONDITION, "clinical_status")) code = JSONField(validators=[ontology_validator], help_text=rec_help(d.CANCER_CONDITION, "code")) date_of_diagnosis = models.DateTimeField(blank=True, null=True, help_text=rec_help( d.CANCER_CONDITION, "date_of_diagnosis")) histology_morphology_behavior = JSONField( blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_CONDITION, "histology_morphology_behavior")) verification_status = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_CONDITION, "verification_status")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.CANCER_CONDITION, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class Phenopacket(models.Model, IndexableMixin): """ Class to aggregate Individual's experiments data FHIR: Composition """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.PHENOPACKET, "id")) # if Individual instance is deleted Phenopacket instance is deleted too # CHECK !!! Force as required? subject = models.ForeignKey( Individual, on_delete=models.CASCADE, related_name="phenopackets", help_text=rec_help(d.PHENOPACKET, "subject")) # PhenotypicFeatures are present in Biosample, so can be accessed via Biosample instance # phenotypic_features = models.ManyToManyField(PhenotypicFeature, blank=True, # help_text='Phenotypic features observed in the proband.') biosamples = models.ManyToManyField(Biosample, blank=True, help_text=rec_help(d.PHENOPACKET, "biosamples")) genes = models.ManyToManyField(Gene, blank=True, help_text=rec_help(d.PHENOPACKET, "genes")) variants = models.ManyToManyField(Variant, blank=True, help_text=rec_help(d.PHENOPACKET, "variants")) diseases = models.ManyToManyField(Disease, blank=True, help_text=rec_help(d.PHENOPACKET, "diseases")) hts_files = models.ManyToManyField(HtsFile, blank=True, help_text=rec_help(d.PHENOPACKET, "hts_files")) # TODO OneToOneField meta_data = models.ForeignKey(MetaData, on_delete=models.CASCADE, help_text=rec_help(d.PHENOPACKET, "meta_data")) table = models.ForeignKey("chord.Table", on_delete=models.CASCADE, blank=True, null=True) # TODO: Help text extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.PHENOPACKET, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id)
class MCodePacket(models.Model, IndexableMixin): """ Class to aggregate Individual's cancer related metadata """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.MCODEPACKET, "id")) subject = models.ForeignKey(Individual, on_delete=models.CASCADE, help_text=rec_help(d.MCODEPACKET, "subject")) genomics_report = models.ForeignKey(GenomicsReport, blank=True, null=True, on_delete=models.SET_NULL, help_text=rec_help( d.MCODEPACKET, "genomics_report")) cancer_condition = models.ManyToManyField(CancerCondition, blank=True, help_text=rec_help( d.MCODEPACKET, "cancer_condition")) cancer_related_procedures = models.ManyToManyField( CancerRelatedProcedure, blank=True, help_text=rec_help(d.MCODEPACKET, "cancer_related_procedures")) medication_statement = models.ManyToManyField(MedicationStatement, blank=True, help_text=rec_help( d.MCODEPACKET, "medication_statement")) date_of_death = models.CharField(max_length=200, blank=True, help_text=rec_help( d.MCODEPACKET, "date_of_death")) cancer_disease_status = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help( d.MCODEPACKET, "cancer_disease_status")) # link to dataset via the table table = models.ForeignKey("chord.Table", on_delete=models.CASCADE, blank=True, null=True) # TODO: Help text extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.MCODEPACKET, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class PhenotypicFeature(models.Model, IndexableMixin): """ Class to describe a phenotype of an Individual FHIR: Condition or Observation """ description = models.CharField(max_length=200, blank=True, help_text=rec_help(d.PHENOTYPIC_FEATURE, "description")) pftype = JSONField(verbose_name='type', validators=[ontology_validator], help_text=rec_help(d.PHENOTYPIC_FEATURE, "type")) negated = models.BooleanField(default=False, help_text=rec_help(d.PHENOTYPIC_FEATURE, "negated")) severity = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.PHENOTYPIC_FEATURE, "severity")) modifier = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.PHENOTYPIC_FEATURE, "modifier")) onset = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.PHENOTYPIC_FEATURE, "onset")) # evidence can stay here because evidence is given for an observation of PF # JSON schema to check evidence_code is present # FHIR: Condition.evidence evidence = JSONField(blank=True, null=True, validators=[JsonSchemaValidator(schema=PHENOPACKET_EVIDENCE_SCHEMA)], help_text=rec_help(d.PHENOTYPIC_FEATURE, "evidence")) biosample = models.ForeignKey( "Biosample", on_delete=models.SET_NULL, blank=True, null=True, related_name='phenotypic_features') phenopacket = models.ForeignKey( "Phenopacket", on_delete=models.SET_NULL, blank=True, null=True, related_name='phenotypic_features') extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.PHENOTYPIC_FEATURE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class CancerRelatedProcedure(models.Model, IndexableMixin): """ Class to represent radiological treatment or surgical action addressing a cancer condition. """ PROCEDURE_TYPES = (('radiation', 'radiation'), ('surgical', 'surgical')) id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "id")) procedure_type = models.CharField(choices=PROCEDURE_TYPES, max_length=200, help_text=rec_help( d.CANCER_RELATED_PROCEDURE, "procedure_type")) code = JSONField(validators=[ontology_validator], help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "code")) body_site = JSONField(null=True, validators=[ontology_list_validator], help_text=rec_help(d.CANCER_RELATED_PROCEDURE, 'body_site')) laterality = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "laterality")) treatment_intent = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "treatment_intent")) # Only for Surgical Procedure # TODO CHANGE to ontology list validator reason_code = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "reason_code")) reason_reference = models.ManyToManyField(CancerCondition, blank=True, help_text=rec_help( d.CANCER_RELATED_PROCEDURE, "reason_reference")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.CANCER_RELATED_PROCEDURE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class Procedure(models.Model): """ Class to represent a clinical procedure performed on an individual (subject) in order to extract a biosample FHIR: Procedure """ code = JSONField(help_text=rec_help(d.PROCEDURE, "code")) body_site = JSONField(blank=True, null=True, help_text=rec_help(d.PROCEDURE, "body_site")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.PROCEDURE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class MetaData(models.Model): """ Class to store structured definitions of the resources and ontologies used within the phenopacket FHIR: Metadata """ created = models.DateTimeField(default=timezone.now, help_text=rec_help(d.META_DATA, "created")) created_by = models.CharField(max_length=200, help_text=rec_help(d.META_DATA, "created_by")) submitted_by = models.CharField(max_length=200, blank=True, help_text=rec_help(d.META_DATA, "submitted_by")) resources = models.ManyToManyField(Resource, help_text=rec_help(d.META_DATA, "resources")) updates = ArrayField( JSONField(null=True, blank=True), blank=True, null=True, help_text=rec_help(d.META_DATA, "updates")) phenopacket_schema_version = models.CharField(max_length=200, blank=True, help_text='Schema version of the current phenopacket.') external_references = ArrayField( JSONField(null=True, blank=True), blank=True, null=True, help_text=rec_help(d.META_DATA, "external_references")) extra_properties = JSONField( blank=True, null=True, help_text=rec_help(d.META_DATA, "extra_properties")) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class MetaData(models.Model): """ Class to store structured definitions of the resources and ontologies used within the phenopacket FHIR: Metadata """ created = models.DateTimeField(default=timezone.now, help_text=rec_help(d.META_DATA, "created")) created_by = models.CharField(max_length=200, help_text=rec_help(d.META_DATA, "created_by")) submitted_by = models.CharField(max_length=200, blank=True, help_text=rec_help(d.META_DATA, "submitted_by")) resources = models.ManyToManyField(Resource, help_text=rec_help(d.META_DATA, "resources")) updates = JSONField(blank=True, null=True, validators=[JsonSchemaValidator( schema=schema_list(PHENOPACKET_UPDATE_SCHEMA), formats=['date-time'])], help_text=rec_help(d.META_DATA, "updates")) phenopacket_schema_version = models.CharField(max_length=200, blank=True, help_text='Schema version of the current phenopacket.') external_references = JSONField(blank=True, null=True, validators=[JsonSchemaValidator( schema=schema_list(PHENOPACKET_EXTERNAL_REFERENCE_SCHEMA))], help_text=rec_help(d.META_DATA, "external_references")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.META_DATA, "extra_properties")) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class GenomicRegionStudied(models.Model, IndexableMixin): """ Class to describe the area of the genome region referenced in testing for variants. """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.GENOMIC_REGION_STUDIED, "id")) # TODO schema Range list dna_ranges_examined = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help( d.GENOMIC_REGION_STUDIED, "dna_ranges_examined")) dna_region_description = ArrayField(models.CharField( max_length=100, help_text=rec_help(d.GENOMIC_REGION_STUDIED, 'dna_region_description')), blank=True, default=list) gene_mutation = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.GENOMIC_REGION_STUDIED, "gene_mutation")) # TODO check: thisis not a Reference in mcode data dictionary why not? gene_studied = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.GENOMIC_REGION_STUDIED, "gene_studied")) genomic_reference_sequence_id = JSONField( blank=True, null=True, help_text=rec_help(d.GENOMIC_REGION_STUDIED, "genomic_reference_sequence_id")) genomic_region_coordinate_system = JSONField( blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.GENOMIC_REGION_STUDIED, "genomic_region_coordinate_system")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.GENOMIC_REGION_STUDIED, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class Gene(models.Model): """ Class to represent an identifier for a gene FHIR: ? Draft extension for Gene is in development where Gene defined via class CodeableConcept """ # Gene id is unique id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.GENE, "id")) # CURIE style? Yes! alternate_ids = ArrayField(models.CharField(max_length=200, blank=True), blank=True, default=list, help_text=rec_help(d.GENE, "alternate_ids")) symbol = models.CharField(max_length=200, help_text=rec_help(d.GENE, "symbol")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.GENE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class HtsFile(models.Model, IndexableMixin): """ Class to link HTC files with data FHIR: DocumentReference """ HTS_FORMAT = ( ('UNKNOWN', 'UNKNOWN'), ('SAM', 'SAM'), ('BAM', 'BAM'), ('CRAM', 'CRAM'), ('VCF', 'VCF'), ('BCF', 'BCF'), ('GVCF', 'GVCF'), ) uri = models.URLField(primary_key=True, max_length=200, help_text=rec_help(d.HTS_FILE, "uri")) description = models.CharField(max_length=200, blank=True, help_text=rec_help(d.HTS_FILE, "description")) hts_format = models.CharField(max_length=200, choices=HTS_FORMAT, help_text=rec_help(d.HTS_FILE, "hts_format")) genome_assembly = models.CharField(max_length=200, help_text=rec_help(d.HTS_FILE, "genome_assembly")) # e.g. # "individualToSampleIdentifiers": { # "patient23456": "NA12345" # TODO how to perform this validation, ensure the patient id is the correct one? individual_to_sample_identifiers = JSONField( blank=True, null=True, help_text=rec_help(d.HTS_FILE, "individual_to_sample_identifiers")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.HTS_FILE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.uri)
class Resource(models.Model): """ Class to represent a description of an external resource used for referencing an object FHIR: CodeSystem """ class Meta: unique_together = (("namespace_prefix", "version"), ) # resource_id e.g. "id": "uniprot:2019_07" id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.RESOURCE, "id")) name = models.CharField(max_length=200, help_text=rec_help(d.RESOURCE, "name")) namespace_prefix = models.CharField(max_length=200, help_text=rec_help( d.RESOURCE, "namespace_prefix")) url = models.URLField(max_length=200, help_text=rec_help(d.RESOURCE, "url")) version = models.CharField(max_length=200, help_text=rec_help(d.RESOURCE, "version")) iri_prefix = models.URLField(max_length=200, help_text=rec_help(d.RESOURCE, "iri_prefix")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.RESOURCE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def clean(self): # For phenopackets compliance, we need to have a string identifier. Django does not allow compound keys, we # ideally want to identify resources by the pair (namespace_prefix, version). In this case, we hack this by # enforcing that id == (namespace_prefix, version). In the case of an unspecified version, enforce # id == namespace_prefix. if (self.version and self.id != f"{self.namespace_prefix}:{self.version}") or \ (not self.version and self.id != self.namespace_prefix): raise ValidationError({ "id": [ ValidationError( "Resource ID must match the format 'namespace_prefix:version'" ) ], }) def save(self, *args, **kwargs): self.clean() return super().save(*args, **kwargs) def __str__(self): return str(self.id)
class GenomicsReport(models.Model, IndexableMixin): """ Genetic Analysis Summary. """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.GENOMICS_REPORT, "id")) code = JSONField(validators=[ontology_validator], help_text=rec_help(d.GENOMICS_REPORT, "code")) performing_organization_name = models.CharField( max_length=200, blank=True, help_text=rec_help(d.GENOMICS_REPORT, "performing_organization_name")) issued = models.DateTimeField(default=timezone.now, help_text=rec_help(d.GENOMICS_REPORT, "issued")) genetic_specimen = models.ManyToManyField(GeneticSpecimen, blank=True, help_text=rec_help( d.GENOMICS_REPORT, "genetic_specimen")) genetic_variant = models.ForeignKey(CancerGeneticVariant, blank=True, null=True, on_delete=models.SET_NULL, help_text=rec_help( d.GENOMICS_REPORT, "genetic_variant")) genomic_region_studied = models.ForeignKey(GenomicRegionStudied, blank=True, null=True, on_delete=models.SET_NULL, help_text=rec_help( d.GENOMICS_REPORT, "genomic_region_studied")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.GENOMICS_REPORT, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class TNMStaging(models.Model, IndexableMixin): """ Class to describe the spread of cancer in a patient’s body. """ TNM_TYPES = (('clinical', 'clinical'), ('pathologic', 'pathologic')) id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.TNM_STAGING, "id")) tnm_type = models.CharField(choices=TNM_TYPES, max_length=200, help_text=rec_help(d.TNM_STAGING, "tnm_type")) stage_group = JSONField(validators=[complex_ontology_validator], help_text=rec_help(d.TNM_STAGING, "stage_group")) primary_tumor_category = JSONField(validators=[complex_ontology_validator], help_text=rec_help( d.TNM_STAGING, "primary_tumor_category")) regional_nodes_category = JSONField( validators=[complex_ontology_validator], help_text=rec_help(d.TNM_STAGING, "regional_nodes_category")) distant_metastases_category = JSONField( validators=[complex_ontology_validator], help_text=rec_help(d.TNM_STAGING, "distant_metastases_category")) # TODO check if one cancer condition has many TNM Staging cancer_condition = models.ForeignKey(CancerCondition, on_delete=models.CASCADE, help_text=rec_help( d.TNM_STAGING, "cancer_condition")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.TNM_STAGING, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class MedicationStatement(models.Model, IndexableMixin): """ Class to record the use of a medication. """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.MEDICATION_STATEMENT, "id")) # list http://hl7.org/fhir/us/core/STU3.1/ValueSet-us-core-medication-codes.html medication_code = JSONField(validators=[ontology_validator], help_text=rec_help(d.MEDICATION_STATEMENT, "medication_code")) termination_reason = JSONField(null=True, validators=[ontology_list_validator], help_text=rec_help(d.MEDICATION_STATEMENT, 'termination_reason')) treatment_intent = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.MEDICATION_STATEMENT, "treatment_intent")) start_date = models.DateTimeField(blank=True, null=True, help_text=rec_help( d.MEDICATION_STATEMENT, "start_date")) end_date = models.DateTimeField(blank=True, null=True, help_text=rec_help(d.MEDICATION_STATEMENT, "end_date")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.MEDICATION_STATEMENT, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)
class Resource(models.Model): """ Class to represent a description of an external resource used for referencing an object FHIR: CodeSystem """ # resource_id e.g. "id": "uniprot" id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.RESOURCE, "id")) name = models.CharField(max_length=200, help_text=rec_help(d.RESOURCE, "name")) namespace_prefix = models.CharField(max_length=200, help_text=rec_help(d.RESOURCE, "namespace_prefix")) url = models.URLField(max_length=200, help_text=rec_help(d.RESOURCE, "url")) version = models.CharField(max_length=200, help_text=rec_help(d.RESOURCE, "version")) iri_prefix = models.URLField(max_length=200, help_text=rec_help(d.RESOURCE, "iri_prefix")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.RESOURCE, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.id)
class Experiment(models.Model, IndexableMixin): """ Class to store Experiment information """ LIBRARY_STRATEGY = ( ('DNase-Hypersensitivity', 'DNase-Hypersensitivity'), ('ATAC-seq', 'ATAC-seq'), ('NOME-Seq', 'NOME-Seq'), ('Bisulfite-Seq', 'Bisulfite-Seq'), ('MeDIP-Seq', 'MeDIP-Seq'), ('MRE-Seq', 'MRE-Seq'), ('ChIP-Seq', 'ChIP-Seq'), ('RNA-Seq', 'RNA-Seq'), ('miRNA-Seq', 'miRNA-Seq'), ('WGS', 'WGS'), ) MOLECULE = ( ('total RNA', 'total RNA'), ('polyA RNA', 'polyA RNA'), ('cytoplasmic RNA', 'cytoplasmic RNA'), ('nuclear RNA', 'nuclear RNA'), ('small RNA', 'small RNA'), ('genomic DNA', 'genomic DNA'), ('protein', 'protein'), ('other', 'other'), ) id = CharField(primary_key=True, max_length=200, help_text=rec_help(d.EXPERIMENT, 'id')) reference_registry_id = CharField(max_length=30, blank=True, null=True, help_text=rec_help( d.EXPERIMENT, 'reference_registry_id')) qc_flags = ArrayField(CharField(max_length=100, help_text=rec_help(d.EXPERIMENT, 'qc_flags')), blank=True, default=list) experiment_type = CharField(max_length=30, help_text=rec_help(d.EXPERIMENT, 'experiment_type')) experiment_ontology = JSONField(blank=True, default=list, validators=[ontology_list_validator], help_text=rec_help(d.EXPERIMENT, 'experiment_ontology')) molecule_ontology = JSONField(blank=True, default=list, validators=[ontology_list_validator], help_text=rec_help(d.EXPERIMENT, 'molecule_ontology')) molecule = CharField(choices=MOLECULE, max_length=20, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, 'molecule')) library_strategy = CharField(choices=LIBRARY_STRATEGY, max_length=25, help_text=rec_help(d.EXPERIMENT, 'library_strategy')) other_fields = JSONField(blank=True, default=dict, validators=[key_value_validator], help_text=rec_help(d.EXPERIMENT, 'other_fields')) biosample = models.ForeignKey(Biosample, on_delete=models.CASCADE, help_text=rec_help(d.EXPERIMENT, 'biosample')) table = models.ForeignKey("chord.Table", on_delete=models.CASCADE, blank=True, null=True) # TODO: Help text def __str__(self): return str(self.id)
class Experiment(models.Model, IndexableMixin): """ Class to store Experiment information """ id = CharField(primary_key=True, max_length=200, help_text=rec_help(d.EXPERIMENT, "id")) # STUDY TYPE # ["Whole Genome Sequencing","Metagenomics","Transcriptome Analysis","Resequencing","Epigenetics", # "Synthetic Genomics","Forensic or Paleo-genomics","Gene Regulation Study","Cancer Genomics", # "Population Genomics","RNASeq","Pooled Clone Sequencing","Transcriptome Sequencing","Other"] study_type = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "study_type")) # TYPE experiment_type = CharField(max_length=200, help_text=rec_help(d.EXPERIMENT, "experiment_type")) experiment_ontology = JSONField(blank=True, default=list, validators=[ontology_list_validator], help_text=rec_help(d.EXPERIMENT, "experiment_ontology")) # MOLECULE molecule = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "molecule")) molecule_ontology = JSONField(blank=True, default=list, validators=[ontology_list_validator], help_text=rec_help(d.EXPERIMENT, "molecule_ontology")) # LIBRARY library_strategy = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "library_strategy")) library_source = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "library_source")) library_selection = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "library_selection")) library_layout = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "library_layout")) extraction_protocol = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT, "extraction_protocol")) reference_registry_id = CharField(max_length=200, blank=True, null=True, help_text=rec_help( d.EXPERIMENT, "reference_registry_id")) qc_flags = ArrayField(CharField(max_length=200, help_text=rec_help(d.EXPERIMENT, "qc_flags")), blank=True, default=list) # SAMPLE biosample = models.ForeignKey(Biosample, on_delete=models.CASCADE, help_text=rec_help(d.EXPERIMENT, "biosample")) table = models.ForeignKey("chord.Table", on_delete=models.CASCADE, blank=True, null=True) # TODO: Help text # EXPERIMENT RESULT experiment_results = models.ManyToManyField("ExperimentResult", blank=True, help_text=rec_help( d.EXPERIMENT, "experiment_results")) # INTSRUMENT instrument = models.ForeignKey("Instrument", blank=True, null=True, on_delete=models.CASCADE, help_text=rec_help(d.EXPERIMENT, "instrument")) # EXTRA extra_properties = JSONField(blank=True, default=dict, validators=[key_value_validator], help_text=rec_help(d.EXPERIMENT, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id)
class ExperimentResult(models.Model, IndexableMixin): """ Class to represent information about analysis of sequencing data in a file format. """ FILE_FORMAT = ( ("SAM", "SAM"), ("BAM", "BAM"), ("CRAM", "CRAM"), ("BAI", "BAI"), ("CRAI", "CRAI"), ("VCF", "VCF"), ("BCF", "BCF"), ("GVCF", "GVCF"), ("BigWig", "BigWig"), ("BigBed", "BigBed"), ("FASTA", "FASTA"), ("FASTQ", "FASTQ"), ("TAB", "TAB"), ("SRA", "SRA"), ("SRF", "SRF"), ("SFF", "SFF"), ("GFF", "GFF"), ("TABIX", "TABIX"), ("UNKNOWN", "UNKNOWN"), ("OTHER", "OTHER"), ) # TODO or Processed/Sequenced vs. Raw/Derived DATA_OUTPUT_TYPE = ( ("Raw data", "Raw data"), ("Derived data", "Derived data"), ) # Data usage # USAGE = ( # ("Visualize", "Visualize"), # ("Download", "Download"), # ) # TODO identifier assigned by lab (?) identifier = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "identifier")) description = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "description")) filename = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "filename")) file_format = CharField(max_length=50, choices=FILE_FORMAT, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "file_format")) data_output_type = CharField(max_length=50, choices=DATA_OUTPUT_TYPE, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "data_output_type")) usage = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "usage")) creation_date = CharField(max_length=500, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "creation_date")) created_by = CharField(max_length=200, blank=True, null=True, help_text=rec_help(d.EXPERIMENT_RESULT, "created_by")) extra_properties = JSONField(blank=True, default=dict, validators=[key_value_validator], help_text=rec_help(d.EXPERIMENT_RESULT, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.identifier)
class Biosample(models.Model, IndexableMixin): """ Class to describe a unit of biological material FHIR: Specimen """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.BIOSAMPLE, "id")) # if Individual instance is deleted Biosample instance is deleted too individual = models.ForeignKey( Individual, on_delete=models.CASCADE, blank=True, null=True, related_name="biosamples", help_text=rec_help(d.BIOSAMPLE, "individual_id")) description = models.CharField(max_length=200, blank=True, help_text=rec_help(d.BIOSAMPLE, "description")) sampled_tissue = JSONField(validators=[ontology_validator], help_text=rec_help(d.BIOSAMPLE, "sampled_tissue")) # phenotypic_features = models.ManyToManyField(PhenotypicFeature, blank=True, # help_text='List of phenotypic abnormalities of the sample.') taxonomy = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.BIOSAMPLE, "taxonomy")) # An ISO8601 string represent age individual_age_at_collection = JSONField(blank=True, null=True, validators=[age_or_age_range_validator], help_text=rec_help("individual_age_at_collection")) histological_diagnosis = JSONField( blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.BIOSAMPLE, "histological_diagnosis")) # TODO: Lists? tumor_progression = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.BIOSAMPLE, "tumor_progression")) tumor_grade = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.BIOSAMPLE, "tumor_grade")) diagnostic_markers = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.BIOSAMPLE, "diagnostic_markers")) # CHECK! if Procedure instance is deleted Biosample instance is deleted too procedure = models.ForeignKey(Procedure, on_delete=models.CASCADE, help_text=rec_help(d.BIOSAMPLE, "procedure")) hts_files = models.ManyToManyField( HtsFile, blank=True, related_name='biosample_hts_files', help_text=rec_help(d.BIOSAMPLE, "hts_files")) variants = models.ManyToManyField(Variant, blank=True, help_text=rec_help(d.BIOSAMPLE, "variants")) is_control_sample = models.BooleanField(default=False, help_text=rec_help(d.BIOSAMPLE, "is_control_sample")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.BIOSAMPLE, "extra_properties")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(self.id) @property def get_sample_tissue_data(self): return {'reference': { 'reference': self.sampled_tissue.get('id'), 'display': self.sampled_tissue.get('label') } }
class CancerGeneticVariant(models.Model, IndexableMixin): """ Class to record an alteration in DNA. """ id = models.CharField(primary_key=True, max_length=200, help_text=rec_help(d.CANCER_GENETIC_VARIANT, "id")) data_value = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_GENETIC_VARIANT, "data_value")) method = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_GENETIC_VARIANT, "method")) amino_acid_change = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_GENETIC_VARIANT, "amino_acid_change")) amino_acid_change_type = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help( d.CANCER_GENETIC_VARIANT, "amino_acid_change_type")) cytogenetic_location = JSONField(blank=True, null=True, help_text=rec_help( d.CANCER_GENETIC_VARIANT, "cytogenetic_location")) cytogenetic_nomenclature = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help( d.CANCER_GENETIC_VARIANT, "cytogenetic_nomenclature")) gene_studied = models.ManyToManyField(Gene, blank=True, help_text=rec_help( d.CANCER_GENETIC_VARIANT, "gene_studied")) genomic_dna_change = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help(d.CANCER_GENETIC_VARIANT, "genomic_dna_change")) genomic_source_class = JSONField(blank=True, null=True, validators=[ontology_validator], help_text=rec_help( d.CANCER_GENETIC_VARIANT, "genomic_source_class")) variation_code = JSONField(blank=True, null=True, validators=[ontology_list_validator], help_text=rec_help(d.CANCER_GENETIC_VARIANT, "variation_code")) extra_properties = JSONField(blank=True, null=True, help_text=rec_help(d.CANCER_GENETIC_VARIANT, "extra_properties")) created = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['id'] def __str__(self): return str(self.id)