Skip to content
Snippets Groups Projects
models.py 11.6 KiB
Newer Older
from django.core.exceptions import ValidationError
from django.db import models


# Main biological and medical entities


class PPIDataset(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=128, default='', unique=False)
    link = models.CharField(max_length=128, default='', unique=False)
    version = models.CharField(max_length=128, default='', unique=False)
    licenced = models.BooleanField(default=True)

    def __str__(self):
        return f'{self.name}-{self.version}_{"licenced" if self.licenced else "unlicenced"}'

    class Meta:
        unique_together = ('name', 'version', 'licenced')


class PDIDataset(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=128, default='', unique=False)
    link = models.CharField(max_length=128, default='', unique=False)
    version = models.CharField(max_length=128, default='', unique=False)
    licenced = models.BooleanField(default=True)

    def __str__(self):
        return f'{self.name}-{self.version}_{"licenced" if self.licenced else "unlicenced"}'

    class Meta:
        unique_together = ('name', 'version','licenced')


class PDisDataset(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=128, default='', unique=False)
    link = models.CharField(max_length=128, default='', unique=False)
    version = models.CharField(max_length=128, default='', unique=False)
    licenced = models.BooleanField(default=True)

    def __str__(self):
        return f'{self.name}-{self.version}_{"licenced" if self.licenced else "unlicenced"}'

    class Meta:
        unique_together = ('name', 'version', 'licenced')


class DrDiDataset(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=128, default='', unique=False)
    link = models.CharField(max_length=128, default='', unique=False)
    version = models.CharField(max_length=128, default='', unique=False)
    licenced = models.BooleanField(default=True)

    def __str__(self):
        return f'{self.name}-{self.version}_{"licenced" if self.licenced else "unlicenced"}'

    class Meta:
        unique_together = ('name', 'version', 'licenced')


class EnsemblGene(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=15)  # starts with ENSG...
    protein = models.ForeignKey('Protein', on_delete=models.CASCADE, related_name='ensg')


class Protein(models.Model):
    # According to https://www.uniprot.org/help/accession_numbers UniProt accession codes
    # are either 6 or 10 characters long
    id = models.AutoField(primary_key=True)
    uniprot_code = models.CharField(max_length=10)
    gene = models.CharField(max_length=127, default='')  # symbol
    protein_name = models.CharField(max_length=255, default='')
    entrez = models.CharField(max_length=15, default='')
    drugs = models.ManyToManyField('Drug', through='ProteinDrugInteraction',
                                   related_name='interacting_drugs')
    tissue_expression = models.ManyToManyField('Tissue', through='ExpressionLevel',
                                               related_name='interacting_drugs')

    class Meta:
        unique_together = ('uniprot_code', 'gene', 'entrez')

    def __str__(self):
        return self.gene

AndiMajore's avatar
AndiMajore committed
    def __eq__(self, other):
        return self.uniprot_code == other.uniprot_code and self.gene == other.gene and self.protein_name == other.protein_name and self.entrez == other.entrez

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.uniprot_code, self.gene, self.entrez))

AndiMajore's avatar
AndiMajore committed
    def update(self, other):
        self.uniprot_code = other.uniprot_code
        self.gene = other.gene
        self.protein_name = other.protein_name
        self.entrez = other.entrez
class ExpressionLevel(models.Model):
    id = models.AutoField(primary_key=True)
    tissue = models.ForeignKey('Tissue', on_delete=models.CASCADE)
    protein = models.ForeignKey('Protein', on_delete=models.CASCADE)
    expression_level = models.FloatField()

    class Meta:
        unique_together = ('tissue', 'protein')

    def __hash__(self):
        return hash(f'{self.tissue_id}_{self.protein_id}')


class Tissue(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=128, default='', unique=True)

    def __str__(self):
        return self.name


class Disorder(models.Model):
    id = models.AutoField(primary_key=True)
    mondo_id = models.CharField(max_length=7)
AndiMajore's avatar
AndiMajore committed
    label = models.CharField(max_length=256, default='')  # symbol
AndiMajore's avatar
AndiMajore committed
    icd10 = models.CharField(max_length=512, default='')
    proteins = models.ManyToManyField(
        'Protein', through='ProteinDisorderAssociation', related_name='associated_proteins')

    class Meta:
        unique_together = ('mondo_id', 'label', 'icd10')

    def __str__(self):
        return self.label

AndiMajore's avatar
AndiMajore committed
    def __eq__(self, other):
        return self.mondo_id == other.mondo_id and self.label == other.label and self.icd10 == other.icd10

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.mondo_id, self.label, self.icd10))

AndiMajore's avatar
AndiMajore committed
        self.mondo_id = other.mondo_id
        self.label = other.label
        self.icd10 = other.icd10


class Drug(models.Model):
    id = models.AutoField(primary_key=True)
AndiMajore's avatar
AndiMajore committed
    drug_id = models.CharField(max_length=10, unique=True)
    name = models.CharField(max_length=256, default='')
    status = models.CharField(max_length=128, default='')
    # in_trial = models.BooleanField(default=False)
    # in_literature = models.BooleanField(default=False)
    links = models.CharField(max_length=16 * 1024, default='')

    def __str__(self):
        return self.drug_id

    def __eq__(self, other):
        return self.drug_id == other.drug_id and self.name == other.name and self.status == other.status
AndiMajore's avatar
AndiMajore committed

AndiMajore's avatar
AndiMajore committed
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.drug_id, self.name, self.status))

AndiMajore's avatar
AndiMajore committed
    def update(self, other):
        self.drug_id = other.drug_id
        self.name = other.name
        self.status = other.status
        self.links = other.links


class ProteinDisorderAssociation(models.Model):
    id = models.BigAutoField(primary_key=True)
    pdis_dataset = models.ForeignKey(
        'PDisDataset', null=True, on_delete=models.CASCADE, related_name='pdis_dataset_relation')
    protein = models.ForeignKey('Protein', on_delete=models.CASCADE)
    disorder = models.ForeignKey('Disorder', on_delete=models.CASCADE)
    score = models.FloatField()

    class Meta:
        unique_together = ('pdis_dataset', 'protein', 'disorder')

    def __str__(self):
        return f'{self.pdis_dataset}-{self.protein}-{self.disorder}'

    def __eq__(self, other):
        return self.pdis_dataset_id == other.pdis_dataset_id and self.protein_id == other.protein_id and self.disorder_id == other.disorder_id

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.pdis_dataset_id, self.protein_id, self.disorder_id))


class DrugDisorderIndication(models.Model):
    id = models.AutoField(primary_key=True)
    drdi_dataset = models.ForeignKey(
        'DrDiDataset', null=True, on_delete=models.CASCADE, related_name='drdi_dataset_relation')
    drug = models.ForeignKey('Drug', on_delete=models.CASCADE)
    disorder = models.ForeignKey('Disorder', on_delete=models.CASCADE)

    class Meta:
        unique_together = ('drdi_dataset', 'drug', 'disorder')

    def __str__(self):
        return f'{self.drdi_dataset}-{self.drug}-{self.disorder}'

    def __eq__(self, other):
        return self.drdi_dataset_id == other.drdi_dataset_id and self.drug_id == other.drug_id and self.disorder_id == other.disorder_id
    def __ne__(self, other):
        return not self.__eq__(other)
    def __hash__(self):
        return hash((self.drdi_dataset_id, self.drug_id, self.disorder_id))


class ProteinProteinInteraction(models.Model):
    id = models.BigAutoField(primary_key=True)
    ppi_dataset = models.ForeignKey(
        'PPIDataset', null=True, on_delete=models.CASCADE, related_name='ppi_dataset_relation')
    from_protein = models.ForeignKey('Protein', on_delete=models.CASCADE, related_name='interacting_proteins_out')
    to_protein = models.ForeignKey('Protein', on_delete=models.CASCADE, related_name='interacting_proteins_in')

    def validate_unique(self, exclude=None):
        p1p2_q = ProteinProteinInteraction.objects.filter(
            from_protein=self.from_protein,
            to_protein=self.to_protein,
            ppi_dataset=self.ppi_dataset
AndiMajore's avatar
AndiMajore committed
        )
        p2p1_q = ProteinProteinInteraction.objects.filter(
            from_protein=self.to_protein,
            to_protein=self.from_protein,
            ppi_dataset=self.ppi_dataset
AndiMajore's avatar
AndiMajore committed
        )

        if p1p2_q.exists() or p2p1_q.exists():
            raise ValidationError('Protein-Protein interaction must be unique!')

    def save(self, *args, **kwargs):
        self.validate_unique()
        super(ProteinProteinInteraction, self).save(*args, **kwargs)

    def __str__(self):
        return f'{self.ppi_dataset}-{self.from_protein}-{self.to_protein}'

    def __eq__(self, other):
        return self.ppi_dataset_id == other.ppi_dataset_id and self.from_protein_id == other.from_protein_id and self.to_protein_id == other.to_protein_id

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.ppi_dataset_id, self.from_protein_id, self.to_protein_id))


class ProteinDrugInteraction(models.Model):
    id = models.BigAutoField(primary_key=True)
    pdi_dataset = models.ForeignKey(
        PDIDataset, null=True, on_delete=models.CASCADE, related_name='pdi_dataset_relation')
    protein = models.ForeignKey('Protein', on_delete=models.CASCADE)
    drug = models.ForeignKey('Drug', on_delete=models.CASCADE)

    class Meta:
        unique_together = ('pdi_dataset', 'protein', 'drug')

    def __str__(self):
        return f'{self.pdi_dataset}-{self.protein}-{self.drug}'

    def __eq__(self, other):
        return self.pdi_dataset_id == other.pdi_dataset_id and self.protein_id == other.protein_id and self.drug_id == other.drug_id

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.pdi_dataset_id, self.protein_id, self.drug_id))


class Task(models.Model):
    token = models.CharField(max_length=32, unique=True, primary_key=True)
    created_at = models.DateTimeField(auto_now_add=True)
    target = models.CharField(max_length=32, choices=[('drug', 'Drug'), ('drug-target', 'Drug Target')])

    algorithm = models.CharField(max_length=128)
    parameters = models.TextField()

    progress = models.FloatField(default=0.0)  # Progress as fraction (0.0 - 1.0)
    started_at = models.DateTimeField(null=True)
    finished_at = models.DateTimeField(null=True)
    worker_id = models.CharField(max_length=128, null=True)
    job_id = models.CharField(max_length=128, null=True)
    done = models.BooleanField(default=False)
    failed = models.BooleanField(default=False)
    status = models.CharField(max_length=255, null=True)

    result = models.TextField(null=True)


class Network(models.Model):
    id = models.CharField(primary_key=True, max_length=32, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    nodes = models.TextField(null=True, default='')
    edges = models.TextField(null=True, default='')
    config = models.TextField(null=True, default='')
    groups = models.TextField(null=True, default='')