From b523d132d67da71c778323b7c50e8a8b4597a651 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Herv=C3=A9=20=20MENAGER?= <herve.menager@pasteur.fr>
Date: Thu, 18 May 2017 16:08:54 +0200
Subject: [PATCH] migrate Ppi and PpiComplex data

fixes #24
---
 ippisite/db.sqlite3                           | Bin 569344 -> 569344 bytes
 .../management/commands/import_v1_data.py     | 100 +++++++++++-------
 .../migrations/0011_auto_20170518_1404.py     |  20 ++++
 ippisite/ippidb/models.py                     |   2 +-
 4 files changed, 81 insertions(+), 41 deletions(-)
 create mode 100644 ippisite/ippidb/migrations/0011_auto_20170518_1404.py

diff --git a/ippisite/db.sqlite3 b/ippisite/db.sqlite3
index 585c05bac9b5bb713a7f404b36981aaa02f2ba17..8222fa0613fb7defe327ce8452ea41e836d26eeb 100644
GIT binary patch
delta 6316
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
E05sF~i~s-t

delta 2453
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
YDksPd;t^N5C;G)STdGILru1I+4=8Z9>Hq)$

diff --git a/ippisite/ippidb/management/commands/import_v1_data.py b/ippisite/ippidb/management/commands/import_v1_data.py
index 67b83282..69948d26 100644
--- a/ippisite/ippidb/management/commands/import_v1_data.py
+++ b/ippisite/ippidb/management/commands/import_v1_data.py
@@ -2,7 +2,7 @@ from django.core.management import BaseCommand, CommandError
 import mysql.connector
 
 from ippidb.models import Bibliography, Protein, Taxonomy, MolecularFunction, \
-    Domain, ProteinDomainBoundComplex, ProteinDomainPartnerComplex, Symmetry, Ppi
+    Domain, ProteinDomainBoundComplex, ProteinDomainPartnerComplex, Symmetry, Ppi, PpiComplex
 
 class Command(BaseCommand):
 
@@ -31,18 +31,18 @@ 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(
-            '--symmetries',
+            '--ppi',
             action='store_true',
-            dest='symmetries',
+            dest='ppi',
             default=False,
-            help='Flush and create symmetries',
+            help='Flush and migrate ppis and complexes',
         )
         parser.add_argument(
             '--stoponfail',
@@ -117,39 +117,6 @@ 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']:
-            sql_request_string = '''
-                select distinct protein.NumUniprot, domain.PfamNumAccession  , complexe.NbCopy, cmpdAction.IDComplexeBound, bindingSiteEvidence.CodePDB  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) left outer join bindingSiteEvidence on (ppi.IDPPI=bindingSiteEvidence.IDPPI)'''
-            cursor.execute(sql_request_string)
-            rows = cursor.fetchall()
-            ProteinDomainBoundComplex.objects.all().delete()
-            ProteinDomainPartnerComplex.objects.all().delete()
-            Ppi.objects.all().delete()
-            self.stdout.write(self.style.SUCCESS('Successfully flushed protein domain complex tables and Ppi'))
-            for row in rows:
-                try:
-                    if row[3]=="null":
-                        c = ProteinDomainPartnerComplex()
-                    else:
-                        c = ProteinDomainBoundComplex()
-                    protein = Protein.objects.get(uniprot_id=row[0])
-                    c.protein_id = protein
-                    domain = Domain.objects.get(pfam_acc=row[1])
-                    c.domain_id = domain
-                    c.ppc_copy_nb = row[2]
-                    if isinstance(c, ProteinDomainBoundComplex):
-                        c.ppp_copy_nb_per_p = 1
-                        c.pockets_nb = 1
-                    c.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['symmetries']:
             Symmetry.objects.all().delete()
             self.stdout.write(self.style.SUCCESS('Successfully flushed symmetries table'))
@@ -179,4 +146,57 @@ 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])))
+        if options['ppi']:
+            sql_request_string = '''
+select distinct protein.NumUniprot, domain.PfamNumAccession, complexe.NbCopy, cmpdAction.IDComplexeBound, bindingSiteEvidence.CodePDB, 'part1', ppi.IDPPI  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) left outer join bindingSiteEvidence on (ppi.IDPPI=bindingSiteEvidence.IDPPI)
+union 
+select distinct protein.NumUniprot, domain.PfamNumAccession  , complexe.NbCopy, cmpdAction.IDComplexeBound, null, 'part2', ppi.IDPPI  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)'''
+            cursor.execute(sql_request_string)
+            rows = cursor.fetchall()
+            ProteinDomainBoundComplex.objects.all().delete()
+            ProteinDomainPartnerComplex.objects.all().delete()
+            Ppi.objects.all().delete()
+            PpiComplex.objects.all().delete()
+            self.stdout.write(self.style.SUCCESS('Successfully flushed protein domain complex tables and Ppi'))
+            ppi_ids_mapping = {}
+            for row in rows:
+                try:
+                    # create or retrieve Ppi object
+                    if row[5]=='part1':
+                        ppi = Ppi()
+                        ppi.pdb_id = row[4]
+                        ppi.symmetry = Symmetry.objects.get(code='AS')
+                        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]=="null":
+                        c = ProteinDomainPartnerComplex()
+                    else:
+                        c = ProteinDomainBoundComplex()
+                    protein = Protein.objects.get(uniprot_id=row[0])
+                    c.protein = protein
+                    domain = Domain.objects.get(pfam_acc=row[1])
+                    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
+                        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])))
             
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 00000000..9abe3d73
--- /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/models.py b/ippisite/ippidb/models.py
index 50288a93..4e4f0901 100644
--- a/ippisite/ippidb/models.py
+++ b/ippisite/ippidb/models.py
@@ -150,7 +150,7 @@ class Symmetry(models.Model):
         return '{} ({})'.format(self.code, self.description)
 
 class Ppi(models.Model):
-    pdb_id = models.CharField('PDB ID', max_length=4)
+    pdb_id = models.CharField('PDB ID', max_length=4, null=True)
     symmetry = models.ForeignKey(Symmetry)
 
 class PpiComplex(models.Model):
-- 
GitLab