diff --git a/ippisite/db.sqlite3 b/ippisite/db.sqlite3 deleted file mode 100644 index 54ce807e6aa9dacb5042158a9d03fbb8b299edf6..0000000000000000000000000000000000000000 Binary files a/ippisite/db.sqlite3 and /dev/null differ diff --git a/ippisite/db.sqlite3.REMOVED.git-id b/ippisite/db.sqlite3.REMOVED.git-id new file mode 100644 index 0000000000000000000000000000000000000000..cb9c5e1693a3710e494a1ba429eeae1858babf29 --- /dev/null +++ b/ippisite/db.sqlite3.REMOVED.git-id @@ -0,0 +1 @@ +067f156ca37c93920f1a15dac26337a9956fccbb \ No newline at end of file diff --git a/ippisite/ippidb/admin.py b/ippisite/ippidb/admin.py index 84f0182710f92258d32496198e4c561823df6199..3b32cd020b9245306579d28bf9379a49357f6f86 100644 --- a/ippisite/ippidb/admin.py +++ b/ippisite/ippidb/admin.py @@ -20,13 +20,29 @@ class DomainAdmin(admin.ModelAdmin): @admin.register(ProteinDomainBoundComplex) class ProteinDomainBoundComplexAdmin(admin.ModelAdmin): - list_display = ('protein_id', 'domain_id', 'ppc_copy_nb', 'ppp_copy_nb_per_p', 'pockets_nb') - list_display_links = ('protein_id', 'domain_id', 'ppc_copy_nb', 'ppp_copy_nb_per_p', 'pockets_nb') + list_display = ('protein', 'domain', 'ppc_copy_nb', 'ppp_copy_nb_per_p') + list_display_links = ('protein', 'domain', 'ppc_copy_nb', 'ppp_copy_nb_per_p') @admin.register(ProteinDomainPartnerComplex) class ProteinDomainPartnerComplexAdmin(admin.ModelAdmin): - list_display = ('protein_id', 'domain_id', 'ppc_copy_nb') - list_display_links = ('protein_id', 'domain_id', 'ppc_copy_nb') + list_display = ('protein', 'domain', 'ppc_copy_nb') + list_display_links = ('protein', 'domain', 'ppc_copy_nb') + +@admin.register(Symmetry) +class Symmetry(admin.ModelAdmin): + list_display = ('code', 'description') + +@admin.register(MDDRCompoundImport) +class MDDRCompoundImport(admin.ModelAdmin): + list_display = ('mddr_name', 'dvpmt_phase', 'canonical_smile') + +@admin.register(Compound) +class Compound(admin.ModelAdmin): + list_display = ('iupac_name', 'common_name', 'canonical_smile') + +@admin.register(TestActivityDescription) +class TextActivityDescription(admin.ModelAdmin): + list_display = ('test_name', 'test_type', 'test_modulation_type') for model in apps.get_app_config('ippidb').models.values(): try: diff --git a/ippisite/ippidb/forms.py b/ippisite/ippidb/forms.py index 955a5f723bce8600bb86e28d87dc9b057c4b7255..7b6f3a5464387d28aa106a1e543b2809b470162e 100644 --- a/ippisite/ippidb/forms.py +++ b/ippisite/ippidb/forms.py @@ -1,7 +1,7 @@ from django.forms import ModelForm from django import forms from django.db import models -from .models import Bibliography, Protein, ProteinDomainComplex, Ppi +from .models import Bibliography, Protein, ProteinDomainComplex, Ppi, PpiComplex class IdForm(forms.Form): id = forms.CharField(label="",max_length=100, widget=forms.TextInput(attrs={'placeholder': 'PubMed ID / DOI / Patent ID'})) @@ -62,10 +62,14 @@ class ProteinDomainComplexTypeForm(forms.Form): class ProteinDomainComplexForm(ModelForm): class Meta: model = ProteinDomainComplex - fields = ['protein_id', 'domain_id', 'ppc_copy_nb'] - + fields = ['protein', 'domain', 'ppc_copy_nb'] class PpiForm(ModelForm): class Meta: model = Ppi - fields = ['complex_id', 'cc_nb', 'pdb_id', 'symmetry_id'] + fields = ['pdb_id', 'symmetry'] + +class PpiComplexForm(ModelForm): + class Meta: + model = PpiComplex + fields = ['complex', 'cc_nb'] diff --git a/ippisite/ippidb/management/commands/import_v1_data.py b/ippisite/ippidb/management/commands/import_v1_data.py index 7de942bfb3338deea3efe79377b0147a6ab3eea3..30a3cab000463365178d210dce125f41096eac6e 100644 --- a/ippisite/ippidb/management/commands/import_v1_data.py +++ b/ippisite/ippidb/management/commands/import_v1_data.py @@ -1,8 +1,25 @@ +import glob + +from django.utils import timezone from django.core.management import BaseCommand, CommandError import mysql.connector +from pybel import readfile from ippidb.models import Bibliography, Protein, Taxonomy, MolecularFunction, \ - Domain, ProteinDomainBoundComplex, ProteinDomainPartnerComplex + Domain, ProteinDomainBoundComplex, ProteinDomainPartnerComplex, Symmetry, Ppi, PpiComplex, Disease, \ + Compound, MDDRCompoundImport, MDDRActivityClass, TestActivityDescription, CellLine + +class MyConverter(mysql.connector.conversion.MySQLConverter): + + def row_to_python(self, row, fields): + row = super(MyConverter, self).row_to_python(row, fields) + + def to_unicode(col): + if type(col) == bytearray: + return col.decode('utf-8') + return col + + return[to_unicode(col) for col in row] class Command(BaseCommand): @@ -31,11 +48,39 @@ class Command(BaseCommand): help='Flush and migrate domains', ) parser.add_argument( - '--complexes', + '--symmetries', action='store_true', - dest='complexes', + dest='symmetries', default=False, - help='Flush and migrate complexes', + help='Flush and create symmetries', + ) + parser.add_argument( + '--ppi', + action='store_true', + dest='ppi', + default=False, + help='Flush and migrate ppis and complexes', + ) + parser.add_argument( + '--mddr', + action='store_true', + dest='mddr', + default=False, + help='Flush and import MDDR database', + ) + parser.add_argument( + '--compound', + action='store_true', + dest='compound', + default=False, + help='Flush and migrate compounds', + ) + parser.add_argument( + '--test-activity-description', + action='store_true', + dest='test-activity-description', + default=False, + help='Flush and migrate test activity descriptions', ) parser.add_argument( '--stoponfail', @@ -47,7 +92,7 @@ class Command(BaseCommand): def handle(self, *args, **options): - conn = mysql.connector.connect(host="localhost",user="root",password="ippidb", database="ippidb") + conn = mysql.connector.connect(converter_class=MyConverter, host="localhost", user="root", password="ippidb", database="ippidb") cursor = conn.cursor() if options['bibliographies']: cursor.execute("""SELECT * FROM biblio""") @@ -110,29 +155,83 @@ class Command(BaseCommand): self.stdout.write(self.style.ERROR('Failed inserting {} {}'.format(row[1], row[2]))) else: self.stdout.write(self.style.SUCCESS('Successfully inserted {} {}'.format(row[1], row[2]))) - if options['complexes']: + if options['symmetries']: + Symmetry.objects.all().delete() + self.stdout.write(self.style.SUCCESS('Successfully flushed symmetries table')) + rows = [ + ['AS', 'asymmetric'], + ['C2', 'C2 symmetry'], + ['D2', 'D2 symmetry'], + ['C3', 'C3 symmetry'], + ['D3', 'D3 symmetry'], + ['C4', 'C4 symmetry'], + ['D4', 'D4 symmetry'], + ['C5', 'C5 symmetry'], + ['D5', 'D5 symmetry'], + ] + for row in rows: + try: + symmetry = Symmetry() + symmetry.code = row[0] + symmetry.description = row[1] + symmetry.save() + except Exception as e: + if options['stoponfail']: + import traceback + self.stderr.write(traceback.format_exc()) + raise CommandError('Failed inserting {} {}'.format(row[0], row[1])) + else: + self.stdout.write(self.style.ERROR('Failed inserting {} {}'.format(row[0], row[1]))) + else: + self.stdout.write(self.style.SUCCESS('Successfully inserted {} {}'.format(row[0], row[1]))) + if options['ppi']: sql_request_string = ''' - select distinct protein.NumUniprot, domain.PfamNumAccession , complexe.NbCopy, cmpdAction.IDComplexeBound from bindingSite inner join ppi on (bindingSite.IDBindingSite=ppi.IDBindingSite1) inner join complexe on (ppi.IDComplexe1=complexe.IDComplexe) left outer join cmpdAction on (complexe.IDComplexe=cmpdAction.IDComplexeBound) inner join protein on (bindingSite.IDProtein=protein.IDProtein) inner join domain on (bindingSite.IDDomain=domain.IDDomain) union select distinct protein.NumUniprot, domain.PfamNumAccession , complexe.NbCopy, cmpdAction.IDComplexeBound from bindingSite inner join ppi on (bindingSite.IDBindingSite=ppi.IDBindingSite2) inner join complexe on (ppi.IDComplexe2=complexe.IDComplexe) left outer join cmpdAction on (complexe.IDComplexe=cmpdAction.IDComplexeBound) inner join protein on (bindingSite.IDProtein=protein.IDProtein) inner join domain on (bindingSite.IDDomain=domain.IDDomain)''' +select distinct protein.NumUniprot, domain.PfamNumAccession, complexe.NbCopy, cmpdAction.IDComplexeBound, bindingSiteEvidence.CodePDB, 'part1', ppi.IDPPI, disease.Disease from bindingSite inner join ppi on (bindingSite.IDBindingSite=ppi.IDBindingSite1) inner join complexe on (ppi.IDComplexe1=complexe.IDComplexe) left outer join cmpdAction on (complexe.IDComplexe=cmpdAction.IDComplexeBound) inner join protein on (bindingSite.IDProtein=protein.IDProtein) inner join domain on (bindingSite.IDDomain=domain.IDDomain) inner join disease on (disease.IDPPI=ppi.IDPPI) left outer join bindingSiteEvidence on (ppi.IDPPI=bindingSiteEvidence.IDPPI) +union +select distinct protein.NumUniprot, domain.PfamNumAccession , complexe.NbCopy, cmpdAction.IDComplexeBound, null, 'part2', ppi.IDPPI, disease.Disease from bindingSite inner join ppi on (bindingSite.IDBindingSite=ppi.IDBindingSite2) inner join complexe on (ppi.IDComplexe2=complexe.IDComplexe) left outer join cmpdAction on (complexe.IDComplexe=cmpdAction.IDComplexeBound) inner join protein on (bindingSite.IDProtein=protein.IDProtein) inner join domain on (bindingSite.IDDomain=domain.IDDomain) inner join disease on (disease.IDPPI=ppi.IDPPI)''' cursor.execute(sql_request_string) rows = cursor.fetchall() ProteinDomainBoundComplex.objects.all().delete() ProteinDomainPartnerComplex.objects.all().delete() - self.stdout.write(self.style.SUCCESS('Successfully flushed protein domain complex tables')) + Disease.objects.all().delete() + Ppi.objects.all().delete() + PpiComplex.objects.all().delete() + self.stdout.write(self.style.SUCCESS('Successfully flushed protein domain complex, PPI, and disease tables')) + ppi_ids_mapping = {} for row in rows: try: - if row[3]=="null": + # create or retrieve Ppi object + if row[5]=='part1': + ppi = Ppi() + disease, created = Disease.objects.get_or_create(name=row[7]) + ppi.pdb_id = row[4] + ppi.pockets_nb = 1 + ppi.symmetry = Symmetry.objects.get(code='AS') + ppi.save() + ppi.diseases.add(disease) + ppi.save() + ppi_ids_mapping[row[6]]=ppi.id + else: + ppi = Ppi.objects.get(id=ppi_ids_mapping[row[6]]) + # create a complex + if row[3] is None: c = ProteinDomainPartnerComplex() else: c = ProteinDomainBoundComplex() protein = Protein.objects.get(uniprot_id=row[0]) - c.protein_id = protein + c.protein = protein domain = Domain.objects.get(pfam_acc=row[1]) - c.domain_id = domain + c.domain = domain c.ppc_copy_nb = row[2] if isinstance(c, ProteinDomainBoundComplex): c.ppp_copy_nb_per_p = 1 - c.pockets_nb = 1 c.save() + # create the PpiComplex object + ppi_complex = PpiComplex() + ppi_complex.ppi = ppi + ppi_complex.complex = c + ppi_complex.cc_nb = 1 + ppi_complex.save() except Exception as e: if options['stoponfail']: import traceback @@ -142,3 +241,129 @@ class Command(BaseCommand): self.stdout.write(self.style.ERROR('Failed inserting {} {}'.format(row[0], row[1]))) else: self.stdout.write(self.style.SUCCESS('Successfully inserted {} {}'.format(row[0], row[1]))) + cursor.execute("""SELECT * FROM testActivityDescription""") + rows = cursor.fetchall() + TestActivityDescription.objects.all().delete() + CellLine.objects.all().delete() + self.stdout.write(self.style.SUCCESS('Successfully flushed test activity descriptions table and cell lines table')) + for row in rows: + try: + tad = TestActivityDescription() + cursor.execute("""select IDSource from biblio where IDBiblio={}""".format(row[2])) + biblio_row = cursor.fetchone() + biblio = Bibliography.objects.get(id_source=biblio_row[0]) + tad.biblio = biblio + tad.ppi = Ppi.objects.get(id=ppi_ids_mapping[row[3]]) + tad.test_name = row[4] + tad.test_type = row[7].upper() + tad.test_modulation_type = row[8][0] + tad.nb_active_compounds = row[9] + if row[16] is not None: + tad.cell_line, created = CellLine.objects.get_or_create(name=row[16]) + tad.save() + except Exception as e: + if options['stoponfail']: + import traceback + self.stderr.write(traceback.format_exc()) + raise CommandError('Failed inserting {} {}'.format(row[1], row[2])) + else: + self.stdout.write(self.style.ERROR('Failed inserting {} {}'.format(row[1], row[2]))) + else: + self.stdout.write(self.style.SUCCESS('Successfully inserted {}'.format(row[2]))) + if options['mddr']: + MDDRCompoundImport.objects.all().delete() + MDDRActivityClass.objects.all().delete() + self.stdout.write(self.style.SUCCESS('Successfully flushed MDDR Compound and Activity class tables')) + for sdf_file in glob.glob('/home/hmenager/iPPIDB/mddr20151_2d.sdf/*.sdf'): + for item in readfile("sdf", sdf_file): + try: + m = MDDRCompoundImport() + m.mddr_name = item.data['MOLNAME'] + m.canonical_smile = str(item) + m.dvpmt_phase = item.data['PHASE'] + m.db_import_date = timezone.now() + m.save() + for activity_class_name in item.data['ACTIV_CLASS'].split(','): + activity_class, created = MDDRActivityClass.objects.get_or_create(name=activity_class_name) + m.activity_classes.add(activity_class) + m.save() + except Exception as e: + if options['stoponfail']: + import traceback + self.stderr.write(traceback.format_exc()) + raise CommandError('Failed inserting {}'.format(str(item))) + else: + self.stdout.write(self.style.ERROR('Failed inserting {}'.format(str(item)))) + else: + self.stdout.write(self.style.SUCCESS('Successfully inserted {} {}'.format(item.data['MOLNAME'], str(item)))) + if options['compound']: + cursor.execute("""SELECT * FROM compound""") + rows = cursor.fetchall() + Compound.objects.all().delete() + self.stdout.write(self.style.SUCCESS('Successfully flushed compound table')) + for row in rows: + try: + compound = Compound() + compound.canonical_smile = row[1] + compound.is_macrocycle = (row[4]=='Y') + compound.aromatic_ratio = row[5] + compound.balaban_index = row[6] + compound.fsp3 = row[7] #Csp3Ratio + compound.gc_molar_refractivity=row[10] #GCMolarRefractivity + compound.log_d = row[13] #LogD + compound.a_log_p = row[14] #ALogP + compound.mean_atom_vol_vdw = row[15] #MeanAtomVolVdW + compound.molecular_weight = row[16] #MolecularWeight + compound.nb_acceptor_h = row[17] #NbAcceptorH + compound.nb_aliphatic_amines = row[18] #NbAliphaticsAmines + compound.nb_aromatic_bonds = row[19] #NbAromaticBonds + compound.nb_aromatic_ether = row[20] #NbAromaticsEther + compound.nb_aromatic_sssr = row[21] #NbAromaticsSSSR + compound.nb_atom = row[22] #NbAtom + compound.nb_atom_non_h = row[23] #NbAtomNonH + compound.nb_benzene_like_rings = row[24] #NbBenzLikeRings + compound.nb_bonds = row[25] #NbBonds + compound.nb_bonds_non_h = row[26] #NbBondsNonH + compound.nb_br = row[27] #NbBr + compound.nb_c = row[28] #NbC + compound.nb_chiral_centers = row[29] #NbChiralCenters + compound.nb_circuits = row[30] #NbCircuits + compound.nb_cl = row[31] #NbCl + compound.nb_csp2 = row[32] #NbCsp2 + compound.nb_csp3 = row[33] #NbCsp3 + compound.nb_donor_h = row[34] #NbDonorH + compound.nb_double_bonds = row[35] #NbDoubleBonds + compound.nb_f = row[36] #NbF + compound.nb_i = row[37] #NbI + compound.nb_multiple_bonds = row[38] #NbMultBonds + compound.nb_n = row[39] #NbN + compound.nb_o = row[40] #NbO + compound.nb_rings = row[41] #NbRings + compound.nb_rotatable_bonds = row[42] #NbRotatableBonds + compound.randic_index = row[44] #RandicIndex + compound.rdf070m = row[45] #RDF070m + compound.rotatable_bond_fraction = row[46] #RotatableBondFraction + compound.sum_atom_polar = row[47] #SumAtomPolar + compound.sum_atom_vol_vdw = row[48] #SumAtomVolVdW + compound.tpsa = row[51] #TPSA + compound.ui = row[52] #Ui + compound.wiener_index = row[54] #WienerIndex + if row[55]!='N': + compound.common_name = row[55] #CmpdNameSh + compound.pubchem_id = row[56] #IdPubchem + if row[57]!='N': + compound.chemspider_id = row[57] #IdPubchem + compound.chembl_id = row[58] + compound.iupac_name = row[59] + #compound.mddr_compound = row[60] + #FIXME lookup MDDR to get the right ID + compound.save() + except Exception as e: + if options['stoponfail']: + import traceback + self.stderr.write(traceback.format_exc()) + raise CommandError('Failed inserting {} {}'.format(row[1], row[2])) + else: + self.stdout.write(self.style.ERROR('Failed inserting {} {}'.format(row[1], row[2]))) + else: + self.stdout.write(self.style.SUCCESS('Successfully inserted {} {}'.format(row[1], row[2]))) diff --git a/ippisite/ippidb/migrations/0009_auto_20170517_2020.py b/ippisite/ippidb/migrations/0009_auto_20170517_2020.py new file mode 100644 index 0000000000000000000000000000000000000000..51fbffd8892fe1bb4048f3d395ac5d898cfd12cf --- /dev/null +++ b/ippisite/ippidb/migrations/0009_auto_20170517_2020.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-17 20:20 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0008_auto_20170329_1441'), + ] + + operations = [ + migrations.RenameField( + model_name='cmpdaction', + old_name='complex_id', + new_name='complex', + ), + migrations.RenameField( + model_name='cmpdaction', + old_name='compound_id', + new_name='compound', + ), + migrations.RenameField( + model_name='cmpdaction', + old_name='ppi_id', + new_name='ppi', + ), + migrations.RenameField( + model_name='compound', + old_name='mddr_compound_id', + new_name='mddr_compound', + ), + migrations.RenameField( + model_name='compoundactivityresult', + old_name='activity_type_id', + new_name='activity_type', + ), + migrations.RenameField( + model_name='compoundactivityresult', + old_name='compound_id', + new_name='compound', + ), + migrations.RenameField( + model_name='compoundactivityresult', + old_name='test_activity_description_id', + new_name='test_activity_description', + ), + migrations.RenameField( + model_name='compoundcytotoxicityresult', + old_name='compound_id', + new_name='compound', + ), + migrations.RenameField( + model_name='compoundcytotoxicityresult', + old_name='test_cytotoxicity_description_id', + new_name='test_cytotoxicity_description', + ), + migrations.RenameField( + model_name='compoundpkresult', + old_name='compound_id', + new_name='compound', + ), + migrations.RenameField( + model_name='compoundpkresult', + old_name='test_pk_description_id', + new_name='test_pk_description', + ), + migrations.RenameField( + model_name='disease', + old_name='ppi_id', + new_name='ppi', + ), + migrations.RenameField( + model_name='mddrcompoundactivityclass', + old_name='mddr_compound_id', + new_name='mddr_compound', + ), + migrations.RenameField( + model_name='ppi', + old_name='complex_id', + new_name='complex', + ), + migrations.RenameField( + model_name='ppi', + old_name='symmetry_id', + new_name='symmetry', + ), + migrations.RenameField( + model_name='proteindomaincomplex', + old_name='domain_id', + new_name='domain', + ), + migrations.RenameField( + model_name='proteindomaincomplex', + old_name='protein_id', + new_name='protein', + ), + migrations.RenameField( + model_name='refcompoundbiblio', + old_name='bibliography_id', + new_name='bibliography', + ), + migrations.RenameField( + model_name='refcompoundbiblio', + old_name='compound_id', + new_name='compound', + ), + migrations.RenameField( + model_name='testactivitydescription', + old_name='biblio_id', + new_name='biblio', + ), + migrations.RenameField( + model_name='testactivitydescription', + old_name='complex_id', + new_name='complex', + ), + migrations.RenameField( + model_name='testactivitydescription', + old_name='ppi_id', + new_name='ppi', + ), + migrations.RenameField( + model_name='testcytotoxdescription', + old_name='biblio_id', + new_name='biblio', + ), + migrations.RenameField( + model_name='testpkdescription', + old_name='biblio_id', + new_name='biblio', + ), + migrations.RemoveField( + model_name='compound', + name='dh_Petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='diam_graph_non_h_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='g_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='ig_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='radius_graph_non_h_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='surface_vdw_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='thickness_petitjean', + ), + migrations.RemoveField( + model_name='compound', + name='vol_vdw_petitjean', + ), + migrations.AlterField( + model_name='compound', + name='canonical_smile', + field=models.CharField(max_length=500, unique=True, verbose_name='Canonical Smile'), + ), + migrations.AlterUniqueTogether( + name='cmpdaction', + unique_together=set([('complex', 'compound', 'pdb_id')]), + ), + migrations.AlterUniqueTogether( + name='compoundactivityresult', + unique_together=set([('compound', 'test_activity_description', 'activity_type')]), + ), + migrations.AlterUniqueTogether( + name='compoundcytotoxicityresult', + unique_together=set([('compound', 'test_cytotoxicity_description')]), + ), + migrations.AlterUniqueTogether( + name='compoundpkresult', + unique_together=set([('compound', 'test_pk_description')]), + ), + migrations.AlterUniqueTogether( + name='mddrcompoundactivityclass', + unique_together=set([('mddr_compound', 'activity_class')]), + ), + migrations.AlterUniqueTogether( + name='refcompoundbiblio', + unique_together=set([('compound', 'bibliography')]), + ), + ] diff --git a/ippisite/ippidb/migrations/0010_auto_20170518_1142.py b/ippisite/ippidb/migrations/0010_auto_20170518_1142.py new file mode 100644 index 0000000000000000000000000000000000000000..520ae2dce8e60f030c0fe11f1d218dbad969ca5f --- /dev/null +++ b/ippisite/ippidb/migrations/0010_auto_20170518_1142.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-18 11:42 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0009_auto_20170517_2020'), + ] + + operations = [ + migrations.CreateModel( + name='PpiComplex', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cc_nb', models.IntegerField(default=1, verbose_name='Number of copies of the complex in the PPI')), + ('complex', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ippidb.ProteinDomainComplex')), + ], + options={ + 'verbose_name_plural': 'Ppi complexes', + }, + ), + migrations.RemoveField( + model_name='ppi', + name='cc_nb', + ), + migrations.RemoveField( + model_name='ppi', + name='complex', + ), + migrations.RemoveField( + model_name='ppi', + name='ppi_id', + ), + migrations.RemoveField( + model_name='testactivitydescription', + name='complex', + ), + migrations.AlterField( + model_name='compoundactivityresult', + name='activity_type', + field=models.CharField(choices=[('pIC50', 'pIC50 (half maximal inhibitory concentration, -log10)'), ('pEC50', 'pEC50 (half maximal effective concentration, -log10)'), ('pKd', 'pKd (dissociation constant, -log10)'), ('pKi', 'pKi (inhibition constant, -log10)')], max_length=5, verbose_name='Activity type'), + ), + migrations.AlterUniqueTogether( + name='cmpdaction', + unique_together=set([('compound', 'activation_mode', 'pdb_id')]), + ), + migrations.RemoveField( + model_name='cmpdaction', + name='complex', + ), + migrations.AlterUniqueTogether( + name='cmpdaction', + unique_together=set([('ppi', 'compound', 'activation_mode', 'pdb_id')]), + ), + migrations.DeleteModel( + name='ActivityType', + ), + migrations.AddField( + model_name='ppicomplex', + name='ppi', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ippidb.Ppi'), + ), + ] diff --git a/ippisite/ippidb/migrations/0011_auto_20170518_1404.py b/ippisite/ippidb/migrations/0011_auto_20170518_1404.py new file mode 100644 index 0000000000000000000000000000000000000000..9abe3d730559d93e1f8dfbcf9b6caa7543b582dd --- /dev/null +++ b/ippisite/ippidb/migrations/0011_auto_20170518_1404.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-18 14:04 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0010_auto_20170518_1142'), + ] + + operations = [ + migrations.AlterField( + model_name='ppi', + name='pdb_id', + field=models.CharField(max_length=4, null=True, verbose_name='PDB ID'), + ), + ] diff --git a/ippisite/ippidb/migrations/0012_auto_20170518_1913.py b/ippisite/ippidb/migrations/0012_auto_20170518_1913.py new file mode 100644 index 0000000000000000000000000000000000000000..118254a486dd69356b14d2072192c33a593b080b --- /dev/null +++ b/ippisite/ippidb/migrations/0012_auto_20170518_1913.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-18 19:13 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0011_auto_20170518_1404'), + ] + + operations = [ + migrations.RenameModel( + old_name='CmpdAction', + new_name='CompoundAction', + ), + ] diff --git a/ippisite/ippidb/migrations/0013_auto_20170518_1943.py b/ippisite/ippidb/migrations/0013_auto_20170518_1943.py new file mode 100644 index 0000000000000000000000000000000000000000..bc133acbe966237dbe441307e21939d0b1f84aa0 --- /dev/null +++ b/ippisite/ippidb/migrations/0013_auto_20170518_1943.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-18 19:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0012_auto_20170518_1913'), + ] + + operations = [ + migrations.RemoveField( + model_name='disease', + name='disease_name', + ), + migrations.RemoveField( + model_name='disease', + name='ppi', + ), + migrations.AddField( + model_name='disease', + name='name', + field=models.CharField(default=None, max_length=30, unique=True, verbose_name='Disease'), + preserve_default=False, + ), + migrations.AddField( + model_name='ppi', + name='diseases', + field=models.ManyToManyField(to='ippidb.Disease'), + ), + ] diff --git a/ippisite/ippidb/migrations/0014_auto_20170519_1243.py b/ippisite/ippidb/migrations/0014_auto_20170519_1243.py new file mode 100644 index 0000000000000000000000000000000000000000..3aef4f320ee659e960a6df1b4ea503dbabb02eb3 --- /dev/null +++ b/ippisite/ippidb/migrations/0014_auto_20170519_1243.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-19 12:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0013_auto_20170518_1943'), + ] + + operations = [ + migrations.RemoveField( + model_name='proteindomainboundcomplex', + name='pockets_nb', + ), + migrations.AddField( + model_name='ppi', + name='pockets_nb', + field=models.IntegerField(default=1, verbose_name='Total number of pockets in the complex'), + ), + ] diff --git a/ippisite/ippidb/migrations/0015_auto_20170519_1442.py b/ippisite/ippidb/migrations/0015_auto_20170519_1442.py new file mode 100644 index 0000000000000000000000000000000000000000..1fca3005fce46c0e16f303ccfd014beb9c630e59 --- /dev/null +++ b/ippisite/ippidb/migrations/0015_auto_20170519_1442.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-19 14:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0014_auto_20170519_1243'), + ] + + operations = [ + migrations.AlterField( + model_name='compound', + name='pubchem_id', + field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Pubchem ID'), + ), + ] diff --git a/ippisite/ippidb/migrations/0016_auto_20170519_1453.py b/ippisite/ippidb/migrations/0016_auto_20170519_1453.py new file mode 100644 index 0000000000000000000000000000000000000000..f33ad147e4718a43b7b49bbe90ed61510e000e8e --- /dev/null +++ b/ippisite/ippidb/migrations/0016_auto_20170519_1453.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-19 14:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0015_auto_20170519_1442'), + ] + + operations = [ + migrations.AlterField( + model_name='compound', + name='iupac_name', + field=models.CharField(blank=True, max_length=255, null=True, verbose_name='IUPAC name'), + ), + ] diff --git a/ippisite/ippidb/migrations/0017_auto_20170519_1500.py b/ippisite/ippidb/migrations/0017_auto_20170519_1500.py new file mode 100644 index 0000000000000000000000000000000000000000..f62efeeaadac44fe2c45aed5f9a3e3a704165015 --- /dev/null +++ b/ippisite/ippidb/migrations/0017_auto_20170519_1500.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-19 15:00 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0016_auto_20170519_1453'), + ] + + operations = [ + migrations.AlterField( + model_name='compound', + name='chembl_id', + field=models.CharField(blank=True, max_length=30, null=True, verbose_name='Chembl ID'), + ), + ] diff --git a/ippisite/ippidb/migrations/0018_auto_20170522_1501.py b/ippisite/ippidb/migrations/0018_auto_20170522_1501.py new file mode 100644 index 0000000000000000000000000000000000000000..2986ba98f06fc35caa42f508d3876dc97978a3d9 --- /dev/null +++ b/ippisite/ippidb/migrations/0018_auto_20170522_1501.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-22 15:01 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0017_auto_20170519_1500'), + ] + + operations = [ + migrations.CreateModel( + name='MDDRActivityClass', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('activity_class', models.CharField(max_length=100, unique=True, verbose_name='Activity Class')), + ], + options={ + 'verbose_name_plural': 'MDDR activity classes', + }, + ), + migrations.AlterUniqueTogether( + name='mddrcompoundactivityclass', + unique_together=set([]), + ), + migrations.RemoveField( + model_name='mddrcompoundactivityclass', + name='mddr_compound', + ), + migrations.DeleteModel( + name='MDDRCompoundActivityClass', + ), + migrations.AddField( + model_name='mddrcompoundimport', + name='activity_classes', + field=models.ManyToManyField(to='ippidb.MDDRActivityClass'), + ), + ] diff --git a/ippisite/ippidb/migrations/0019_auto_20170522_1931.py b/ippisite/ippidb/migrations/0019_auto_20170522_1931.py new file mode 100644 index 0000000000000000000000000000000000000000..4b1fb04481fafdec61d4558534bdf62b5fa66ae4 --- /dev/null +++ b/ippisite/ippidb/migrations/0019_auto_20170522_1931.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-22 19:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0018_auto_20170522_1501'), + ] + + operations = [ + migrations.AlterField( + model_name='mddrcompoundimport', + name='db_import_date', + field=models.DateTimeField(verbose_name='MDDR release year/month'), + ), + migrations.AlterUniqueTogether( + name='mddrcompoundimport', + unique_together=set([('mddr_name', 'dvpmt_phase', 'canonical_smile')]), + ), + migrations.RemoveField( + model_name='mddrcompoundimport', + name='mddr_compound_id', + ), + ] diff --git a/ippisite/ippidb/migrations/0020_auto_20170522_1945.py b/ippisite/ippidb/migrations/0020_auto_20170522_1945.py new file mode 100644 index 0000000000000000000000000000000000000000..1aee4b1079c721331c6ba6b99acf0ad0e3faae37 --- /dev/null +++ b/ippisite/ippidb/migrations/0020_auto_20170522_1945.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-22 19:45 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0019_auto_20170522_1931'), + ] + + operations = [ + migrations.RenameField( + model_name='mddractivityclass', + old_name='activity_class', + new_name='name', + ), + ] diff --git a/ippisite/ippidb/migrations/0021_auto_20170522_1949.py b/ippisite/ippidb/migrations/0021_auto_20170522_1949.py new file mode 100644 index 0000000000000000000000000000000000000000..fcb415f24dc5e13d83edaf296c11b704dc711bfc --- /dev/null +++ b/ippisite/ippidb/migrations/0021_auto_20170522_1949.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-22 19:49 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0020_auto_20170522_1945'), + ] + + operations = [ + migrations.AlterField( + model_name='mddrcompoundimport', + name='canonical_smile', + field=models.CharField(blank=True, max_length=500, null=True, verbose_name='Canonical Smile'), + ), + ] diff --git a/ippisite/ippidb/migrations/0022_auto_20170523_1311.py b/ippisite/ippidb/migrations/0022_auto_20170523_1311.py new file mode 100644 index 0000000000000000000000000000000000000000..24690d2087d0133ef86a6d373b7c6ddf25e7dd1d --- /dev/null +++ b/ippisite/ippidb/migrations/0022_auto_20170523_1311.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-23 13:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0021_auto_20170522_1949'), + ] + + operations = [ + migrations.AlterField( + model_name='mddrcompoundimport', + name='dvpmt_phase', + field=models.CharField(choices=[('Biological Testing', ''), ('Preclinical', ''), ('Phase III', ''), ('Phase II', ''), ('Phase I/II', ''), ('Phase I', ''), ('Launched', ''), ('Pre-Registered', ''), ('Not Applicable', ''), ('Discontinued', ''), ('Clinical', ''), ('Withdrawn', ''), ('Registered', ''), ('Not Determined', ''), ('Phase II/III', ''), ('IND Filed', '')], max_length=20, verbose_name='Development phase'), + ), + ] diff --git a/ippisite/ippidb/migrations/0023_auto_20170523_1858.py b/ippisite/ippidb/migrations/0023_auto_20170523_1858.py new file mode 100644 index 0000000000000000000000000000000000000000..904209de44969541baed91edb7396d3cb0cbe27e --- /dev/null +++ b/ippisite/ippidb/migrations/0023_auto_20170523_1858.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-23 18:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0022_auto_20170523_1311'), + ] + + operations = [ + migrations.AlterField( + model_name='testpkdescription', + name='administration_mode', + field=models.CharField(blank=True, choices=[('IV', ''), ('PO', ''), ('IP', ''), ('SL', 'SL')], max_length=2, null=True, verbose_name='Administration mode'), + ), + migrations.DeleteModel( + name='AdministrationMode', + ), + ] diff --git a/ippisite/ippidb/migrations/0024_auto_20170523_2000.py b/ippisite/ippidb/migrations/0024_auto_20170523_2000.py new file mode 100644 index 0000000000000000000000000000000000000000..d107a840d0bc9cda5e69578a73dcba995c0968a0 --- /dev/null +++ b/ippisite/ippidb/migrations/0024_auto_20170523_2000.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-05-23 20:00 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ippidb', '0023_auto_20170523_1858'), + ] + + operations = [ + migrations.AlterField( + model_name='testactivitydescription', + name='cell_line', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ippidb.CellLine'), + ), + ] diff --git a/ippisite/ippidb/models.py b/ippisite/ippidb/models.py index dbd49d260c49d0af56530de3bf49e79b077dcfc4..2b188a844e95c994bdab6b68ff3c26a33c801887 100644 --- a/ippisite/ippidb/models.py +++ b/ippisite/ippidb/models.py @@ -40,6 +40,8 @@ class Bibliography(models.Model): class Meta: verbose_name_plural = "bibliographies" + def __str__(self): + return '{}, {}'.format(self.source, self.id_source) class Taxonomy(models.Model): @@ -119,16 +121,18 @@ class Domain(models.Model): return '{} ({}-{})'.format(self.pfam_acc, self.pfam_id, self.pfam_description) class ProteinDomainComplex(models.Model): - protein_id = models.ForeignKey('Protein') - domain_id = models.ForeignKey('Domain') + protein = models.ForeignKey('Protein') + domain = models.ForeignKey('Domain') ppc_copy_nb = models.IntegerField('Number of copies of the protein in the complex') class Meta: verbose_name_plural = "complexes" + def __str__(self): + return '{}-{}'.format(self.protein_id, self.domain_id) + 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" @@ -143,21 +147,53 @@ class Symmetry(models.Model): class Meta: verbose_name_plural = "symmetries" + def __str__(self): + return '{} ({})'.format(self.code, self.description) + + +class Disease(models.Model): + name = models.CharField('Disease', max_length=30, unique=True) # is there any database/nomenclature for diseases? + + def __str__(self): + return self.name + class Ppi(models.Model): - ppi_id = models.IntegerField('PPI identifier') - complex_id = models.ForeignKey(ProteinDomainComplex) + pdb_id = models.CharField('PDB ID', max_length=4, null=True) + pockets_nb = models.IntegerField('Total number of pockets in the complex', default=1) + symmetry = models.ForeignKey(Symmetry) + diseases = models.ManyToManyField(Disease) + + def __str__(self): + return '{} PPI, PDB:{}'.format(self.symmetry.description, self.pdb_id or 'unknown') + + def get_ppi_complexes(self): + """ + return all ppi complexes belonging to this ppi + """ + return PpiComplex.objects.filter(ppi=self) + + def get_ppi_bound_complexes(self): + """ + return bound ppi complexes belonging to this ppi + """ + #this is the less efficient query ever seen, FIXME + return PpiComplex.objects.filter(ppi=self, complex__in=ProteinDomainBoundComplex.objects.all()) + + +class PpiComplex(models.Model): + ppi = models.ForeignKey(Ppi) + complex = models.ForeignKey(ProteinDomainComplex) cc_nb = models.IntegerField('Number of copies of the complex in the PPI', default=1) - pdb_id = models.CharField('PDB ID', max_length=4) - symmetry_id = models.ForeignKey(Symmetry) -class Disease(models.Model): - ppi_id = models.ForeignKey(Ppi) - disease_name = models.CharField('Disease', max_length=30) # is there any database/nomenclature for diseases? + class Meta: + verbose_name_plural = "Ppi complexes" + + def __str__(self): + return 'PPI {}, Complex {} ({})'.format(self.ppi, self.complex, self.cc_nb) class Compound(models.Model): canonical_smile = models.CharField('Canonical Smile', unique=True, max_length=500) - #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) @@ -202,37 +238,56 @@ class Compound(models.Model): 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) + pubchem_id = models.CharField('Pubchem ID', 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) - mddr_compound_id = models.ForeignKey('MDDRCompoundImport', blank=True, null=True) + chembl_id = models.CharField('Chembl ID', max_length=30, blank=True, null=True) + iupac_name = models.CharField('IUPAC name', max_length=255, blank=True, null=True) + mddr_compound = models.ForeignKey('MDDRCompoundImport', blank=True, null=True) + +class MDDRActivityClass(models.Model): + name = models.CharField('Activity Class', max_length=100, unique=True) + + class Meta: + verbose_name_plural = "MDDR activity classes" + + def __str__(self): + return self.name class MDDRCompoundImport(models.Model): - mddr_compound_id = models.IntegerField('MDDR compound ID') + + MDDR_DEVELOPMENT_PHASES = ( + ('Biological Testing',''), + ('Preclinical',''), + ('Phase III',''), + ('Phase II',''), + ('Phase I/II',''), + ('Phase I',''), + ('Launched',''), + ('Pre-Registered',''), + ('Not Applicable',''), + ('Discontinued',''), + ('Clinical',''), + ('Withdrawn',''), + ('Registered',''), + ('Not Determined',''), + ('Phase II/III',''), + ('IND Filed',''), + ) + 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) + dvpmt_phase = models.CharField('Development phase', max_length=20, choices=MDDR_DEVELOPMENT_PHASES) + canonical_smile = models.CharField('Canonical Smile', max_length=500, 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) + db_import_date = models.DateTimeField('MDDR release year/month') + activity_classes = models.ManyToManyField(MDDRActivityClass) 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'),) + unique_together = (('mddr_name', 'dvpmt_phase', 'canonical_smile'),) verbose_name_plural = "MDDR compound imports" - -class MDDRCompoundActivityClass(models.Model): - mddr_compound_id = models.ForeignKey(MDDRCompoundImport) - activity_class = models.CharField('Activity Class', max_length=100) - - class Meta: - unique_together = (('mddr_compound_id', 'activity_class'),) - verbose_name_plural = "MDDR compound activity classes" - - 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) @@ -245,6 +300,9 @@ class MDDRSimilarity(models.Model): class CellLine(models.Model): name = models.CharField('Name', max_length=50, unique=True) + def __str__(self): + return self.name + class TestActivityDescription(models.Model): TEST_TYPES = ( ('BIOCH', 'Biochemical assay'), @@ -255,17 +313,23 @@ class TestActivityDescription(models.Model): ('I', 'Inhibition'), ('S', 'Stabilization') ) - complex_id = models.ForeignKey(ProteinDomainBoundComplex) - biblio_id = models.ForeignKey(Bibliography) - ppi_id = models.ForeignKey(Ppi, blank=True, null=True) + biblio = models.ForeignKey(Bibliography) + ppi = models.ForeignKey(Ppi, blank=True, null=True) 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) + cell_line = models.ForeignKey(CellLine, blank=True, null=True) + + def get_complexes(self): + """ + get the complexes tested for this PPI + depends on the modulation type + """ + if self.test_modulation_type=='I': + return self.ppi.get_ppi_complexes() + else: + return self.ppi.get_ppi_bound_complexes() class CompoundActivityResult(models.Model): MODULATION_TYPES = ( @@ -273,43 +337,52 @@ class CompoundActivityResult(models.Model): ('I', 'Inhibition'), ('S', 'Stabilization') ) - compound_id = models.ForeignKey(Compound) - test_activity_description_id = models.ForeignKey(TestActivityDescription) - activity_type_id = models.ForeignKey(ActivityType) + ACTIVITY_TYPES = ( + ('pIC50','pIC50 (half maximal inhibitory concentration, -log10)'), + ('pEC50','pEC50 (half maximal effective concentration, -log10)'), + ('pKd','pKd (dissociation constant, -log10)'), + ('pKi','pKi (inhibition constant, -log10)'), + ) + compound = models.ForeignKey(Compound) + test_activity_description = models.ForeignKey(TestActivityDescription) + activity_type = models.CharField('Activity type', max_length=5, choices=ACTIVITY_TYPES) activity = models.DecimalField('Activity', max_digits=12, decimal_places=10) modulation_type = models.CharField('Modulation type', max_length=1, choices=MODULATION_TYPES) class Meta: - unique_together = (('compound_id', 'test_activity_description_id', 'activity_type_id'),) + unique_together = (('compound', 'test_activity_description', 'activity_type'),) class TestCytotoxDescription(models.Model): - biblio_id = models.ForeignKey(Bibliography) + biblio = models.ForeignKey(Bibliography) 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) class CompoundCytotoxicityResult(models.Model): - compound_id = models.ForeignKey(Compound) - test_cytotoxicity_description_id = models.ForeignKey(TestCytotoxDescription) + compound = models.ForeignKey(Compound) + test_cytotoxicity_description = models.ForeignKey(TestCytotoxDescription) toxicity = models.BooleanField('Toxicity', default=False) class Meta: - unique_together = (('compound_id', 'test_cytotoxicity_description_id'),) - -class AdministrationMode(models.Model): - name = models.CharField('Administration mode', max_length=20, blank=True, null=True) + unique_together = (('compound', 'test_cytotoxicity_description'),) class TestPKDescription(models.Model): - biblio_id = models.ForeignKey(Bibliography) + ADMINISTRATION_MODES = ( + ('IV', ''), + ('PO', ''), + ('IP', ''), + ('SL', 'SL') + ) + biblio = models.ForeignKey(Bibliography) test_name = models.CharField('Pharmacokinetic test name', max_length=100) organism = models.ForeignKey(Taxonomy) - administration_mode = models.ForeignKey(AdministrationMode, blank=True, null=True) + administration_mode = models.CharField('Administration mode', max_length=2, choices=ADMINISTRATION_MODES,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): - compound_id = models.ForeignKey(Compound) - test_pk_description_id = models.ForeignKey(TestPKDescription) + compound = models.ForeignKey(Compound) + test_pk_description = models.ForeignKey(TestPKDescription) 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) @@ -320,28 +393,34 @@ class CompoundPKResult(models.Model): voldistribution = models.DecimalField('Volume distribution (Vd)', max_digits=5, decimal_places=2, blank=True, null=True) class Meta: - unique_together = (('compound_id', 'test_pk_description_id'),) + unique_together = (('compound', 'test_pk_description'),) -class CmpdAction(models.Model): +class CompoundAction(models.Model): ACTIVATION_MODES = ( ('O', 'Orthosteric'), ('A', 'Allosteric') ) - complex_id = models.ForeignKey(ProteinDomainBoundComplex) - compound_id = models.ForeignKey(Compound) + compound = models.ForeignKey(Compound) activation_mode = models.CharField('Activation mode', max_length=1, choices=ACTIVATION_MODES) - ppi_id = models.ForeignKey(Ppi) + ppi = models.ForeignKey(Ppi) pdb_id = models.CharField('PDB ID', max_length=4) nb_copy_compounds = models.IntegerField('Number of copies for the compound') class Meta: - unique_together = (('complex_id', 'compound_id', 'pdb_id'),) + unique_together = (('ppi', 'compound', 'activation_mode', 'pdb_id'),) + + def get_complexes(self): + """ + get the complexes involved in the compound action + which are always the bound complexes + """ + return ppi.get_ppi_bound_complexes() class RefCompoundBiblio(models.Model): - compound_id = models.ForeignKey(Compound) - bibliography_id = models.ForeignKey(Bibliography) + compound = models.ForeignKey(Compound) + bibliography = models.ForeignKey(Bibliography) compound_name = models.CharField('Compound name in the publication', max_length=50) class Meta: - unique_together = (('compound_id', 'bibliography_id'),) + unique_together = (('compound', 'bibliography'),)