<commit_before># -*- coding: utf-8 -*-
import logging
LOG = logging.getLogger(__name__)

import itertools

from django.utils import timezone
from django.utils.text import slugify
from django.contrib.gis.db import models
from django.conf import settings

from django.contrib.contenttypes.fields import GenericForeignKey

from model_utils import FieldTracker
from pg_fts.fields import TSVectorField

from .querysets import PassThroughGeoManager, LocalitiesQuerySet


class ChangesetMixin(models.Model):
    changeset = models.ForeignKey('Changeset')
    version = models.IntegerField()

    class Meta:
        abstract = True

    def inc_version(self):
        self.version = (self.version or 0) + 1


class UpdateMixin(models.Model):
    class Meta:
        abstract = True

    def before_save(self, *args, **kwargs):
        """
        Executed before actually saving the model, should be overridden
        """
        pass

    def save(self, *args, **kwargs):
        # update
        if self.pk and not(kwargs.get('force_insert')):
            # execute any model specific changes
            self.before_save(*args, update=True, **kwargs)

            if self.tracker.changed():
                # increase version and save if there are more changed attrs
                self.inc_version()
                super(UpdateMixin, self).save(*args, **kwargs)
        # create
        else:
            self.before_save(*args, create=True, **kwargs)
            self.inc_version()
            super(UpdateMixin, self).save(*args, **kwargs)


class ArchiveMixin(ChangesetMixin):
    content_type = models.ForeignKey('contenttypes.ContentType')
    object_id = models.IntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    class Meta:
        abstract = True


class Domain(UpdateMixin, ChangesetMixin):
    name = models.CharField(max_length=50, unique=True)
    description = models.TextField(null=True, blank=True, default='')
    template_fragment = models.TextField(null=True, blank=True, default='')

    attributes = models.ManyToManyField('Attribute', through='Specification')

    tracker = FieldTracker()

    def __unicode__(self):
        return u'{}'.format(self.name)


class DomainArchive(ArchiveMixin):
    name = models.CharField(max_length=50)
    description = models.TextField(null=True, blank=True)
    template_fragment = models.TextField(null=True, blank=True)


class Locality(UpdateMixin, ChangesetMixin):
    domain = models.ForeignKey('Domain')
    uuid = models.TextField(unique=True)
    upstream_id = models.TextField(null=True, unique=True)
    geom = models.PointField(srid=4326)
    specifications = models.ManyToManyField('Specification', through='Value')

    objects = PassThroughGeoManager.for_queryset_class(LocalitiesQuerySet)()

    tracker = FieldTracker()

    def before_save(self, *args, **kwargs):
        # make sure that we don't allow uuid modifications
        if self.tracker.previous('uuid') and self.tracker.has_changed('uuid'):
            self.uuid = self.tracker.previous('uuid')
<commit_msg>Document Locality models<commit_after># -*- coding: utf-8 -*-
import logging
LOG = logging.getLogger(__name__)

import itertools

from django.utils import timezone
from django.utils.text import slugify
from django.contrib.gis.db import models
from django.conf import settings

from django.contrib.contenttypes.fields import GenericForeignKey

from model_utils import FieldTracker
from pg_fts.fields import TSVectorField

from .querysets import PassThroughGeoManager, LocalitiesQuerySet


class ChangesetMixin(models.Model):
    """
    This mixin facilitates defines common attributes and methods for models
    that will record and track changes
    """
    changeset = models.ForeignKey('Changeset')
    version = models.IntegerField()

    class Meta:
        abstract = True

    def inc_version(self):
        """
        Common method to increase version of a tracked object
        """
        self.version = (self.version or 0) + 1


class UpdateMixin(models.Model):
    """
    This mixin defines common methods for models that are tracked using
    changeset and version

    *save* method will increase version of an 'object' if there are changes

    Models that use this mixin should be extra careful when overriding save,
    in case they just need to change some fields, 'before_save' should be
    overridden instead
    """
    class Meta:
        abstract = True

    def before_save(self, *args, **kwargs):
        """
        Executed before actually saving the model, should be overridden
        """
        pass

    def save(self, *args, **kwargs):
        # object exists - update
        if self.pk and not(kwargs.get('force_insert')):
            # execute any model specific changes
            self.before_save(*args, update=True, **kwargs)

            if self.tracker.changed():
                # increase version and save in case there are changed attrs
                self.inc_version()
                super(UpdateMixin, self).save(*args, **kwargs)
        # object does not exist - create
        else:
            self.before_save(*args, create=True, **kwargs)
            self.inc_version()
            super(UpdateMixin, self).save(*args, **kwargs)


class ArchiveMixin(ChangesetMixin):
    """
    This mixin defines common attributes for Object archival

    We opted to use ContentType framework in order to delete referenced
    objects without depending on *on_delete* support in Django

    Object archival is facilitated by Django signal framework
    """
    content_type = models.ForeignKey('contenttypes.ContentType')
    object_id = models.IntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    class Meta:
        abstract = True


class Domain(UpdateMixin, ChangesetMixin):
    """
    Domain defines a common theme for the data, for example: Health,
    Sanitation and House, might be considered as unique domains

    Domain is defined by a *name* and an optional *description*. Every domain
    might have different attributes so we can define it's representation using
    the *template_fragment*.

    Connection between a Domain and Attributes is defined though the
    *Specification* model
    """
    name = models.CharField(max_length=50, unique=True)
    description = models.TextField(null=True, blank=True, default='')
    template_fragment = models.TextField(null=True, blank=True, default='')

    attributes = models.ManyToManyField('Attribute', through='Specification')

    tracker = FieldTracker()

    def __unicode__(self):
        return u'{}'.format(self.name)


class DomainArchive(ArchiveMixin):
    """
    Defines Archive model for the Domain
    """
    name = models.CharField(max_length=50)
    description = models.TextField(null=True, blank=True)
    template_fragment = models.TextField(null=True, blank=True)


class Locality(UpdateMixin, ChangesetMixin):
    """
    A Locality is uniquely defined by an *uuid* attribute. Attribute *geom*
    stores geometry as a point object. *upstream_id* is used to preserve link
    to the originating dataset which is used to find and update a Locality on
    any reoccurring data imports.

    A Locality is in a *Domain* and data values for Attributes, to be exact,
    their Specifications, are defined through *Value*
    """
    domain = models.ForeignKey('Domain')
    uuid = models.TextField(unique=True)
    upstream_id = models.TextField(null=True, unique=True)
    geom = models.PointField(srid=4326)
    specifications = models.ManyToManyField('Specification', through='Value')

    objects = PassThroughGeoManager.for_queryset_class(LocalitiesQuerySet)()

    tracker = FieldTracker()

    def before_save(self, *args, **kwargs):
        # make sure that we don't allow uuid modifications
        if self.tracker.previous('uuid') and self.tracker.has_changed('uuid'):
            self.uuid = self.tracker.previous('uuid')

{'fraction_non_alphanumeric': 0.09243697478991597, 'fraction_numerical': 0.002759312680295999, 'mean_word_length': 3.3455040871934605, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2958598', 'n_tokens_mistral': 2216, 'n_tokens_neox': 2118, 'n_words': 652}