]> git.parisson.com Git - mezzo.git/commitdiff
Finally fix various M2M values and related import rules, minor network.models update
authorGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Fri, 4 Nov 2016 15:13:15 +0000 (16:13 +0100)
committerGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Fri, 4 Nov 2016 15:13:15 +0000 (16:13 +0100)
app/organization/network/admin.py
app/organization/network/management/commands/import-ircam-person-xls.py
app/organization/network/migrations/0047_auto_20161104_1424.py [new file with mode: 0644]
app/organization/network/migrations/0048_auto_20161104_1445.py [new file with mode: 0644]
app/organization/network/migrations/0049_auto_20161104_1453.py [new file with mode: 0644]
app/organization/network/models.py

index 7e29ea4c72e8493198e5acf5697baa8dae2f1dee..e4485ca5d75351f7cfd071c4ce2ef928bfb63cb2 100644 (file)
@@ -78,6 +78,7 @@ class PersonActivityInline(StackedDynamicInlineAdmin):
 
     model = PersonActivity
     fk_name = 'person'
+    filter_horizontal = ['organizations', 'employers', 'teams', 'projects', 'supervisors', 'phd_directors', ]
 
 
 class PersonPlaylistInline(TabularDynamicInlineAdmin):
@@ -108,24 +109,32 @@ class PersonBlockInline(StackedDynamicInlineAdmin):
 class PersonAdmin(BaseTranslationOrderedModelAdmin):
 
     model = Person
-    inlines = [PersonActivityInline,
-               PersonImageInline,
+    inlines = [PersonImageInline,
                PersonBlockInline,
                PersonPlaylistInline,
                PersonLinkInline,
-               PersonFileInline ]
+               PersonFileInline,
+               PersonActivityInline,]
     first_fields = ['last_name', 'first_name', 'title', 'gender', 'user']
     search_fields = ['last_name', 'first_name']
     list_display = ['last_name', 'first_name', 'description', 'email', 'gender']
     list_filter = ['person_title', 'activities__date_from', 'activities__date_to',
                     'activities__is_permanent', 'activities__framework', 'activities__grade',
-                    'activities__function', 'activities__team',]
+                    'activities__function', 'activities__teams',]
 
 
-class PersonActivityAdmin(admin.ModelAdmin):
+class PersonActivityAdmin(BaseTranslationModelAdmin):
 
     model = PersonActivity
-    list_display = ['person', 'team', 'status', 'date_from', 'date_to']
+    list_display = ['person', 'get_teams', 'status', 'date_from', 'date_to']
+    filter_horizontal = ['organizations', 'employers', 'teams', 'projects', 'supervisors', 'phd_directors', ]
+
+    def get_teams(self, instance):
+        values = []
+        for team in instance.teams.all():
+            print(team.code)
+            values.append(team.code)
+        return ' - '.join(values)
 
 
 class PersonListBlockInlineAdmin(TabularDynamicInlineAdmin):
index 3efe10fc975ff2e2d49febd0282e6c809325bb0b..054768646e93dd0f881dade2462d55badaf235ea 100644 (file)
@@ -77,7 +77,7 @@ class IrcamPerson(object):
         self.person, c = Person.objects.get_or_create(title=title, first_name=first_name, last_name=last_name)
         self.activity = PersonActivity(person=self.person)
 
-    def get_identity(self, ):
+    def set_identity(self, ):
         gender = self.row[2].value
         if gender == 'H':
             self.person.gender = 'male'
@@ -92,19 +92,6 @@ class IrcamPerson(object):
 
         self.person.save()
 
-    def get_or_create_name(self, model, column_id):
-        return model.objects.get_or_create(name=self.row[column_id].value)[0] if self.row[column_id].value else None
-
-    def split_names(self, names):
-        name_list = []
-        for spliter in self.spliters:
-            if spliter in names:
-                name_list = names.split(spliter)
-        if name_list:
-            for map(str.strip, name_list)
-            return name_list
-        return names
-
     def get_person(self, value):
         if value:
             name_exceptions = ['de', 'von']
@@ -133,21 +120,54 @@ class IrcamPerson(object):
             return person
         return None
 
-    def get_team(self, code):
-        code = str(code)
-        qs = Q(code=code) | Q(code=code.lower()) | Q(code=code.upper()) | Q(code=code.capitalize())
-        teams = Team.objects.filter(qs)
-        if teams:
-            return teams[0]
-
-        qs = Q(title=code) | Q(title=code.lower()) | Q(title=code.upper()) | Q(title=code.capitalize())
-        projects = Project.objects.filter(qs)
-        if projects:
-            self.activity.project = projects[0]
-            return None
-        return None
+    def get_or_create_name(self, model, column_id):
+        value = self.row[column_id].value if self.row[column_id].value else None
+        obj = None
+        if value:
+            try:
+                obj, c = model.objects.get_or_create(name=value)
+            except:
+                obj = model(name=value)
+                obj.save()
+        return obj
 
-    def get_activity(self):
+    def split_names(self, names):
+        name_list = []
+        for spliter in self.spliters:
+            if spliter in names:
+                name_list = names.split(spliter)
+        if name_list:
+            name_list = map(str.strip, name_list)
+            return name_list
+        return [names,]
+
+    def add_many(self, field, model, column_id, type='name'):
+        values = self.row[column_id].value if self.row[column_id].value else None
+        if values:
+            for value in self.split_names(values):
+                if type == 'name':
+                    qs = Q(name=value) | Q(name=value.lower()) | Q(name=value.upper()) | Q(name=value.capitalize())
+                    obj = model(name=value)
+                elif type == 'code':
+                    qs = Q(code=value) | Q(code=value.lower()) | Q(code=value.upper()) | Q(code=value.capitalize())
+                    obj = model(code=value)
+                elif type == 'title':
+                    qs = Q(title=value) | Q(title=value.lower()) | Q(title=value.upper()) | Q(title=value.capitalize())
+                    obj = model(title=value)
+                elif type == 'person':
+                    obj = self.get_person(value)
+                    qs = None
+                if qs:
+                    objects = model.objects.filter(qs)
+                    if objects:
+                        obj = objects[0]
+                    else:
+                        obj.save()
+                else:
+                    obj.save()
+                field.add(obj)
+
+    def set_activity(self):
         self.activity.date_from = datetime.datetime(*xlrd.xldate_as_tuple(self.row[4].value, self.datemode)) if self.row[4].value else None
         self.activity.date_to = datetime.datetime(*xlrd.xldate_as_tuple(self.row[5].value, self.datemode)) if self.row[5].value else None
         try:
@@ -159,18 +179,16 @@ class IrcamPerson(object):
         self.activity.is_permanent = True if self.row[11].value else False
         self.activity.framework = self.get_or_create_name(ActivityFramework, 12)
         self.activity.grade = self.get_or_create_name(ActivityGrade, 13)
+        self.activity.save()
 
-        self.activity.employer = self.get_or_create_name(Organization, 14)
-        self.activity.attachment_organization = self.get_or_create_name(Organization, 15)
-        self.activity.second_employer = self.get_or_create_name(Organization, 16)
+        self.add_many(self.activity.employers, Organization, 14)
+        self.add_many(self.activity.organizations, Organization, 15)
+        self.add_many(self.activity.employers, Organization, 16)
         self.activity.umr = self.get_or_create_name(UMR, 17)
 
-        self.activity.team = self.get_team(self.row[19].value)
-        try:
-            self.activity.second_team = self.get_team(self.row[21].value)
-        except:
-            self.activity.second_team_text =  self.row[21].value
-        self.activity.project, c = Project.objects.get_or_create(title=self.row[22].value) if self.row[22].value else (None, False)
+        self.add_many(self.activity.teams, Team, 19, type='code')
+        self.add_many(self.activity.teams, Team, 21, type='code')
+        self.add_many(self.activity.projects, Project, 22, type='title')
 
         quota = self.row[23].value
         try:
@@ -179,9 +197,12 @@ class IrcamPerson(object):
             self.activity.rd_quota_text = str(quota)
 
         self.activity.phd_doctoral_school = self.get_or_create_name(Organization, 25)
-        self.activity.phd_director = self.get_person(self.row[26].value)
-        self.activity.phd_officer_1 = self.get_person(self.row[27].value)
-        self.activity.phd_officer_2 = self.get_person(self.row[28].value)
+        if self.activity.phd_doctoral_school:
+            self.activity.phd_doctoral_school.type, c = OrganizationType.objects.get_or_create(name='Ecole doctorale')
+            self.activity.phd_doctoral_school.save()
+        self.add_many(self.activity.phd_directors, Person, 26, type='person')
+        self.add_many(self.activity.supervisors, Person, 27, type='person')
+        self.add_many(self.activity.supervisors, Person, 28, type='person')
 
         self.activity.training_type = self.get_or_create_name(TrainingType, 29)
         self.activity.training_level = self.get_or_create_name(TrainingLevel, 30)
@@ -189,13 +210,13 @@ class IrcamPerson(object):
         self.activity.training_speciality = self.get_or_create_name(TrainingSpeciality, 32)
         self.activity.function = self.get_or_create_name(ActivityFunction, 34)
 
-        if self.activity.phd_director:
+        if self.activity.phd_directors:
             self.activity.phd_title = self.row[35].value
             try:
                 self.activity.phd_defense_date = datetime.datetime(*xlrd.xldate_as_tuple(self.row[38].value, self.datemode)) if self.row[38].value else None
             except:
                 pass
-            self.activity.phd_postdoctoralsituation = self.row[39].value
+            self.activity.phd_post_doctoral_situation = self.row[39].value
         elif self.activity.training_type:
             self.activity.training_title = self.row[35].value
 
@@ -213,7 +234,9 @@ class IrcamPerson(object):
 
 
 class Command(BaseCommand):
-    help = """Import Person data from IRCAM's legacy XLS management file"""
+    help = """Import Person data from IRCAM's legacy XLS management file.
+              python manage.py import-ircam-person-xls -s /srv/backup/TB_personnel_GP-GM_4.xls
+    """
 
     option_list = BaseCommand.option_list + (
           make_option('-d', '--dry-run',
@@ -242,5 +265,5 @@ class Command(BaseCommand):
         xls = IrcamXLS(self.source_file)
         for i in range(xls.first_row, xls.size):
             p = IrcamPerson(xls.sheet.row(i), xls.book.datemode)
-            p.get_identity()
-            p.get_activity()
+            p.set_identity()
+            p.set_activity()
diff --git a/app/organization/network/migrations/0047_auto_20161104_1424.py b/app/organization/network/migrations/0047_auto_20161104_1424.py
new file mode 100644 (file)
index 0000000..7301dfb
--- /dev/null
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.10 on 2016-11-04 13:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0046_auto_20161026_1025'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='personactivity',
+            old_name='phd_postdoctoralsituation',
+            new_name='phd_post_doctoral_situation',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='attachment_organization',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='employer',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='phd_officers',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='second_employer',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='second_team',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='second_team_text',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='team',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='third_employer',
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='employers',
+            field=models.ManyToManyField(blank=True, related_name='employer_project_activities', to='organization-network.Organization', verbose_name='employers'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='organization',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='project_activities', to='organization-network.Organization', verbose_name='organization (attachment or subscribed)'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='supervisors',
+            field=models.ManyToManyField(blank=True, related_name='supervisor_activities', to='organization-network.Person', verbose_name='supervisors'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='team_text',
+            field=models.CharField(blank=True, max_length=256, null=True, verbose_name='other team text'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='teams',
+            field=models.ManyToManyField(blank=True, related_name='team_activities', to='organization-network.Team', verbose_name='teams'),
+        ),
+        migrations.AlterField(
+            model_name='personactivity',
+            name='rd_quota_float',
+            field=models.FloatField(blank=True, null=True, verbose_name='R&D quota (float)'),
+        ),
+    ]
diff --git a/app/organization/network/migrations/0048_auto_20161104_1445.py b/app/organization/network/migrations/0048_auto_20161104_1445.py
new file mode 100644 (file)
index 0000000..460c8f1
--- /dev/null
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.10 on 2016-11-04 13:45
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0047_auto_20161104_1424'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='organization',
+            name='mappable_location',
+            field=models.CharField(blank=True, help_text='This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field.', max_length=128, null=True),
+        ),
+    ]
diff --git a/app/organization/network/migrations/0049_auto_20161104_1453.py b/app/organization/network/migrations/0049_auto_20161104_1453.py
new file mode 100644 (file)
index 0000000..7d6e42d
--- /dev/null
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.10 on 2016-11-04 13:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0048_auto_20161104_1445'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='organization',
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='organizations',
+            field=models.ManyToManyField(blank=True, related_name='project_activities', to='organization-network.Organization', verbose_name='organizations (attachment or subscribed)'),
+        ),
+    ]
index 490a7416decd046e5f1ba7d627c9717002aac394..5232ea0585370f1ed055b2f9d22d7d5302747f20 100644 (file)
@@ -63,12 +63,12 @@ ALIGNMENT_CHOICES = (('left', _('left')), ('left', _('left')), ('right', _('righ
 class Organization(Named, Address, URL, AdminThumbRelatedMixin):
     """(Organization description)"""
 
-    mappable_location = models.CharField(max_length=128, blank=True, help_text="This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field.")
+    mappable_location = models.CharField(max_length=128, blank=True, null=True, help_text="This address will be used to calculate latitude and longitude. Leave blank and set Latitude and Longitude to specify the location yourself, or leave all three blank to auto-fill from the Location field.")
     lat = models.DecimalField(max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Latitude", help_text="Calculated automatically if mappable location is set.")
     lon = models.DecimalField(max_digits=10, decimal_places=7, blank=True, null=True, verbose_name="Longitude", help_text="Calculated automatically if mappable location is set.")
     type = models.ForeignKey('OrganizationType', verbose_name=_('organization type'), blank=True, null=True, on_delete=models.SET_NULL)
     initials = models.CharField(_('initials'), max_length=128, blank=True, null=True)
-    is_on_map = models.BooleanField(_('is on map'), default=False)
+    is_on_map = models.BooleanField(_('is on map'), default=False, blank=True)
 
     admin_thumb_type = 'logo'
 
@@ -89,7 +89,8 @@ class Organization(Named, Address, URL, AdminThumbRelatedMixin):
             raise ValidationError("Latitude required if specifying longitude.")
 
         if not (self.lat and self.lon) and not self.mappable_location:
-            self.mappable_location = self.address.replace("\n"," ").replace('\r', ' ') + ", " + self.postal_code + " " + self.city
+            if self.address:
+                self.mappable_location = self.address.replace("\n"," ").replace('\r', ' ') + ", " + self.postal_code + " " + self.city
 
         if self.mappable_location and not (self.lat and self.lon): #location should always override lat/long if set
             g = GoogleMaps(domain=settings.EVENT_GOOGLE_MAPS_DOMAIN)
@@ -388,27 +389,25 @@ class PersonActivity(Period):
     grade = models.ForeignKey(ActivityGrade, verbose_name=_('grade'), blank=True, null=True, on_delete=models.SET_NULL)
     function = models.ForeignKey(ActivityFunction, verbose_name=_('function'), blank=True, null=True, on_delete=models.SET_NULL)
 
-    employer = models.ForeignKey(Organization, verbose_name=_('employer'), related_name='employer_activities', blank=True, null=True, on_delete=models.SET_NULL)
-    attachment_organization = models.ForeignKey(Organization, verbose_name=_('attachment organization'), related_name='attachment_activities', blank=True, null=True, on_delete=models.SET_NULL)
-    second_employer = models.ForeignKey(Organization, verbose_name=_('second employer'), related_name='second_employer_activities', blank=True, null=True, on_delete=models.SET_NULL)
-    third_employer = models.ForeignKey(Organization, verbose_name=_('third employer'), related_name='third_employer_activities', blank=True, null=True, on_delete=models.SET_NULL)
+    organizations = models.ManyToManyField(Organization, verbose_name=_('organizations (attachment or subscribed)'), related_name='project_activities', blank=True)
+    employers = models.ManyToManyField(Organization, verbose_name=_('employers'), related_name='employer_project_activities', blank=True)
     umr = models.ForeignKey(UMR, verbose_name=_('UMR'), blank=True, null=True, on_delete=models.SET_NULL)
-    team = models.ForeignKey('Team', verbose_name=_('team'), related_name='team_activities', blank=True, null=True, on_delete=models.SET_NULL)
-    second_team = models.ForeignKey('Team', verbose_name=_('second team'), related_name='second_team_activities', blank=True, null=True, on_delete=models.SET_NULL)
-    second_team_text = models.CharField(_('second team text'), blank=True, null=True, max_length=256)
+    teams = models.ManyToManyField('Team', verbose_name=_('teams'), related_name='team_activities', blank=True)
+    team_text = models.CharField(_('other team text'), blank=True, null=True, max_length=256)
 
     projects = models.ManyToManyField('organization-projects.Project', verbose_name=_('projects'), related_name='activities', blank=True)
-    rd_quota_float = models.IntegerField(_('R&D quota (float)'), blank=True, null=True)
+    rd_quota_float = models.FloatField(_('R&D quota (float)'), blank=True, null=True)
     rd_quota_text = models.CharField(_('R&D quota (text)'), blank=True, null=True, max_length=128)
     rd_program = models.TextField(_('R&D program'), blank=True)
     budget_code = models.ForeignKey(BudgetCode, blank=True, null=True, on_delete=models.SET_NULL)
 
+    supervisors = models.ManyToManyField('Person', verbose_name=_('supervisors'), related_name='supervisor_activities', blank=True)
+
     phd_doctoral_school = models.ForeignKey(Organization, verbose_name=_('doctoral school'), blank=True, null=True, on_delete=models.SET_NULL)
     phd_directors = models.ManyToManyField('Person', verbose_name=_('PhD directors'), related_name='phd_director_activities', blank=True)
-    phd_officers = models.ManyToManyField('Person', verbose_name=_('PhD officers'), related_name='phd_officer_activities', blank=True)
     phd_defense_date = models.DateField(_('PhD defense date'), blank=True, null=True)
     phd_title = models.TextField(_('PhD title'), blank=True)
-    phd_postdoctoralsituation =  models.CharField(_('post-doctoral situation'), blank=True, max_length=256)
+    phd_post_doctoral_situation =  models.CharField(_('post-doctoral situation'), blank=True, max_length=256)
     hdr = models.BooleanField(_('HDR'), default=False)
 
     training_type = models.ForeignKey(TrainingType, verbose_name=_('training type'), blank=True, null=True, on_delete=models.SET_NULL)
@@ -430,6 +429,7 @@ class PersonActivity(Period):
     class Meta:
         verbose_name = _('activity')
         verbose_name_plural = _('activities')
+        ordering = ['person__last_name',]
 
     def __str__(self):
         if self.status: