コード例 #1
0
class AbstractDocumentModel(AbstractDocumentManagementModel):
    """Base document model class
    """
    name = fields.char_field(blank=False,
                             null=False,
                             max_length=constants.NAME_FIELD_MAX_LENGTH)
    language = fields.char_field(blank=False,
                                 null=False,
                                 default=settings.LANGUAGE_CODE)
    # deletion of client will result in deletion of its associated documents
    client = fields.foreign_key_field(Client, on_delete=CASCADE)
    mime_type = fields.char_field(blank=False,
                                  null=False,
                                  default=constants.MIME_TYPE_UNKNOWN,
                                  choices=constants.MIME_TYPE_CHOICES)
    document_type = fields.char_field(
        blank=False,
        null=False,
        default=constants.DOCUMENT_TYPE_REFERENCE,
        choices=constants.DOCUMENT_TYPE_CHOICES)

    title = fields.char_field(blank=True,
                              null=True,
                              max_length=constants.TITLE_FIELD_MAX_LENGTH)
    description = fields.description_field(
        blank=True,
        null=True,
        max_length=constants.DESCRIPTION_FIELD_MAX_LENGTH)

    category = fields.foreign_key_field(Category,
                                        blank=True,
                                        null=True,
                                        on_delete=SET_NULL)
    tags = fields.many_to_many_field(Tag,
                                     related_name='documents',
                                     through='DocumentTag',
                                     through_fields=('document', 'tag'))

    annotations = fields.many_to_many_field(Annotation,
                                            related_name='documents',
                                            through='DocumentAnnotation',
                                            through_fields=('document',
                                                            'annotation'))

    #@ TODO: this is not a symetrical relationship -> it is unidirectional using from_document
    documents = fields.many_to_many_field('self',
                                          symmetrical=False,
                                          related_name='related_documents',
                                          through='DocumentAssociation',
                                          through_fields=('from_document',
                                                          'to_document'))

    class Meta(AbstractDocumentManagementModel.Meta):
        """Meta class definition"""
        abstract = True
        unique_together = ('client', 'name')

    def __str__(self):
        """pretty format instance as string"""
        return self.name
コード例 #2
0
class DocumentAssociation(AbstractDocumentManagementModel):
    """Document  association model class.

    A document  may be associated with 0 or more other documents
    Document(1)  -------> Document(0..*)
    """
    from_document = fields.foreign_key_field(Document,
                                             related_name='from_document',
                                             on_delete=CASCADE)
    to_document = fields.foreign_key_field(Document,
                                           related_name='to_document',
                                           on_delete=CASCADE)
    client = fields.foreign_key_field(Client, on_delete=CASCADE)

    # relationship purpose
    purpose = fields.char_field(
        blank=False,
        null=False,
        default=constants.DOCUMENT_ASSOCIATION_PURPOSE_UNKNOWN,
        choices=constants.DOCUMENT_ASSOCIATION_PURPOSE_CHOICES)

    class Meta(AbstractDocumentManagementModel.Meta):
        """Model meta class definition"""
        db_table = db_table(app_label, _document_association)
        verbose_name = _(_document_association_verbose)
        verbose_name_plural = _(pluralize(_document_association_verbose))
        unique_together = ('from_document', 'to_document', 'purpose')

    def __str__(self):
        """pretty format instance as string"""
        return '({},{},{})'.format(str(self.from_document),
                                   str(self.to_document), self.purpose)
コード例 #3
0
class Annotation(AbstractDocumentManagementModel):
    """Annotation class definition
    Allows to annotate another model instance.
    """
    name = fields.char_field(blank=False,
                             null=False,
                             max_length=constants.NAME_FIELD_MAX_LENGTH)
    annotation = fields.annotation_field(
        blank=False,
        null=False,
        max_length=constants.ANNOTATION_FIELD_MAX_LENGTH)
    # deletion of client will result in deletion of associated annotations
    client = fields.foreign_key_field(Client, on_delete=CASCADE)

    class Meta(AbstractDocumentManagementModel.Meta):
        """Meta class definition"""
        abstract = False
        db_table = db_table(app_label, _annotation)
        verbose_name = _(_annotation_verbose)
        verbose_name_plural = _(pluralize(_annotation_verbose))
        unique_together = ('client', 'name')

    def __str__(self):
        """generate pretty string representation"""
        return self.name
コード例 #4
0
ファイル: client.py プロジェクト: ajaniv/document-management
class ClientUser(AbstractDocumentManagementModel):
    """Client user  model class.

    Capture client user  attributes.  A client may be associated
    with 0 or more  users:
        Client(1) ------> Annotation(0..*)

    A user can only be associated with a single client
    """
    # when client or user are deleted, the associated ClientUser instance
    # is deleted.
    client = fields.foreign_key_field(Client, on_delete=CASCADE)
    user = fields.one_to_one_field(to_class=User, on_delete=CASCADE)
    phone = fields.phone_number_field(blank=True, null=True)
    description = fields.description_field(blank=True, null=True,
                                           max_length=constants.DESCRIPTION_FIELD_MAX_LENGTH)


    def has_logged_in(self):
        """Determine if user has ever logged in"""
        return self.user.last_login  is not None    # pylint: disable=no-member


    class Meta(AbstractDocumentManagementModel.Meta):
        """ClientUser meta class"""
        db_table = db_table(app_label, _client_user)
        verbose_name = _(_client_user_verbose)
        verbose_name_plural = _(pluralize(_client_user_verbose))

    def __str__(self):
        """pretty format instance as string"""
        return "{},{}".format(self.client, self.user)
コード例 #5
0
class AnalysisResults(AbstractResultsModel):
    """ Analysis results model class
    """
    documents = fields.foreign_key_field(DocumentAssociation,
                                         on_delete=CASCADE,
                                         blank=True,
                                         null=True)

    class Meta(AbstractResultsModel.Meta):
        """Meta class definition"""
        db_table = db_table(app_label, _analysis_results)
        verbose_name = _(_analysis_results_verbose)
        verbose_name_plural = _(pluralize(_analysis_results_verbose))

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        """save the instance
        """
        self.full_clean()

        # auto assign a name
        if self.documents and not self.name:
            # pylint: disable=no-member
            self.name = '{}:{}'.format(self.documents.from_document.name,
                                       self.documents.to_document.name)
        return super(AnalysisResults, self).save(force_insert, force_update,
                                                 using, update_fields)
コード例 #6
0
ファイル: models.py プロジェクト: ajaniv/document-management
class AbstractModel(models.Model):
    """An abstract base class for application models.
    """

    id = fields.auto_field()
    uuid = fields.uuid_field(
        blank=False,
        null=False,
    )
    version = fields.integer_field(blank=False, null=False)
    is_enabled = fields.boolean_field(blank=False, null=False, default=True)
    is_deleted = fields.boolean_field(blank=False, null=False, default=False)
    creation_time = fields.datetime_field(blank=False,
                                          null=False,
                                          auto_now_add=True)
    update_time = fields.datetime_field(blank=False, null=False, auto_now=True)

    # user who created the instance
    creation_user = fields.user_field(related_name=related_name_base +
                                      "creation_user")

    # user who triggered the instance update
    update_user = fields.user_field(related_name=related_name_base +
                                    "update_user")

    # user on whose behalf change is made
    effective_user = fields.user_field(related_name=related_name_base +
                                       "effective_user")

    site = fields.foreign_key_field(Site,
                                    related_name=related_name_base + "site")

    objects = BaseModelManager()

    class Meta:
        """Meta class declaration."""
        abstract = True
        get_latest_by = "update_time"

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        """Save an instance.
        """
        self.full_clean()
        self.version += 1
        super(AbstractModel, self).save(force_insert=False,
                                        force_update=False,
                                        using=None,
                                        update_fields=None)

    def __str__(self):
        return '{0} object {1.id!s} {1.uuid!s} {1.version!s}'.format(
            instance_class_name(self), self)
コード例 #7
0
class DocumentTag(AbstractDocumentManagementModel):
    """Document tag association model class.

    A document  may be associated with 0 or more tags:
    Document(1)  -------> Tag(0..*)
    """
    document = fields.foreign_key_field(Document, on_delete=CASCADE)
    tag = fields.foreign_key_field(Tag, on_delete=CASCADE)
    client = fields.foreign_key_field(Client, on_delete=CASCADE)

    class Meta(AbstractDocumentManagementModel.Meta):
        """Model meta class definition"""
        db_table = db_table(app_label, _document_tag)
        verbose_name = _(_document_tag_verbose)
        verbose_name_plural = _(pluralize(_document_tag_verbose))
        unique_together = ('document', 'tag')

    def __str__(self):
        """pretty format instance as string"""
        return '({},{})'.format(str(self.document), str(self.tag))
コード例 #8
0
class AbstractResultsModel(AbstractAnalyticsModel):
    """Base results model class
    """
    input = fields.json_field(blank=False, null=False)
    output = fields.json_field(blank=False, null=False)
    name = fields.char_field(blank=True,
                             null=True,
                             max_length=constants.NAME_FIELD_MAX_LENGTH)

    # deletion of client will result in deletion of its associated documents
    client = fields.foreign_key_field(Client, on_delete=CASCADE)

    description = fields.description_field(
        blank=True,
        null=True,
        max_length=constants.DESCRIPTION_FIELD_MAX_LENGTH)

    class Meta(AbstractAnalyticsModel.Meta):
        """Meta class definition"""
        abstract = True

    def __str__(self):
        """pretty format instance as string"""
        return self.name if self.name else super().__str__()
コード例 #9
0
class AbstractClassification(AbstractDocumentManagementModel):
    """Abstract classification class definition
    Allows to associate a classification with an  instance.
    """
    name = fields.char_field(blank=False, null=False, max_length=constants.NAME_FIELD_MAX_LENGTH)
    # deletion of client will result in deletion of associated classifications
    client = fields.foreign_key_field(Client, on_delete=CASCADE)
    # deletion of parent will result in parent being set to null
    parent = fields.foreign_key_field('self', blank=True, null=True,
                                      related_name='children', on_delete=SET_NULL)
    description = fields.description_field(
        blank=True, null=True, max_length=constants.DESCRIPTION_FIELD_MAX_LENGTH)
    # the classification population (i.e. AuxiliaryDocument, Reference Document)
    target = fields.char_field(blank=False, null=False,
                               default=constants.CLASSIFICATION_TARGET_REFERENCE_DOCUMENT,
                               choices=constants.CLASSIFICATION_TARGET_CHOICES)
    # the industry or other top level classification such as finance, insurance, shipping, general
    domain = fields.char_field(blank=False, null=False,
                               default=constants.CLASSIFICATION_DOMAIN_GENERAL,
                               choices=constants.CLASSIFICATION_DOMAIN_CHOICES)

    class Meta(AbstractDocumentManagementModel.Meta):
        """Meta class definition"""
        abstract = True
        unique_together = ('client', 'name')

    def clean(self):
        """Model wide validation"""
        # pylint: disable=no-member
        if self.parent:
            if not self.parent.id:
                raise ValidationError(_('Invalid parent - has not been saved.'))
            # verify that parent exists - if not exception will be thrown
            self.__class__.objects.get(pk=self.parent.id)

        # check the entire hierarchy for name and id duplicates
        depth = 0
        max_depth = 10
        current = self
        name_cache = dict()
        id_cache = dict()
        while current and depth < max_depth:
            current_name = current.name
            current_id = current.id
            if current_name in name_cache:
                raise ValidationError(_(f'Duplicate name {current_name} in hierarchy.'))
            if current_id in id_cache:
                raise ValidationError(_(f'Duplicate id {current_id} in hierarchy.'))

            name_cache[current_name] = current
            id_cache[current_id] = current
            if current.parent:
                current = self.__class__.objects.get(pk=current.parent.id)
                depth += 1
            else:
                current = current.parent

        if depth >= max_depth:
            raise ValidationError(_(f'Max depth of {max_depth} exceeded.'))

        super(AbstractClassification, self).clean()

    def __str__(self):
        """generate pretty string representation"""
        full_path = [self.name]
        current = self.parent

        while current is not None:
            full_path.append(current.name)
            current = current.parent        # pylint: disable=no-member

        return ' -> '.join(full_path[::-1])