Skip to content
Snippets Groups Projects
models.py 8.52 KiB
from copy import deepcopy

from django.contrib.contenttypes.fields import GenericRelation
from typing import List, Optional

from django.db import models, transaction

from financial_settlement.models import FinStatement
from meanings.models import LexicalUnit, Synset
from semantics.models import PredefinedSelectionalPreference, RelationalSelectionalPreference, ArgumentRole, \
    RoleType, Argument, Frame, SelectionalPreferenceRelation

from . import choices


class UnifiedFrameQueryset(models.QuerySet):
    def for_lexical_unit(self, lexical_unit):
        return self.filter(unified_frame_2_slowal_frame__slowal_frame__lexical_units=lexical_unit)


class UnifiedFrame(models.Model):
    status = models.TextField(
        max_length=10,
        choices=choices.UnifiedFrameStatus.choices,
        default=choices.UnifiedFrameStatus.PROCESSING,
    )
    title = models.CharField(max_length=200, default=None, blank=True, null=True)

    assignments = GenericRelation("users.Assignment", content_type_field="subject_ct", object_id_field="subject_id")

    arguments_count = models.PositiveIntegerField(null=False, default=0)

    slowal_frames_count = models.PositiveIntegerField(null=False, default=0)

    objects = models.Manager.from_queryset(UnifiedFrameQueryset)()

    fin_statement = models.ForeignKey(FinStatement, on_delete=models.PROTECT, blank=True, default=None, null=True,
                                      related_name='unified_frame')

    hasHierarchyElems = models.BooleanField(default=False)

    def sorted_arguments(self):  # TODO: zaimplementowac wlasciwe sortowanie
        return UnifiedFrameArgument.objects.filter(unified_frame=self)

    def __str__(self):
        return '%s: %s' % (self.status, ' + '.join([str(arg) for arg in self.sorted_arguments()]))
    
    @transaction.atomic
    def extract_frames_to(
            self, slowal_frames: List[Frame], new_frame: Optional["UnifiedFrame"] = None
    ) -> "UnifiedFrame":
        new_unified_frame_arguments = None
        if not new_frame:
            new_frame = UnifiedFrame.objects.create()
            new_frame.arguments_count = self.arguments_count
            new_frame.save()
            unified_frame_arguments = UnifiedFrameArgument.objects.filter(unified_frame=self)
            old_2_new_argument_mapping = {}
            for unified_frame_argument in unified_frame_arguments:
                new_unified_frame_argument = UnifiedFrameArgument.objects.create(
                                                                  role_type=unified_frame_argument.role_type,
                                                                  role=unified_frame_argument.role,
                                                                  unified_frame=new_frame)
                new_unified_frame_argument.proposed_roles.set(unified_frame_argument.proposed_roles.all())
                new_unified_frame_argument.save()
                old_2_new_argument_mapping[unified_frame_argument.id] = new_unified_frame_argument.id
        else:
            new_unified_frame_arguments = UnifiedFrameArgument.objects.filter(unified_frame=new_frame).all()
            unified_frame_arguments = UnifiedFrameArgument.objects.filter(unified_frame=self).all()
            if len(new_unified_frame_arguments) < len(unified_frame_arguments):
                raise Exception('Target frame has to little arguments, required: ' + str(len(unified_frame_arguments)) +
                                ', but found: '+str(len(new_unified_frame_arguments)))

        for slowal_frame in slowal_frames:
            mapping = UnifiedFrame2SlowalFrameMapping.objects.get(unified_frame=self, slowal_frame=slowal_frame)
            mapping.unified_frame = new_frame
            mapping.save()
            argument_mappings = UnifiedFrameArgumentSlowalFrameMapping.objects.filter(unified_frame_mapping=mapping)
            for i, argument_mapping in enumerate(argument_mappings):
                if new_unified_frame_arguments is None:
                    argument_mapping.unified_agrument_id = old_2_new_argument_mapping[argument_mapping.unified_agrument_id]
                else:
                    argument_mapping.unified_agrument_id = new_unified_frame_arguments[i]
                argument_mapping.save()

        self.update_sloval_frame_count()
        new_frame.update_sloval_frame_count()

        # curr_mapping = UnifiedFrame2SlowalFrameMapping.objects.filter(unified_frame=self).all()
        # if len(curr_mapping) == 0:
        #     unified_frame_arguments = UnifiedFrameArgument.objects.filter(unified_frame=self).all()
        #     unified_frame_arguments.delete()
        #     self.delete()

        return new_frame

    @transaction.atomic
    def update_sloval_frame_count(
            self, new_frame_title: Optional = None
    ) -> "UnifiedFrame":
        self.slowal_frames_count = self.unified_frame_2_slowal_frame.count()
        self.save()

    @transaction.atomic
    def duplicate(
            self, new_frame_title: Optional = None
    ) -> "UnifiedFrame":
        new_frame = UnifiedFrame.objects.create(title=new_frame_title)
        new_frame.arguments_count = self.arguments_count
        new_frame.slowal_frames_count = self.slowal_frames_count
        new_frame.save()
        unified_frame_arguments = UnifiedFrameArgument.objects.filter(unified_frame=self)
        for unified_frame_argument in unified_frame_arguments:
            new_unified_frame_argument = UnifiedFrameArgument.objects.create(
                role_type=unified_frame_argument.role_type,
                role=unified_frame_argument.role,
                unified_frame=new_frame)
            new_unified_frame_argument.proposed_roles.set(unified_frame_argument.proposed_roles.all())
            new_unified_frame_argument.predefined.set(unified_frame_argument.predefined.all())
            new_unified_frame_argument.synsets.set(unified_frame_argument.synsets.all())
            new_unified_frame_argument.relations.set(unified_frame_argument.relations.all())
            new_unified_frame_argument.save()

        return new_frame


class UnifiedFrameArgument(models.Model):
    role_type = models.ForeignKey(RoleType, on_delete=models.PROTECT, default=None, blank=True, null=True)
    # rola - wybrana przez użytkownika
    role = models.ForeignKey(ArgumentRole, on_delete=models.PROTECT, default=None, blank=True, null=True)
    # role zaproponowane przez system unifikacyjny
    proposed_roles = models.ManyToManyField(ArgumentRole, related_name='proposed_roles')

    # 3 typy preferencji - wybrane przez użytkownika
    predefined = models.ManyToManyField(PredefinedSelectionalPreference)
    synsets = models.ManyToManyField(Synset)
    relations = models.ManyToManyField('UnifiedRelationalSelectionalPreference')

    # odwołanie do ramy
    unified_frame = models.ForeignKey(UnifiedFrame, related_name='unified_arguments',
                                      default=None, blank=True, null=True, on_delete=models.PROTECT)

    # do wyszukiwania
    preferences_count = models.PositiveIntegerField(null=False, default=0)

    def __str__(self):
        return str(self.role)


class UnifiedRelationalSelectionalPreference(models.Model):
    relation = models.ForeignKey(SelectionalPreferenceRelation, on_delete=models.PROTECT)
    to = models.ForeignKey(UnifiedFrameArgument, on_delete=models.PROTECT)

    def __str__(self):
        return '%s -> %s' % (self.relation, self.to)


class UnifiedFrame2SlowalFrameMapping(models.Model):
    removed = models.BooleanField(default=False)
    unified_frame = models.ForeignKey(UnifiedFrame, related_name='unified_frame_2_slowal_frame',
                                      on_delete=models.PROTECT)
    slowal_frame = models.OneToOneField(Frame, related_name='slowal_frame_2_unified_frame', on_delete=models.PROTECT)


class UnifiedFrameArgumentSlowalFrameMapping(models.Model):
    unified_agrument = models.ForeignKey(UnifiedFrameArgument, related_name='unified_agrument_mapping',
                                         on_delete=models.PROTECT)
    slowal_agrument = models.ForeignKey(Argument, related_name='slowal_agrument_mapping', on_delete=models.PROTECT)
    unified_frame_mapping = models.ForeignKey(UnifiedFrame2SlowalFrameMapping,
                                              related_name='unified_frame_argument_mapping', on_delete=models.PROTECT)


class HierarchyModel(models.Model):
    """Represents hierarchy relationship between two unified frames."""
    hyponym = models.ForeignKey(UnifiedFrame, related_name='hyponym_mapping', on_delete=models.PROTECT)
    hyperonym = models.ForeignKey(UnifiedFrame, related_name='hyperonym_mapping', on_delete=models.PROTECT)