models.py 17 KB
Newer Older
Hervé  MENAGER's avatar
Hervé MENAGER committed
1
2
3
4
from __future__ import unicode_literals

from django.db import models

5
from .ws import get_pubmed_info, get_epo_info, get_uniprot_info, get_taxonomy_info, get_go_info, get_pfam_info
6

Hervé  MENAGER's avatar
Hervé MENAGER committed
7
8
9
10
11
12
13
14
15
16
17
class Bibliography(models.Model):
    """
    Bibliography data table
    """
    SOURCES = (
        ('PM', 'PubMed article'),
        ('PT', 'Patent')
    )
    source = models.CharField('Bibliographic type', max_length=2, choices=SOURCES)
    id_source = models.CharField('Bibliographic ID', max_length=25)
    title = models.CharField('Title', max_length=300)
18
    journal_name = models.CharField('Journal name', max_length=50, null=True)
Hervé  MENAGER's avatar
Hervé MENAGER committed
19
20
    authors_list = models.CharField('Authors list', max_length=500)
    biblio_year = models.PositiveSmallIntegerField('Year')
21
22
23
24
25
26
27
    cytotox = models.BooleanField('Cytotoxicity data', default=False)
    in_silico = models.BooleanField('in silico study performed', default=False)
    in_vitro = models.BooleanField('in vitro study performed', default=False)
    in_vivo = models.BooleanField('in vivo study performed', default=False)
    in_cellulo = models.BooleanField('in cellulo study performed', default=False)
    pharmacokinetic = models.BooleanField('pharmacokinetic study performed', default=False)
    xray = models.BooleanField('contains xray data', default=False)
Hervé  MENAGER's avatar
Hervé MENAGER committed
28
29

    def save(self, *args, **kwargs):
30
31
32
33
34
35
36
37
        if self.source == 'PM':
            info = get_pubmed_info(self.id_source)
        else:
            info = get_epo_info(self.id_source)
        self.title = info['title']
        self.journal_name = info['journal_name']
        self.authors_list = info['authors_list']
        self.biblio_year = info['biblio_year']
Hervé  MENAGER's avatar
Hervé MENAGER committed
38
39
        super(Bibliography, self).save(*args, **kwargs)

Hervé  MENAGER's avatar
Hervé MENAGER committed
40
41
42
    class Meta:
        verbose_name_plural = "bibliographies"

43

Hervé  MENAGER's avatar
Hervé MENAGER committed
44
45

class Taxonomy(models.Model):
46
    taxonomy_id = models.DecimalField('NCBI TaxID', unique=True, max_digits=9, decimal_places=0)
Hervé  MENAGER's avatar
Hervé MENAGER committed
47
    name = models.CharField('Organism name', max_length=200)
48
49
50
51
52
53

    def save(self, *args, **kwargs):
        info = get_taxonomy_info(self.taxonomy_id)
        self.name = info['scientific_name']
        super(Taxonomy, self).save(*args, **kwargs)

54
55
56
    def __str__(self):
        return self.name

Hervé  MENAGER's avatar
Hervé MENAGER committed
57
58
    class Meta:
        verbose_name_plural = "taxonomies"
Hervé  MENAGER's avatar
Hervé MENAGER committed
59
60
61
62
63

class MolecularFunction(models.Model):
    go_id = models.CharField('Gene Ontology ID', unique=True, max_length=10) # GO term id format: 'GO:0000000' 
    description = models.CharField('description', max_length=500)

64
65
66
67
68
    def save(self, *args, **kwargs):
        info = get_go_info(self.go_id)
        self.description = info['label']
        super(MolecularFunction, self).save(*args, **kwargs)

69
70
71
    def __str__(self):
        return self.description

Hervé  MENAGER's avatar
Hervé MENAGER committed
72
73
74
75
76
77
78
79
80
class Protein(models.Model):
    uniprot_id = models.CharField('Uniprot ID', unique=True, max_length=10)
    recommended_name_long = models.CharField('Uniprot Recommended Name (long)', max_length=75)
    short_name = models.CharField('Short name', max_length=50)
    gene_name = models.CharField('Gene name', unique=True, max_length=30)
    entry_name = models.CharField('Entry name', max_length=30)
    organism = models.ForeignKey('Taxonomy')
    molecular_functions = models.ManyToManyField(MolecularFunction)

81
    def save(self, *args, **kwargs):
82
        info = get_uniprot_info(self.uniprot_id)
83
        self.recommended_name_long = info['recommended_name']
84
85
86
87
88
89
90
91
92
        self.gene_name = info['gene']
        self.entry_name = info['entry_name']
        try:
            taxonomy = Taxonomy.objects.get(taxonomy_id=info['organism'])
        except Taxonomy.DoesNotExist:
            taxonomy = Taxonomy()
            taxonomy.taxonomy_id = info['organism']
            taxonomy.save()
        self.organism = taxonomy
93
        super(Protein, self).save(*args, **kwargs)
94
95
96
97
98
99
100
101
        for go_id in info['molecular_functions']:
            try:
                mol_function = MolecularFunction.objects.get(go_id=go_id)
            except MolecularFunction.DoesNotExist:
                mol_function = MolecularFunction()
                mol_function.go_id = go_id
                mol_function.save()
            self.molecular_functions.add(mol_function)
102

103
104
105
    def __str__(self):
        return '{} ({})'.format(self.uniprot_id, self.recommended_name_long)

Hervé  MENAGER's avatar
Hervé MENAGER committed
106
107
108
109
class Domain(models.Model):
    pfam_acc = models.CharField('Pfam Accession', max_length=10, unique=True) 
    pfam_id = models.CharField('Pfam Family Identifier', max_length=20) 
    pfam_description = models.CharField('Pfam Description', max_length=100)
110
111
112
113
114
115
116
    domain_family = models.CharField('Domain family', max_length=25)  #TODO: what is this field? check database contents

    def save(self, *args, **kwargs):
        info = get_pfam_info(self.pfam_acc)
        self.pfam_id = info['id']
        self.pfam_description = info['description']
        super(Domain, self).save(*args, **kwargs)
Hervé  MENAGER's avatar
Hervé MENAGER committed
117

118
119
120
    def __str__(self):
        return '{} ({}-{})'.format(self.pfam_acc, self.pfam_id, self.pfam_description)

121
class ProteinDomainComplex(models.Model):
122
123
    protein = models.ForeignKey('Protein')
    domain = models.ForeignKey('Domain')
124
125
    ppc_copy_nb = models.IntegerField('Number of copies of the protein in the complex')
    
Hervé  MENAGER's avatar
Hervé MENAGER committed
126
127
    class Meta:
        verbose_name_plural = "complexes"
128

129
130
131
    def __str__(self):
        return '{}-{}'.format(self.protein_id, self.domain_id)

132
133
134
135
136
class ProteinDomainBoundComplex(ProteinDomainComplex):
    ppp_copy_nb_per_p = models.IntegerField('Number of copies of the protein in the pocket')
    pockets_nb = models.IntegerField('Total number of pockets in the complex')
    class Meta:
        verbose_name_plural = "bound complexes"
Hervé  MENAGER's avatar
Hervé MENAGER committed
137
    
138
139
140
class ProteinDomainPartnerComplex(ProteinDomainComplex):
    class Meta:
        verbose_name_plural = "partner complexes"
Hervé  MENAGER's avatar
Hervé MENAGER committed
141

142
143
144
class Symmetry(models.Model):
    code = models.CharField('Symmetry code', max_length=2)
    description = models.CharField('Description', max_length=300)
Hervé  MENAGER's avatar
Hervé MENAGER committed
145

146
147
148
    class Meta:
        verbose_name_plural = "symmetries"

149
150
151
    def __str__(self):
        return '{} ({})'.format(self.code, self.description)

152
153
class Ppi(models.Model):
    ppi_id = models.IntegerField('PPI identifier')
154
    complex = models.ForeignKey(ProteinDomainComplex)
155
    cc_nb = models.IntegerField('Number of copies of the complex in the PPI', default=1)
Hervé  MENAGER's avatar
Hervé MENAGER committed
156
    pdb_id = models.CharField('PDB ID', max_length=4)
157
    symmetry = models.ForeignKey(Symmetry)
Hervé  MENAGER's avatar
Hervé MENAGER committed
158

159
class Disease(models.Model):
160
    ppi = models.ForeignKey(Ppi)
161
    disease_name = models.CharField('Disease', max_length=30) # is there any database/nomenclature for diseases?
Hervé  MENAGER's avatar
Hervé MENAGER committed
162
163


164
class Compound(models.Model):
Hervé  MENAGER's avatar
Hervé MENAGER committed
165
    canonical_smile = models.CharField('Canonical Smile', unique=True, max_length=500)
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    #TODO index this table on canonical_smile
    is_macrocycle = models.BooleanField('Contains one or more macrocycles') 
    aromatic_ratio = models.DecimalField('Aromatic ratio', max_digits=3, decimal_places=2)
    balaban_index = models.DecimalField('Balaban index', max_digits=3, decimal_places=2)  
    fsp3 = models.DecimalField('Fsp3', max_digits=3, decimal_places=2)
    gc_molar_refractivity = models.DecimalField('GC Molar Refractivity', max_digits=5, decimal_places=2)
    log_d = models.DecimalField('LogD (Partition coefficient octanol-1/water, with pKa information)', max_digits=4, decimal_places=2)
    a_log_p = models.DecimalField('ALogP (Partition coefficient octanol-1/water)', max_digits=4, decimal_places=2)
    mean_atom_vol_vdw = models.DecimalField('Mean atom volume computed with VdW radii', max_digits=4, decimal_places=2)
    molecular_weight = models.DecimalField('Molecular weight', max_digits=6, decimal_places=2)
    nb_acceptor_h = models.IntegerField('Number of hydrogen bond acceptors')
    nb_aliphatic_amines = models.IntegerField('Number of aliphatics amines')
    nb_aromatic_bonds = models.IntegerField('Number of aromatic bonds')
    nb_aromatic_ether = models.IntegerField('Number of aromatic ethers')
    nb_aromatic_sssr = models.IntegerField('Number of aromatic Smallest Set of System Rings (SSSR)')
    nb_atom = models.IntegerField('Number of atoms') 
    nb_atom_non_h = models.IntegerField('Number of non hydrogen atoms') 
    nb_benzene_like_rings = models.IntegerField('Number of benzene-like rings')
    nb_bonds = models.IntegerField('Number of bonds')
    nb_bonds_non_h = models.IntegerField('Number of bonds not involving a hydrogen')  
    nb_br = models.IntegerField('Number of Bromine atoms')  
    nb_c = models.IntegerField('Number of Carbon atoms')  
    nb_chiral_centers = models.IntegerField('Number of chiral centers')  
    nb_circuits = models.IntegerField('Number of circuits')  
    nb_cl = models.IntegerField('Number of Chlorine atoms')  
    nb_csp2 = models.IntegerField('Number of sp2-hybridized carbon atoms')  
    nb_csp3 = models.IntegerField('Number of sp3-hybridized carbon atoms')  
    nb_donor_h = models.IntegerField('Number of hydrogen bond donors')  
    nb_double_bonds = models.IntegerField('Number of double bonds')  
    nb_f = models.IntegerField('Number of fluorine atoms')  
    nb_i = models.IntegerField('Number of iodine atoms')  
    nb_multiple_bonds = models.IntegerField('Number of multiple bonds')  
    nb_n = models.IntegerField('Number of nitrogen atoms')
    nb_o = models.IntegerField('Number of oxygen atoms')  
    nb_rings = models.IntegerField('Number of rings')  
    nb_rotatable_bonds = models.IntegerField('Number of rotatable bonds')  
    randic_index = models.DecimalField('Randic index', max_digits=4, decimal_places=2)  
    rdf070m = models.DecimalField('RDF070m, radial distribution function weighted by the atomic masses at 7Å', max_digits=5, decimal_places=2)  
    rotatable_bond_fraction = models.DecimalField('Fraction of rotatable bonds', max_digits=3, decimal_places=2)  
    sum_atom_polar = models.DecimalField('Sum of atomic polarizabilities', max_digits=5, decimal_places=2)  
    sum_atom_vol_vdw = models.DecimalField('Sum of atom volumes computed with VdW radii', max_digits=6, decimal_places=2)  
    tpsa = models.DecimalField('Topological Polar Surface Area (TPSA)', max_digits=5, decimal_places=2)  
    ui = models.DecimalField('Unsaturation index', max_digits=4, decimal_places=2)  
    wiener_index = models.IntegerField('Wiener index')  
    common_name = models.CharField('Common name', unique=True, max_length=20, blank=True, null=True)  
    pubchem_id = models.CharField('Pubchem ID', unique=True, max_length=10, blank=True, null=True)  
    chemspider_id = models.CharField('Chemspider ID', unique=True, max_length=10, blank=True, null=True)  
    chembl_id = models.CharField('Chembl ID', unique=True, max_length=30, blank=True, null=True)  
    iupac_name = models.CharField('IUPAC name', unique=True, max_length=255, blank=True, null=True)  
215
    mddr_compound = models.ForeignKey('MDDRCompoundImport', blank=True, null=True)  
216
217
218
219
220
221
222
223
224


class MDDRCompoundImport(models.Model):
    mddr_compound_id = models.IntegerField('MDDR compound ID')  
    mddr_name = models.CharField('MDDR name', max_length=40)  
    dvpmt_phase = models.CharField('Development phase', max_length=20)  
    canonical_smile = models.CharField('Canonical Smile', max_length=500, unique=True, blank=True, null=True)  
    #TODO index this table on canonical_smile
    db_import_date = models.DecimalField('MDDR release year/month', max_digits=6, decimal_places=0)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
225

226
227
228
229
    class Meta:
        # over multiple releases of the MDDR database, the same compound can evolve in its development phase
        # the same compound can have different names and development phases in the same MDDR release
        unique_together = (('mddr_compound_id', 'mddr_name', 'dvpmt_phase'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
230
        verbose_name_plural = "MDDR compound imports"
Hervé  MENAGER's avatar
Hervé MENAGER committed
231
232


233
class MDDRCompoundActivityClass(models.Model):
234
    mddr_compound = models.ForeignKey(MDDRCompoundImport)  
235
    activity_class = models.CharField('Activity Class', max_length=100)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
236
237

    class Meta:
238
        unique_together = (('mddr_compound', 'activity_class'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
239
        verbose_name_plural = "MDDR compound activity classes"
Hervé  MENAGER's avatar
Hervé MENAGER committed
240
241


242
243
244
245
class MDDRSimilarity(models.Model):
    canonical_smile_ippidb = models.CharField('Canonical Smile for IPPIDB compound', max_length=500, unique=True, blank=True, null=True)
    canonical_smile_mddr = models.CharField('Canonical Smile for MDDR Compound', max_length=500, unique=True, blank=True, null=True)
    tanimoto = models.DecimalField('Tanimoto', max_digits=6, decimal_places=5)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
246
247

    class Meta:
248
        unique_together = (('canonical_smile_ippidb', 'canonical_smile_mddr'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
249
        verbose_name_plural = "MDDR similarities"
250

251
252
class CellLine(models.Model):
    name = models.CharField('Name', max_length=50, unique=True)
Hervé  MENAGER's avatar
Hervé MENAGER committed
253

254
255
256
257
258
259
260
261
262
263
class TestActivityDescription(models.Model):
    TEST_TYPES = (
        ('BIOCH', 'Biochemical assay'),
        ('CELL', 'Cellular assay')
    )
    TEST_MODULATION_TYPES = (
        ('B', 'Binding'),
        ('I', 'Inhibition'),
        ('S', 'Stabilization')
    )
264
265
266
    complex = models.ForeignKey(ProteinDomainBoundComplex)
    biblio = models.ForeignKey(Bibliography)
    ppi = models.ForeignKey(Ppi, blank=True, null=True)  
267
268
269
270
271
272
273
274
275
276
    test_name = models.CharField('Test name', max_length=100)  
    test_type = models.CharField('Test type', max_length=5, choices=TEST_TYPES)
    test_modulation_type = models.CharField('Test modulation type', max_length=1, choices=TEST_MODULATION_TYPES)
    nb_active_compounds = models.IntegerField('Total number of active compounds')  
    cell_line = models.ForeignKey(CellLine)

class ActivityType(models.Model):
    name = models.CharField('Name', max_length=50, unique=True)

class CompoundActivityResult(models.Model):
277
278
279
280
281
    MODULATION_TYPES = (
        ('B', 'Binding'),
        ('I', 'Inhibition'),
        ('S', 'Stabilization')
    )
282
283
284
    compound = models.ForeignKey(Compound)  
    test_activity_description = models.ForeignKey(TestActivityDescription)  
    activity_type = models.ForeignKey(ActivityType)  
285
    activity = models.DecimalField('Activity', max_digits=12, decimal_places=10)  
286
    modulation_type = models.CharField('Modulation type', max_length=1, choices=MODULATION_TYPES)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
287
288

    class Meta:
289
        unique_together = (('compound', 'test_activity_description', 'activity_type'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
290

291
class TestCytotoxDescription(models.Model):
292
    biblio = models.ForeignKey(Bibliography)  
293
294
295
    test_name = models.CharField('Cytotoxicity test name', max_length=100)  
    cell_line = models.ForeignKey(CellLine)
    compound_concentration = models.DecimalField('Compound concentration in μM', max_digits=7, decimal_places=3, blank=True, null=True)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
296

297
class CompoundCytotoxicityResult(models.Model):
298
299
    compound = models.ForeignKey(Compound)  
    test_cytotoxicity_description = models.ForeignKey(TestCytotoxDescription)
300
    toxicity = models.BooleanField('Toxicity', default=False)
Hervé  MENAGER's avatar
Hervé MENAGER committed
301
302

    class Meta:
303
        unique_together = (('compound', 'test_cytotoxicity_description'),)
304
305
306
307
308

class AdministrationMode(models.Model):
    name = models.CharField('Administration mode', max_length=20, blank=True, null=True)

class TestPKDescription(models.Model):
309
    biblio = models.ForeignKey(Bibliography)  
310
311
312
313
314
315
316
    test_name = models.CharField('Pharmacokinetic test name', max_length=100)  
    organism = models.ForeignKey(Taxonomy)
    administration_mode = models.ForeignKey(AdministrationMode, blank=True, null=True)  
    dose = models.DecimalField('Dose in mg/kg', max_digits=7, decimal_places=4, blank=True, null=True)  
    dose_interval = models.IntegerField('Dose interval, in hours', blank=True, null=True)  

class CompoundPKResult(models.Model):
317
318
    compound = models.ForeignKey(Compound)  
    test_pk_description = models.ForeignKey(TestPKDescription)
319
320
321
322
323
324
325
326
    tolerated = models.NullBooleanField('Tolerated', null=True)
    auc = models.IntegerField('Area under curve (ng.mL-1.hr)', blank=True, null=True)  
    clearance = models.DecimalField('Clearance (mL/hr)', max_digits=7, decimal_places=3, blank=True, null=True)  
    cmax = models.DecimalField('Maximal concentration (ng/mL)', max_digits=7, decimal_places=3, blank=True, null=True)  
    oral_bioavailability = models.IntegerField('Oral Bioavailability (%F)', blank=True, null=True)  
    t_demi = models.IntegerField('t½', blank=True, null=True)  
    t_max = models.IntegerField('tmax', blank=True, null=True)  
    voldistribution = models.DecimalField('Volume distribution (Vd)', max_digits=5, decimal_places=2, blank=True, null=True)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
327
328

    class Meta:
329
        unique_together = (('compound', 'test_pk_description'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
330
331


332
333
334
class CmpdAction(models.Model):
    ACTIVATION_MODES = (
        ('O', 'Orthosteric'),
335
        ('A', 'Allosteric')
336
    )
337
338
    complex = models.ForeignKey(ProteinDomainBoundComplex)
    compound = models.ForeignKey(Compound)  
339
    activation_mode = models.CharField('Activation mode', max_length=1, choices=ACTIVATION_MODES)  
340
    ppi = models.ForeignKey(Ppi)
341
342
    pdb_id = models.CharField('PDB ID', max_length=4)
    nb_copy_compounds = models.IntegerField('Number of copies for the compound')  
Hervé  MENAGER's avatar
Hervé MENAGER committed
343
344

    class Meta:
345
        unique_together = (('complex', 'compound', 'pdb_id'),)
Hervé  MENAGER's avatar
Hervé MENAGER committed
346

347
class RefCompoundBiblio(models.Model):
348
349
    compound = models.ForeignKey(Compound)  
    bibliography = models.ForeignKey(Bibliography)  
350
    compound_name = models.CharField('Compound name in the publication', max_length=50)  
Hervé  MENAGER's avatar
Hervé MENAGER committed
351
352

    class Meta:
353
        unique_together = (('compound', 'bibliography'),)