Switch to side-by-side view

--- a/OSSEval/analysis/models.py
+++ b/OSSEval/analysis/models.py
@@ -1,3 +1,4 @@
+import importlib
 from django.db import models
 from datetime import datetime
 from random import randrange
@@ -41,7 +42,7 @@
 class HasPages(models.Model):
     bar_chart = models.TextField(blank=True)
     radar_chart = models.TextField(blank=True)
-    def create_graphs(self, instances):
+    def create_graphs(self, instances, include_max = True):
         # I draw the graphs for the report
         #styles = [NeonStyle, DarkSolarizedStyle, LightSolarizedStyle, LightStyle, CleanStyle, RedBlueStyle, DarkColorizedStyle, LightColorizedStyle, TurquoiseStyle, LightGreenStyle, DarkGreenStyle, DarkGreenBlueStyle, BlueStyle]
         #style=styles[randrange(len(styles))]
@@ -56,6 +57,9 @@
         instance_scores = {}
         for instance in instances:
             instance_scores[instance.id] = []
+        if include_max:
+            # I use 0 as an id for the max score
+            instance_scores[0] = []
         for page in self.page_set.all():
             radar_chart.x_labels.append(page.name)
             for instance in instances:
@@ -64,9 +68,15 @@
                     instance_scores[instance.id].append(ps.score)
                 except:
                     instance_scores[instance.id].append(0)
+                if include_max:
+                    instance_scores[0].append(5)
+                    print str(page.id) + " - " + str(page.max_score)
         for instance in instances:
             radar_chart.add(instance.name, instance_scores[instance.id])
             bar_chart.add(instance.name, sum(instance_scores[instance.id]))
+        if include_max:
+            radar_chart.add("MAX", instance_scores[0])
+            bar_chart.add("MAX", sum(instance_scores[0]))
         self.radar_chart = radar_chart.render()
         self.bar_chart = bar_chart.render()
         self.save()
@@ -128,6 +138,7 @@
     order = models.IntegerField(null=False,blank=False)
     parent = models.ForeignKey('self',null=True,blank=True)
     methodology_version = models.ForeignKey(MethodologyVersion,null=True,blank=True)
+    max_score = 0
     def questions(self):
         q = list(self.question_set.all())
         for p in self.page_set.all():
@@ -180,6 +191,7 @@
         return '<Page Id="' + str(self.id) + '" Name="' + self.name + '" Order="' + str(self.order) + '">' + str_xml + "</Page>"
 
     def calculate_scores(self, instance, weight_scenario, instances):
+        self.max_score = 5
 #         Let's reset the score to 0
         try:
             ps = PageScore.objects.get(page=self, instance=instance)
@@ -321,6 +333,12 @@
     class Meta:
         ordering = ['order']
 
+class Weight():
+    '''
+    used by WeightScenario so I need to define it first
+    '''
+    pass
+
 class WeightScenario(models.Model):
     name = models.CharField(max_length=200)
     methodology_version = models.ForeignKey(MethodologyVersion)
@@ -335,6 +353,7 @@
             if w.question.id == question_id:
                 weight = w.weight
         return weight
+
     def from_xml(self, xmldoc, methodology_version, insert = True):
         if not insert:
             self.id = xmlMinidom.getNaturalAttribute(xmldoc, 'Id')
@@ -369,11 +388,24 @@
         self.scenario = scenario
         self.weight = xmlMinidom.getStringAttribute(xmldoc, 'weight')
         self.question = Question.objects.get(pk=xmlMinidom.getNaturalAttribute(xmldoc, 'question_id'))
+        # If I am inserting I must check that there's no other Weight for the same 
+        # couple ('question', 'scenario') as I have a unique_together constraint
+        if not self.id:
+            # I look for a Weight for the same question and scenario
+            try:
+                w = Weight.objects.get(scenario_id=self.scenario.id, question_id=self.question.id)
+                w.delete()
+            except:
+                # I didn't find one; nothing to do 
+                pass
         self.save()
     
     def to_xml(self):
         return '<Weight Id="' + str(self.id) + '" question_id="' + str(self.question.id) + '" weight="' + str(self.weight) + '"/>'
 
+    class Meta:
+        unique_together = ('question', 'scenario')
+    
 class Analysis(models.Model):
     name = models.CharField(max_length=200)
     description = models.CharField(max_length=2000)
@@ -388,18 +420,17 @@
     def __str__(self):
         return self.name
     
-    def calculate_scores(self):
+    def calculate_scores(self, weight_scenario_id):
         '''
         Calculates scores for each couple (instance, page) and (instance, question)
         Stores them on the db 
         '''
         #let's get the weight from the scenario if any; the default is 1
         try:
-            weight_scenarios = self.methodology_version.weightscenario_set.filter(active=True)
-            if len(weight_scenarios) == 1:
-                weight_scenario = weight_scenarios[0]
+            if weight_scenario_id > 0:
+                weight_scenario = WeightScenario.objects.get(pk=weight_scenario_id)
             else:
-                raise Exception("There should be exactly one WeightScenario for MethodologyVersion " + str(self.methodology_version.id))
+                weight_scenario = self.weight_scenario
         except:
             # an empty one will set all weights to 1
             weight_scenario = WeightScenario()
@@ -410,6 +441,7 @@
             for instance in self.instance_set.all():
                 page.calculate_scores(instance, weight_scenario, self.instance_set.all())
         self.methodology_version.create_graphs(self.instance_set.all())
+        return weight_scenario
         
 #  @staticmethod
 #     def create_graphs(object, pages, instances):
@@ -422,7 +454,26 @@
         All but the MethodologyVersion so that we can independently import from xml 
         MethodologyVersion and Analysis
         '''
-        pass
+        if not insert:
+            self.id = xmlMinidom.getNaturalAttribute(xmldoc, 'Id')
+        self.name = xmlMinidom.getStringAttribute(xmldoc, 'Name')
+        self.comment = xmlMinidom.getStringAttribute(xmldoc, 'Comment')
+        self.created = xmlMinidom.getStringAttribute(xmldoc, 'Created')
+        self.methodology_version = MethodologyVersion.objects.get(pk=xmlMinidom.getNaturalAttribute(xmldoc, 'MethodologyVersionId'))
+        self.user_login = xmlMinidom.getStringAttribute(xmldoc, 'UserLogin')
+        self.visible = xmlMinidom.getStringAttribute(xmldoc, 'Visible')
+        self.protected = xmlMinidom.getStringAttribute(xmldoc, 'Protected')
+        #self.weight_scenario
+        xml_weight_scenario = xmldoc.getElementsByTagName('WeightScenario')[0]
+        ws = WeightScenario()        
+        ws.from_xml(xml_weight_scenario, self.methodology_version, insert)
+        self.weight_scenario = ws
+        self.save()
+        #Instances
+        xml_instances = xmldoc.getElementsByTagName('Instance')
+        for xml_instance in xml_instances:
+            i = Instance()
+            i.from_xml(xml_instance, self, insert)
     
     def to_xml(self):
         str_xml = "<Description>" + self.description + "</Description>"
@@ -433,29 +484,45 @@
             str_xml += instance.to_xml()
         str_xml += "</Instances>"
              
-        return '<Analysis Id="' + str(self.id) + '" Name="' + self.name + '"  Created="' + str(self.created) + '" UserLogin="' + self.user_login + '">' + str_xml + "</Analysis>"
+        return '<Analysis Id="' + str(self.id) + '" MethodologyVersionId="' + str(self.methodology_version.id) + '" Name="' + self.name + '"  Created="' + str(self.created) + '" Visible="' + str(self.visible) + '" Protected="' + str(self.protected) + '" UserLogin="' + self.user_login + '">' + str_xml + "</Analysis>"
     
 class Instance(models.Model):
     """
     It represents one of the entities we evaluate in the assessment
     """
     name = models.CharField(max_length=200)
+    # name_for_search is not used yet; it is intended to provide a name to be used to search the web
     name_for_search = models.CharField(max_length=200, default="")
     analysis = models.ForeignKey(Analysis)
     
     def __str__(self):
         return self.name + " - " + self.name_for_search
     
-    def from_xml(self, xmldoc, insert = True):
-        pass
+    def from_xml(self, xmldoc, analysis, insert = True):
+        if not insert:
+            self.id = xmlMinidom.getNaturalAttribute(xmldoc, 'Id')
+        self.name = xmlMinidom.getStringAttribute(xmldoc, 'Name')
+        #ActualInstance
+        self.analysis = analysis
+        xml_actual_instance = xmldoc.getElementsByTagName(self.analysis.methodology_version.methodology.entity.actual_entity_class)[0]
+        module = importlib.import_module(self.analysis.methodology_version.methodology.entity.actual_entity_app + ".models")
+        actual_entity_class = getattr(module, self.analysis.methodology_version.methodology.entity.actual_entity_class)
+        self.actual_instance = actual_entity_class()
+        self.actual_instance.from_xml(xml_actual_instance, self, insert)
+        self.save()
+        #Answers
+        xml_answers = xmldoc.getElementsByTagName('Answer')
+        for xml_answer in xml_answers:
+            a = Answer()
+            a.from_xml(xml_answer, self, insert)
     
     def to_xml(self):
         str_xml = "<Answers>"
         for answer in self.answer_set.all():
             str_xml += answer.to_xml()
         str_xml += "</Answers>"
-             
-        return '<Instance Id="' + str(self.id) + '" Name="' + self.name + '" NameForSearch="' + self.name_for_search + '">' + str_xml + "</Instance>"
+        str_xml += self.actual_instance.to_xml()
+        return '<Instance Id="' + str(self.id) + '" Name="' + self.name + '">' + str_xml + "</Instance>"
     
 class PageScore(models.Model):
     page = models.ForeignKey(Page)
@@ -477,14 +544,36 @@
     score = models.FloatField(default=0)
     notes = models.CharField(max_length=2000)
     
-    def from_xml(self, xmldoc, insert = True):
-        pass
+    def from_xml(self, xmldoc, instance, insert = True):
+        if not insert:
+            self.id = xmlMinidom.getNaturalAttribute(xmldoc, 'Id')
+        self.instance = instance
+        xml_question = xmldoc.getElementsByTagName('Question')[0]
+        question = Question.objects.get(pk = xmlMinidom.getNaturalAttribute(xml_question, 'Id'))
+        self.question = question
+        self.value_integer = xmlMinidom.getNaturalAttribute(xmldoc, 'ValueInteger')
+        xml_notes = xmldoc.getElementsByTagName('Notes')[0]
+        try:
+            self.notes = xml_notes.firstChild.data
+        except:
+            self.notes = ""
+        # If I am inserting I must check that there's no other answer for the same 
+        # couple ('question', 'instance') as I have a unique_together constraint
+        if not self.id:
+            # I look for an answer for the same question and instance
+            try:
+                a = Answer.objects.get(instance_id=self.instance.id, question_id=self.question.id)
+                a.delete()
+            except:
+                # I didn't find one; nothing to do 
+                pass
+        self.save()
     
     def to_xml(self):
         str_xml = "<Notes>" + self.notes + "</Notes>"
         str_xml += '<Question Id="' + str(self.question.id) + '"></Question>'
              
-        return '<Answer ValueInteger="' + str(self.value_integer) + '">' + str_xml + "</Answer>"
+        return '<Answer Id="' + str(self.id) + '" ValueInteger="' + str(self.value_integer) + '">' + str_xml + "</Answer>"
 
     class Meta:
         unique_together = ('question', 'instance',)
@@ -497,4 +586,8 @@
     '''
     Used to save uploaded xml file so that it can be later retrieved and imported
     '''
-    docfile = models.FileField(upload_to='documents/%Y/%m/%d')+    docfile = models.FileField(upload_to='documents/%Y/%m/%d')
+    
+class MyModel(models.Model):
+    field1 = models.CharField(max_length=40, blank=False, null=False)
+    field2 = models.CharField(max_length=60, blank=True, null=True)