コード例 #1
0
class Grootstedelijkgebied(models.Model):
    """
    model for data from shp files

    layer.fields:

    ['NAAM']
    """

    id = models.SlugField(max_length=100, primary_key=True)
    naam = models.CharField(max_length=100)
    gsg_type = models.CharField(max_length=5, null=True)
    geometrie = geo.MultiPolygonField(null=True, srid=28992)

    date_modified = models.DateTimeField(auto_now=True)
    objects = geo.Manager()

    class Meta:
        verbose_name = "Grootstedelijkgebied"
        verbose_name_plural = "Grootstedelijke gebieden"

    def __str__(self):
        return "{}".format(self.naam)
コード例 #2
0
ファイル: models.py プロジェクト: happyfisherod/mtp-web
class MapFeature(models.Model):
    unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    accuracy = models.FloatField(default=0)
    altitude = models.FloatField(default=0)
    direction = models.FloatField(default=0)
    first_seen_at = models.DateTimeField(null=True, blank=True)
    mf_key = models.CharField(max_length=100, null=True, blank=True)
    last_seen_at = models.DateTimeField(null=True, blank=True)
    layer = models.CharField(max_length=50)
    value = models.CharField(max_length=100)
    geometry_type = models.CharField(max_length=50, default='Point')
    geometry_point = models.PointField(null=True, blank=True)
    detection_keys = ArrayField(ArrayField(models.CharField(max_length=50)), null=True, blank=True)
    image_keys = ArrayField(ArrayField(models.CharField(max_length=50)), null=True, blank=True)
    user_keys = ArrayField(ArrayField(models.CharField(max_length=50)), null=True, blank=True)

    objects = models.Manager()
    vector_tiles = CustomMapFeatureMVTManager(
        geo_col='geometry_point',
        select_columns=['mf_key', 'unique_id'],
        is_show_id=False,
        source_layer='mtp-map-features'
    )
コード例 #3
0
class Category(models.Model):
    "Model definition of a Category."

    guid = models.UUIDField(_('GUID'),
                            primary_key=False,
                            null=False,
                            default=uuid_lib.uuid4,
                            editable=False)

    name = models.CharField(_('Name of Category'),
                            max_length=255,
                            help_text=_('Enter Category name.'))

    image = models.ImageField(
        _('Image file'),
        null=True,
        blank=True,
        upload_to=os.path.join(MEDIA_ROOT, 'images/trail_category'),
        help_text=_(
            'An image of the trail section. '
            'Most browsers support dragging the image directly on to the '
            '"Choose File" button above.'))

    slug = models.SlugField(null=True, blank=True)

    objects = models.Manager()

    class Meta:
        ordering = ['name']
        app_label = 'trail'
        verbose_name_plural = 'Trail Categories'

    def _str__(self):
        return self.__unicode__()

    def __unicode__(self):
        return '%s' % (self.name)
コード例 #4
0
ファイル: models.py プロジェクト: nicosiseng/mollyproject
class Feed(models.Model):
    title = models.TextField()
    unit = models.CharField(max_length=10, null=True, blank=True)
    rss_url = models.URLField()
    slug = models.SlugField()
    last_modified = models.DateTimeField(null=True,
                                         blank=True)  # this one is in UTC

    ptype = models.CharField(max_length=1, choices=FEED_TYPE_CHOICES)
    provider = models.CharField(max_length=128, choices=PROVIDER_CHOICES)

    def _set_importer_params(self, value):
        self._importer_params = simplejson.dumps(value)

    def _get_importer_params(self):
        return simplejson.loads(self._importer_params)

    importer_params = property(_get_importer_params, _set_importer_params)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    tags = models.ManyToManyField(Tag, blank=True)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-list', args=[self.slug])
        else:
            return reverse('events:item-list', args=[self.slug])

    class Meta:
        ordering = ('title', )
コード例 #5
0
class PointBased(gis_models.Model):
    id = gis_models.AutoField(primary_key=True, editable=False)
    name = gis_models.CharField(max_length=200)
    type = gis_models.CharField(max_length=200, null=True, blank=True)
    subnational = gis_models.ForeignKey(SubNational,
                                        null=True,
                                        blank=True,
                                        on_delete=gis_models.SET_NULL)
    center_longlat = gis_models.PointField(null=True, blank=True)
    comment = gis_models.TextField()
    data_source = gis_models.CharField(max_length=100, null=True, blank=True)
    objects = gis_models.Manager()
    geolocation = GenericRelation(Geolocation,
                                  related_query_name='point_based')

    @property
    def is_capital(self):
        return hasattr(self, 'capital_of')

    def __unicode__(self):
        return self.name

    class Meta:
        verbose_name_plural = "cities"
コード例 #6
0
class SubNational(gis_models.Model):
    id = gis_models.AutoField(primary_key=True, editable=False)
    name = gis_models.CharField(unique=True, max_length=100)
    iso_3166_2 = gis_models.CharField(null=True, blank=True, max_length=2)
    code_local = gis_models.CharField(null=True, blank=True, max_length=100)
    postcode = gis_models.CharField(null=True, blank=True, max_length=100)
    country = gis_models.ForeignKey(Country,
                                    null=True,
                                    blank=True,
                                    on_delete=gis_models.SET_NULL)
    center_longlat = gis_models.PointField(null=True, blank=True)
    polygons = gis_models.GeometryField(null=True, blank=True)
    wikipedia = gis_models.CharField(null=True, blank=True, max_length=150)
    language = gis_models.CharField(max_length=2, null=True)
    data_source = gis_models.CharField(max_length=100, null=True, blank=True)
    objects = gis_models.Manager()
    geolocation = GenericRelation(Geolocation,
                                  related_query_name='sub_national')

    def __unicode__(self):
        return self.name

    class Meta:
        verbose_name_plural = "admin1 regions"
コード例 #7
0
ファイル: models.py プロジェクト: spreeker/bag_services
class GebiedsgerichtwerkenPraktijkgebieden(models.Model):
    """
    model for data from shp files

    layer.fields:

    ['NAAM']
    """

    naam = models.CharField(max_length=100, unique=True)

    date_modified = models.DateTimeField(auto_now=True)

    geometrie = geo.MultiPolygonField(null=True, srid=28992)

    objects = geo.Manager()

    class Meta:
        verbose_name = "Gebiedsgerichtwerken praktijkgebieden"
        verbose_name_plural = "Gebiedsgerichtwerken praktijkgebieden"
        ordering = ('naam', )

    def __str__(self):
        return "{}".format(self.naam)
コード例 #8
0
ファイル: models.py プロジェクト: JivanAmara/eventkit-cloud
class ExportFormat(TimeStampedModelMixin):
    """
    Model for a ExportFormat.
    """
    id = models.AutoField(primary_key=True, editable=False)
    uid = models.UUIDField(unique=True,
                           default=uuid.uuid4,
                           editable=False,
                           db_index=True)
    name = models.CharField(max_length=100)
    slug = LowerCaseCharField(max_length=20, unique=True, default='')
    description = models.CharField(max_length=255)
    cmd = models.TextField(max_length=1000)
    objects = models.Manager()

    class Meta:  # pragma: no cover
        managed = True
        db_table = 'export_formats'

    def __str__(self):
        return '{0}'.format(self.name)

    def __unicode__(self, ):
        return '{0}'.format(self.slug)
コード例 #9
0
class Feed(models.Model):
    title = models.TextField(help_text=_("Feed title"))
    entity = models.ForeignKey(Entity,
                               null=True,
                               blank=True,
                               help_text=_('Place which this feed belongs to'))
    rss_url = models.URLField(help_text=_("URL of feed"),
                              verbose_name=_("URL"))
    slug = models.SlugField(help_text=_("Slug of feed, e.g. oucs-news"))
    # this one is in UTC
    last_modified = models.DateTimeField(null=True, blank=True)
    language = models.CharField(max_length=10,
                                choices=settings.LANGUAGES,
                                null=True)

    # Provider type
    ptype = models.CharField(max_length=1, choices=FEED_TYPE_CHOICES)
    provider = models.CharField(max_length=128, choices=PROVIDER_CHOICES)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    tags = models.ManyToManyField(Tag, blank=True)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-list', args=[self.slug])
        else:
            return reverse('events:item-list', args=[self.slug])

    class Meta:
        ordering = ('title', )
コード例 #10
0
class Hostels(models.Model):
    location = models.PointField(null=True)
    objects = models.Manager()
    address = models.CharField(max_length=100, null=True)
    hostel_name = models.CharField(max_length=50, null=True)
    hostel_room_size = models.IntegerField(null=True)
    hostel_floor_no = models.IntegerField(null=True)
    hostel_room_type = models.BooleanField(default=True)
    hostel_attached_bathroom = models.BooleanField(default=True)
    hostel_mess_facility = models.BooleanField(default=True)
    hostel_other_facilities1 = models.BooleanField(default=True)
    hostel_other_facilities2 = models.BooleanField(default=True)
    hostel_other_facilities3 = models.BooleanField(default=True)
    hostel_other_facilities4 = models.BooleanField(default=True)
    hostel_owner_name = models.CharField(max_length=100, null=True)
    hostel_owner_number = models.PositiveIntegerField(
        null=True, default=0, validators=[MaxValueValidator(9999999999)])
    hostel_owner_mail = models.CharField(max_length=100, null=True)
    hostel_price = models.DecimalField(null=True,
                                       max_digits=10,
                                       decimal_places=2,
                                       default=Decimal('0.00'))
    hostel_description = models.CharField(max_length=300, null=True)
    images1 = models.ImageField(upload_to="images", null=True)
    images2 = models.ImageField(upload_to="images", null=True)
    images3 = models.ImageField(upload_to="images", null=True)
    rating = models.DecimalField(max_digits=10,
                                 decimal_places=2,
                                 default=Decimal('0.00'))
    comments_count = models.IntegerField(default=0)

    def __unicode__(self):
        return self.name

    class Meta:
        verbose_name_plural = "Hostels"
コード例 #11
0
ファイル: models.py プロジェクト: llonchj/django-geonames
class Country(models.Model):
    code = models.CharField(max_length=2, primary_key=True)
    name = models.CharField(max_length=200, unique=True, db_index=True)
    languages = models.ManyToManyField(Language, related_name="countries")
    currency = models.ForeignKey(Currency, related_name="countries")
    # is the website available in this country?
    available = models.BooleanField(default=False)
    deleted = models.BooleanField(default=False)

    objects = ActiveCountryManager()
    objects_deleted_inc = models.Manager()

    class Meta:
        ordering = ['name']

    def __unicode__(self):
        return self.name

    def search_locality(self, locality_name):
        if len(locality_name) == 0:
            return []
        q = Q(country_id=self.code)
        q &= (Q(name__iexact=locality_name) | Q(alternatenames__name__iexact=locality_name))
        return Locality.objects.filter(q).distinct()
コード例 #12
0
class Map(NamedModel):
    """
    Workspace
    """
    ANONYMOUS = 1
    EDITORS = 2
    OWNER = 3
    PUBLIC = 1
    OPEN = 2
    PRIVATE = 3
    EDIT_STATUS = (
        (ANONYMOUS, _('Everyone can edit')),
        (EDITORS, _('Only editors can edit')),
        (OWNER, _('Only owner can edit')),
    )
    SHARE_STATUS = (
        (PUBLIC, _('Public: everyone')),
        (OPEN, _('Hidden: anyone with link')),
        (PRIVATE, _('Private: editors only')),
    )
    slug = models.SlugField(db_index=True)
    description = models.TextField(blank=True,
                                   null=True,
                                   verbose_name=_("description"))
    center = models.PointField(geography=True, verbose_name=_("center"))
    zoom = models.IntegerField(default=7, verbose_name=_("zoom"))
    epsg = models.TextField(default=settings.EPSG,
                            blank=True,
                            null=True,
                            verbose_name=_("EPSG code"))
    proj = models.TextField(default=settings.PROJ,
                            blank=True,
                            null=True,
                            verbose_name=_("Proj"))
    resolutions = models.TextField(default=settings.RESOLUTIONS,
                                   blank=True,
                                   null=True,
                                   verbose_name=_("Proj"))
    origin = models.TextField(default=settings.ORIGIN,
                              blank=True,
                              null=True,
                              verbose_name=_("Proj"))

    locate = models.BooleanField(default=False,
                                 verbose_name=_("locate"),
                                 help_text=_("Locate user on load?"))
    licence = models.ForeignKey(Licence,
                                help_text=_("Choose the map licence."),
                                verbose_name=_('licence'),
                                on_delete=models.SET_DEFAULT,
                                default=get_default_licence)
    modified_at = models.DateTimeField(auto_now=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              blank=True,
                              null=True,
                              related_name="owned_maps",
                              verbose_name=_("owner"),
                              on_delete=models.PROTECT)
    editors = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                     blank=True,
                                     verbose_name=_("editors"))
    edit_status = models.SmallIntegerField(choices=EDIT_STATUS,
                                           default=EDITORS,
                                           verbose_name=_("edit status"))
    share_status = models.SmallIntegerField(choices=SHARE_STATUS,
                                            default=PUBLIC,
                                            verbose_name=_("share status"))
    settings = DictField(blank=True, null=True, verbose_name=_("settings"))

    objects = models.Manager()
    public = PublicManager()

    def get_absolute_url(self):
        return reverse("map",
                       kwargs={
                           'slug': self.slug or "map",
                           'pk': self.pk
                       })

    def get_anonymous_edit_url(self):
        signer = Signer()
        signature = signer.sign(self.pk)
        return reverse('map_anonymous_edit_url',
                       kwargs={'signature': signature})

    def is_anonymous_owner(self, request):
        if self.owner:
            # edit cookies are only valid while map hasn't owner
            return False
        key, value = self.signed_cookie_elements
        try:
            has_anonymous_cookie = int(request.get_signed_cookie(
                key, False)) == value
        except ValueError:
            has_anonymous_cookie = False
        return has_anonymous_cookie

    def can_edit(self, user=None, request=None):
        """
        Define if a user can edit or not the instance, according to his account
        or the request.
        """
        can = False
        if request and not self.owner:
            if (getattr(settings, "UMAP_ALLOW_ANONYMOUS", False)
                    and self.is_anonymous_owner(request)):
                can = True
        if self.edit_status == self.ANONYMOUS:
            can = True
        elif not user.is_authenticated:
            pass
        elif user == self.owner:
            can = True
        elif self.edit_status == self.EDITORS and user in self.editors.all():
            can = True
        return can

    def can_view(self, request):
        if self.owner is None:
            can = True
        elif self.share_status in [self.PUBLIC, self.OPEN]:
            can = True
        elif request.user == self.owner:
            can = True
        else:
            can = not (self.share_status == self.PRIVATE
                       and request.user not in self.editors.all())
        return can

    @property
    def signed_cookie_elements(self):
        return ('anonymous_owner|%s' % self.pk, self.pk)

    def get_tilelayer(self):
        return self.tilelayer or TileLayer.get_default()

    def clone(self, **kwargs):
        new = self.__class__.objects.get(pk=self.pk)
        new.pk = None
        new.name = u"%s %s" % (_("Clone of"), self.name)
        if "owner" in kwargs:
            # can be None in case of anonymous cloning
            new.owner = kwargs["owner"]
        new.save()
        for editor in self.editors.all():
            new.editors.add(editor)
        for datalayer in self.datalayer_set.all():
            datalayer.clone(map_inst=new)
        return new

    class Meta:
        verbose_name = 'Workspace'
        verbose_name_plural = 'Workspaces'
コード例 #13
0
class Questionnaire(models.Model):
    """
    The model representing a Questionnaire instance. This is the common
    denominator for all version (:class:`QuestionnaireVersion`) of a
    Questionnaire.
    """
    data = JSONField()
    created = models.DateTimeField()
    updated = models.DateTimeField()
    uuid = models.CharField(max_length=64, default=uuid4)
    code = models.CharField(max_length=64, default='')
    geom = models.GeometryField(null=True, blank=True)
    is_deleted = models.BooleanField(default=False)
    status = models.IntegerField(choices=STATUSES)
    version = models.IntegerField()
    members = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                     through='QuestionnaireMembership')
    configuration = models.ForeignKey('configuration.Configuration',
                                      on_delete=models.PROTECT)
    links = models.ManyToManyField('self',
                                   through='QuestionnaireLink',
                                   symmetrical=False,
                                   related_name='linked_to+')
    flags = models.ManyToManyField('Flag')

    objects = models.Manager()
    with_status = StatusQuerySet.as_manager()

    class Meta:
        ordering = ['-updated']
        permissions = (
            ("review_questionnaire", "Can review questionnaire"),
            ("publish_questionnaire", "Can publish questionnaire"),
            ("assign_questionnaire",
             "Can assign questionnaire (for review/publish)"),
            ("view_questionnaire", "Can view questionnaire"),
            ("edit_questionnaire", "Can edit questionnaire"),
            ("change_compiler", "Can change compiler of questionnaire"),
            ("flag_unccd_questionnaire", "Can flag UNCCD questionnaire"),
            ("unflag_unccd_questionnaire", "Can unflag UNCCD questionnaire"),
        )
        unique_together = (('code', 'version'), )

    def _get_url_from_configured_app(self, url_name: str) -> str:
        """
        Try to resolve the proper code for the object, using it as namespace.

        If some day, the configurations code is not the exact same string as
        the application name, a 'mapping' dict is required.
        """
        with contextlib.suppress(NoReverseMatch):
            return reverse('{app_name}:{url_name}'.format(
                app_name=self.configuration.code, url_name=url_name),
                           kwargs={'identifier': self.code})
        return None

    def get_absolute_url(self):
        """
        Detail view url of the questionnaire. Important: don't use type hints
        as djangorestframework as of now throws errors
        (https://github.com/tomchristie/django-rest-framework/pull/4076)
        """
        return self._get_url_from_configured_app('questionnaire_details')

    def get_edit_url(self) -> str:
        """
        Edit view url of the questionnaire
        """
        return self._get_url_from_configured_app('questionnaire_edit')

    def get_perma_url(self) -> str:
        """
        Detail view url of this specific version, matched by its ID. 'Pseudo-Permalink',
        not the URL that shows the current version of the questionnaire.
        """
        with contextlib.suppress(NoReverseMatch):
            return reverse(
                f'{self.configuration.code}:questionnaire_permalink',
                kwargs={'pk': self.pk})
        return ''

    def update_data(self, data, updated, configuration_code):
        """
        Helper function to just update the data of the questionnaire
        without creating a new instance.

        Args:
            ``data`` (dict): The data dictionary

            ``updated`` (timestamp): The timestamp of the update

            ``configuration_code`` (str): The configuration code.

        Returns:
            ``Questionnaire``
        """
        self.data = data
        self.updated = updated
        self.save()
        # Unblock all questionnaires with this code, as all questionnaires with
        # this code are blocked for editing.
        Lock.objects.filter(questionnaire_code=self.code).update(
            is_finished=True)

        try:
            self.update_geometry(configuration_code=configuration_code)
        except:
            pass

        # Update the users attached to the questionnaire
        self.update_users_from_data(configuration_code)

        return self

    @staticmethod
    def create_new(configuration_code,
                   data,
                   user,
                   previous_version=None,
                   status=1,
                   created=None,
                   updated=None,
                   old_data=None,
                   languages=None):
        """
        Create and return a new Questionnaire.

        Args:
            ``configuration_code`` (str): The code of the configuration.
            An active configuration with the given code needs to exist.
            The configuration is linked to the questionnaire.

            ``data`` (dict): The questionnaire data.

        Kwargs:
            ``previous_version`` (questionnaire.models.Questionnaire):
            The previous version of the questionnaire.

            ``status`` (int): The status of the questionnaire to be
            created. Defaults to 1 (draft) if not set.

            ``created`` (datetime): A specific datetime object to be set
            as created timestamp. Defaults to ``now`` if not set.

            ``updated`` (datetime): A specific datetime object to be set
            as updated timestamp. Defaults to ``now`` if not set.

            ``old_data`` (dict): The data dictionary containing the old data of
            the questionnaire.

            ``languages`` (list): An optional list of languages in which a newly
            created questionnaire is available. Should only be used when
            importing data.

        Returns:
            ``questionnaire.models.Questionnaire``. The created
            Questionnaire.

        Raises:
            ``ValidationError``
        """
        if updated is None:
            updated = timezone.now()
        if created is None:
            created = timezone.now()

        if previous_version:
            created = previous_version.created
            roles, permissions = previous_version.get_roles_permissions(user)
            code = previous_version.code
            version = previous_version.version
            uuid = previous_version.uuid

            # Unblock all other questionnaires with same code
            Lock.objects.filter(questionnaire_code=code).update(
                is_finished=True)

            if 'edit_questionnaire' not in permissions:
                raise ValidationError(
                    'You do not have permission to edit the questionnaire.')

            if previous_version.status == settings.QUESTIONNAIRE_PUBLIC:
                # Edit of a public questionnaire: Create new version
                # with the same code
                version_count = Questionnaire.objects.filter(code=code).count()
                version = version_count + 1
                languages = previous_version.translations

            elif previous_version.status == settings.QUESTIONNAIRE_DRAFT:
                # Edit of a draft questionnaire: Only update the data
                previous_version.update_data(data, updated, configuration_code)
                previous_version.add_translation_language(original=False)
                return previous_version

            elif previous_version.status == settings.QUESTIONNAIRE_SUBMITTED:
                # Edit of a submitted questionnaire: Only update the data
                # User must be reviewer!
                if 'review_questionnaire' not in permissions:
                    raise ValidationError(
                        'You do not have permission to edit the '
                        'questionnaire.')
                previous_version.update_data(data, updated, configuration_code)
                previous_version.add_translation_language(original=False)
                return previous_version

            elif previous_version.status == settings.QUESTIONNAIRE_REVIEWED:
                # Edit of a reviewed questionnaire: Only update the data
                # User must be publisher!
                if 'publish_questionnaire' not in permissions:
                    raise ValidationError(
                        'You do not have permission to edit the '
                        'questionnaire.')
                previous_version.update_data(data, updated, configuration_code)
                previous_version.add_translation_language(original=False)
                return previous_version

            else:
                raise ValidationError(
                    'The questionnaire cannot be updated because of its status'
                    ' "{}"'.format(previous_version.status))
        else:
            code = ''  # Will be generated later
            version = 1
            uuid = uuid4()
        if status not in [s[0] for s in STATUSES]:
            raise ValidationError('"{}" is not a valid status'.format(status))
        configuration = Configuration.latest_by_code(configuration_code)
        if configuration is None:
            raise ValidationError(
                'No active configuration found for code "{}"'.format(
                    configuration_code))
        questionnaire = Questionnaire.objects.create(
            data=data,
            uuid=uuid,
            code=code,
            version=version,
            status=status,
            created=created,
            updated=updated,
            configuration=configuration)

        if not previous_version:
            # Generate and set a new code for the questionnaire
            from configuration.utils import create_new_code
            code = create_new_code(questionnaire, configuration_code)
            questionnaire.code = code
            if questionnaire.status != settings.QUESTIONNAIRE_PUBLIC:
                questionnaire.save()

        create_questionnaire.send(sender=settings.NOTIFICATIONS_CREATE,
                                  questionnaire=questionnaire,
                                  user=user)

        questionnaire.update_geometry(configuration_code=configuration_code)

        if not languages:
            questionnaire.add_translation_language(original=True)
        else:
            for i, language in enumerate(languages):
                original = i == 0
                questionnaire.add_translation_language(original=original,
                                                       language=language)

        if previous_version:
            # Copy all the functional user roles from the old version
            user_roles = [
                settings.QUESTIONNAIRE_COMPILER, settings.QUESTIONNAIRE_EDITOR,
                settings.QUESTIONNAIRE_REVIEWER,
                settings.QUESTIONNAIRE_PUBLISHER
            ]
            for role in user_roles:
                for old_user in previous_version.get_users_by_role(role):
                    questionnaire.add_user(old_user, role)

            # Also copy any flags
            questionnaire.flags.add(*previous_version.flags.all())
        else:
            questionnaire.add_user(user, settings.QUESTIONNAIRE_COMPILER)
        questionnaire.update_users_from_data(configuration_code)

        return questionnaire

    def add_translation_language(self, original=False, language=None):
        """
        Add a language as a translation of the questionnaire. Add it only once.

        Args:
            original: bool. Whether the language is the original language or not

            language: string. Manually set the language of the translation. If
            not provided, it is looked up using get_language().

        Returns:

        """
        if language is None:
            language = get_language()
        if language not in self.translations:
            QuestionnaireTranslation.objects.create(questionnaire=self,
                                                    language=language,
                                                    original_language=original)
            # Delete cached translation property
            try:
                delattr(self, 'translations')
            except AttributeError:
                pass

    def get_id(self):
        return self.id

    def get_roles_permissions(self, current_user):
        """
        Return the roles and permissions of a given user for the current
        questionnaire.

        The following rules apply:
            * Compilers and editors can edit questionnaires if the status is
              either draft or public.
            * Compilers can submit and assign questionnaires if the status is
              draft.
            * Reviewers can edit and review questionnaires if the status is
              submitted.
            * Publishers can edit and review questionnaires if the status is
              reviewed.
            * Secretariat members can assign questionnaires if the status is
              submitted (assign reviewers) or published (assign publishers).

        Permissions to be returned are:
            * ``edit_questionnaire``
            * ``submit_questionnaire``
            * ``review_questionnaire``
            * ``publish_questionnaire``
            * ``assign_questionnaire``

        Args:
            ``current_user`` (User): The user.

        Returns:
            ``namedtuple``. A named tuple with
                - roles: A list of roles of the user for this questionnaire
                  object as tuple (role_code, role_name)
                - permissions. A list of permissions of the user for this
                  questionnaire object.
        """
        roles = []
        permissions = []

        RolesPermissions = collections.namedtuple('RolesPermissions',
                                                  ['roles', 'permissions'])

        if not isinstance(current_user, get_user_model()):
            return RolesPermissions(roles=roles, permissions=permissions)

        # Permissions based on role of current user in questionnaire
        permission_groups = {
            settings.QUESTIONNAIRE_COMPILER: [{
                'status':
                [settings.QUESTIONNAIRE_DRAFT, settings.QUESTIONNAIRE_PUBLIC],
                'permissions': ['edit_questionnaire', 'delete_questionnaire']
            }, {
                'status': [settings.QUESTIONNAIRE_DRAFT],
                'permissions':
                ['submit_questionnaire', 'assign_questionnaire']
            }],
            settings.QUESTIONNAIRE_EDITOR: [{
                'status':
                [settings.QUESTIONNAIRE_DRAFT, settings.QUESTIONNAIRE_PUBLIC],
                'permissions': ['edit_questionnaire']
            }],
            settings.QUESTIONNAIRE_REVIEWER: [{
                'status': [settings.QUESTIONNAIRE_SUBMITTED],
                'permissions': ['edit_questionnaire', 'review_questionnaire']
            }],
            settings.QUESTIONNAIRE_PUBLISHER: [{
                'status': [settings.QUESTIONNAIRE_REVIEWED],
                'permissions': ['edit_questionnaire', 'publish_questionnaire']
            }]
        }
        for member_role, user in self.get_users(user=current_user):
            permission_group = permission_groups.get(member_role)
            if not permission_group:
                continue

            add_role = False
            for access_level in permission_group:
                if self.status in access_level['status']:
                    permissions.extend(access_level['permissions'])
                    add_role = True

            if add_role is True:
                roles.append(
                    (member_role, dict(QUESTIONNAIRE_ROLES).get(member_role)))

        # General permissions of user
        user_permissions = current_user.get_all_permissions()
        if ('questionnaire.review_questionnaire' in user_permissions
                and self.status in [settings.QUESTIONNAIRE_SUBMITTED]):
            permissions.extend(['review_questionnaire', 'edit_questionnaire'])
            role = settings.QUESTIONNAIRE_REVIEWER
            roles.append((role, dict(QUESTIONNAIRE_ROLES).get(role)))
        if ('questionnaire.publish_questionnaire' in user_permissions
                and self.status in [settings.QUESTIONNAIRE_REVIEWED]):
            permissions.extend(['publish_questionnaire', 'edit_questionnaire'])
            role = settings.QUESTIONNAIRE_PUBLISHER
            roles.append((role, dict(QUESTIONNAIRE_ROLES).get(role)))
        if 'questionnaire.assign_questionnaire' in user_permissions:
            # Piggybacking on the "assign_questionnaire" permission to identify
            # WOCAT secretariat users as this permission is only available for
            # this role.
            permissions.extend([
                'edit_questionnaire', 'delete_questionnaire',
                'submit_questionnaire', 'review_questionnaire',
                'publish_questionnaire', 'change_compiler'
            ])
            if self.status in [
                    settings.QUESTIONNAIRE_SUBMITTED,
                    settings.QUESTIONNAIRE_REVIEWED
            ]:
                permissions.extend(['assign_questionnaire'])
            role = settings.QUESTIONNAIRE_SECRETARIAT
            roles.append((role, dict(QUESTIONNAIRE_ROLES).get(role)))

        # UNCCD Flagging
        questionnaire_country = self.get_question_data('qg_location',
                                                       'country')
        if len(questionnaire_country) == 1 \
                and self.status in [settings.QUESTIONNAIRE_PUBLIC]:
            for country in current_user.get_unccd_countries():
                if country.keyword == questionnaire_country[0]:

                    role = settings.ACCOUNTS_UNCCD_ROLE_NAME
                    roles.append((role, dict(QUESTIONNAIRE_ROLES).get(role)))

                    try:
                        self.flags.get(flag=settings.QUESTIONNAIRE_FLAG_UNCCD)
                        # Flag already exists
                        permissions.extend(['unflag_unccd_questionnaire'])
                    except Flag.DoesNotExist:
                        # No flag yet
                        permissions.extend(['flag_unccd_questionnaire'])

        # Remove duplicates
        permissions = list(set(permissions))
        roles = list(set(roles))

        # Do the translation of the role names
        translated_roles = []
        for role_keyword, role_name in roles:
            translated_roles.append((role_keyword, _(role_name)))

        return RolesPermissions(roles=translated_roles,
                                permissions=permissions)

    def get_question_data(self, qg_keyword, q_keyword):
        """
        Get the raw question data by keyword. This does not translate the values
        or return the labelled choices. For this, use
        QuestionnaireConfiguration.

        Args:
            qg_keyword: (str): The keyword of the questiongroup.
            q_keyword: (str): The keyword of the question.

        Returns:
            (list). A list of (raw) values.
        """
        data = []
        if self.data:
            for q_data in self.data.get(qg_keyword, []):
                for key, value in q_data.items():
                    if key == q_keyword:
                        data.append(value)
        return data

    @property
    def configuration_object(self):
        return get_configuration(code=self.configuration.code,
                                 edition=self.configuration.edition)

    def get_name(self, locale='') -> str:
        """
        Return the name of the questionnaire, based on the configuration.
        """

        names = self.configuration_object.get_questionnaire_name(
            self.data) or {}
        name = names.get(locale or get_language())
        if name:
            # omit additional query
            return name

        original_lang = self.questionnairetranslation_set.filter(
            original_language=True).first()
        if original_lang and names.get(original_lang.language):
            return names[original_lang.language]

        return ''

    def get_countries(self) -> []:
        """
        Return list of translated country names.
        """
        codes = self.get_question_data('qg_location', 'country')
        if codes:
            values = Value.objects.filter(keyword__in=codes)
            if values.exists():
                return [
                    value.get_translation(keyword='label') for value in values
                ]
        return []

    def get_history_versions(self, user: User or None) -> list:
        item = collections.namedtuple('Item', 'id, name, url, updated, status')

        # Function get_query_status_filter requires a request object, which we
        # will fake here.
        pseudo_request = collections.namedtuple('MockRequest', 'user')

        from questionnaire.utils import get_query_status_filter
        status_filter = get_query_status_filter(pseudo_request(user))
        # Inactive versions (previously active) are always visible
        status_filter |= Q(status=settings.QUESTIONNAIRE_INACTIVE)

        history = Questionnaire.with_status.not_deleted().filter(
            status_filter,
            code=self.code,
        ).order_by('created')
        return [
            item(questionnaire.id, questionnaire.get_name(),
                 questionnaire.get_perma_url(), questionnaire.updated,
                 questionnaire.status_property) for questionnaire in history
        ]

    def update_geometry(self, configuration_code, force_update=False):
        """
        Update the geometry of a questionnaire based on the GeoJSON found in the
        data json.

        Args:
            configuration_code:

        Returns:
            -
        """
        def get_geometry_from_string(geometry_string):
            """
            Extract and convert the geometry from a (GeoJSON) string.

            Args:
                geometry_string: The geometry as (GeoJSON) string.

            Returns:
                A GeometryCollection or None.
            """

            if geometry_string is None:
                return None

            try:
                geometry_json = json.loads(geometry_string)
            except json.decoder.JSONDecodeError:
                return None
            geoms = []
            for feature in geometry_json.get('features', []):
                try:
                    feature_geom = GEOSGeometry(
                        json.dumps(feature.get('geometry')))
                except ValueError:
                    continue
                except GDALException:
                    continue
                geoms.append(feature_geom)

            if geoms:
                return GeometryCollection(tuple(geoms))

            else:
                return None

        geometry_value = self.configuration_object.get_questionnaire_geometry(
            self.data)
        geometry = get_geometry_from_string(geometry_value)

        geometry_changed = self.geom != geometry

        try:
            self.geom = geometry
            self.save()
        except ValidationError:
            return

        if self.geom is None or (not force_update and not geometry_changed):
            # If there is no geometry or if it did not change, there is no need
            # to create the static map image (again)
            return

        # Create static map
        width = 1000
        height = 800
        marker_diameter = 24
        marker_color = '#0036FF'

        m = StaticMap(width, height)

        for point in iter(self.geom):
            m.add_marker(
                CircleMarker((point.x, point.y), marker_color,
                             marker_diameter))

        bbox = None
        questionnaire_country = self.get_question_data('qg_location',
                                                       'country')

        if len(questionnaire_country) == 1:
            country_iso3 = questionnaire_country[0].replace('country_', '')
            country_iso2 = settings.CONFIGURATION_COUNTRY_ISO_MAPPING.get(
                country_iso3)

            if country_iso2:
                r = requests.get(
                    'http://api.geonames.org/countryInfoJSON?username=wocat_webdev&country={}'
                    .format(country_iso2))
                geonames_country = r.json().get('geonames')

                if len(geonames_country) == 1:
                    ctry = geonames_country[0]
                    poly_coords = [[ctry.get('west'),
                                    ctry.get('north')],
                                   [ctry.get('west'),
                                    ctry.get('south')],
                                   [ctry.get('east'),
                                    ctry.get('south')],
                                   [ctry.get('east'),
                                    ctry.get('north')],
                                   [ctry.get('west'),
                                    ctry.get('north')]]

                    bbox = Polygon(poly_coords, None, None)

        if bbox:
            m.add_polygon(bbox)
            image = m.render()
        else:
            # No bbox found, guess zoom level
            image = m.render(zoom=6)

        map_folder = get_upload_folder_path(str(self.uuid), subfolder='maps')
        if not os.path.exists(map_folder):
            os.makedirs(map_folder)

        filename = '{}_{}.jpg'.format(self.uuid, self.version)
        image.save(os.path.join(map_folder, filename))

    def add_flag(self, flag):
        """
        Add a Flag object to the questionnaire. Add it only once.

        Args:
            flag: (Flag): The flag to be added.
        """
        if flag not in self.flags.all():
            self.flags.add(flag)

    def get_user(self, user, role):
        """
        Get and return a user of the Questionnaire by role.

        Args:
            user: (User) The user.
            role: (str): The role of the user.

        Returns:
            User or None.
        """
        membership = self.questionnairemembership_set.filter(
            user=user, role=role).first()
        if membership:
            return membership.user
        return None

    def get_users(self, **kwargs):
        """
        Helper function to return the users of a questionnaire along
        with their role in this membership.

        Returns:
            ``list``. A list of tuples where each entry contains the
            following elements:

            - [0]: ``string``. The role of the membership.

            - [1]: ``accounts.models.User``. The user object.
        """
        users = []
        for membership in self.questionnairemembership_set.filter(**kwargs):
            users.append((membership.role, membership.user))
        return users

    def get_users_by_role(self, role):
        """
        Return all users of a questionnaire based on their role in the
        membership.

        Args:
            ``role`` (str): The role of the membership used as a filter.

        Returns:
            ``list``. A list of users.
        """
        users = []
        for user_role, user in self.get_users():
            if user_role == role:
                users.append(user)
        return users

    def get_users_by_roles(self, roles: list) -> list:
        for role, user in self.get_users():
            if role in roles:
                yield user

    @staticmethod
    def get_wocat_mailbox_user():
        """
        Return the WOCAT Mailbox User with the ID set in the settings.
        """
        try:
            return User.objects.get(pk=settings.WOCAT_MAILBOX_USER_ID)
        except User.DoesNotExist:
            return None

    def get_users_for_next_publish_step(self):
        if self.status in settings.QUESTIONNAIRE_WORKFLOW_STEPS:
            role = settings.QUESTIONNAIRE_PUBLICATION_ROLES[self.status]
            return getattr(self, 'get_{role}s'.format(role=role))()
        return []

    def get_reviewers(self):
        return get_user_model().objects.filter(
            groups__permissions__codename='review_questionnaire')

    def get_publishers(self):
        return get_user_model().objects.filter(
            groups__permissions__codename='publish_questionnaire')

    def add_user(self, user, role):
        """
        Add a user. Users are only added if the membership does not yet exist.

        Args:
            ``user`` (User): The user.

            ``role`` (str): The role of the user.
        """
        if self.get_user(user, role) is None:
            QuestionnaireMembership.objects.create(questionnaire=self,
                                                   user=user,
                                                   role=role)

    def remove_user(self, user, role):
        """
        Remove a user.

        Args:
            ``user`` (User): The user.

            ``role`` (str): The role of the user.
        """
        user = self.get_user(user, role)
        QuestionnaireMembership.objects.filter(questionnaire=self,
                                               user=user,
                                               role=role).delete()

    def update_users_from_data(self, configuration_code):
        """
        Based on the data dictionary, update the user links in the
        database. This usually happens after the form of the
        questionnaire was submitted.

        Args:
            ``configuration_code`` (str): The code of the configuration
              of the questionnaire which triggered the update.

            ``compiler`` (accounts.models.User): A user figuring as the
            compiler of the questionnaire.
        """

        user_fields = self.configuration_object.get_user_fields()

        # Collect the users appearing in the data dictionary.
        submitted_users = []
        for user_questiongroup in user_fields:
            for user_data in self.data.get(user_questiongroup[0], []):
                user_id = user_data.get(user_questiongroup[1])
                if not bool(user_id):
                    continue
                submitted_users.append((user_questiongroup[3], user_id))

        # Get the users which were attached before modifying the
        # questionnaire. Collect only those which can be changed through
        # the data dictionary (no functional user roles)
        previous_users = []
        for user_role, user in self.get_users():
            if user_role not in [
                    settings.QUESTIONNAIRE_COMPILER,
                    settings.QUESTIONNAIRE_EDITOR,
                    settings.QUESTIONNAIRE_REVIEWER,
                    settings.QUESTIONNAIRE_PUBLISHER
            ]:
                previous_users.append((user_role, user))

        # Check which users are new (in submitted_users but not in
        # previous_users) and add them to the questionnaire.
        previous_users_found = []
        for submitted_user in submitted_users:
            user_found = False
            for previous_user in previous_users:
                if submitted_user[0] != previous_user[0]:
                    continue
                if str(submitted_user[1]) != str(previous_user[1].id):
                    continue

                user_found = True
                previous_users_found.append(previous_user)

            if user_found is False:
                user = User.objects.get(pk=submitted_user[1])
                self.add_user(user, submitted_user[0])

        # Check for users which were removed (in previous_users but not
        # found when looking through submitted_users) and remove them
        # from the questionnaire
        for removed_user in list(
                set(previous_users) - set(previous_users_found)):
            self.remove_user(removed_user[1], removed_user[0])

    def get_metadata(self):
        """
        Return some metadata about the Questionnaire.

        Returns:
            ``dict``. A dict containing the following metadata:

            * ``created`` (timestamp)

            * ``updated`` (timestamp)

            * ``compilers`` (list): A list of dictionaries containing
              information about the compilers. Each entry contains the
              following data:

              * ``id``

              * ``name``

            * ``editors`` (list): A list of dictionaries containing information
            about the editors. The format is the same as for ``compilers``

            * ``code`` (string)

            * ``configurations`` (list)

            * ``translations`` (list)
        """
        return dict(self._get_metadata())

    def _get_metadata(self):
        # Access the property first, then the model field.
        for key in settings.QUESTIONNAIRE_METADATA_KEYS:
            yield key, getattr(self, '{}_property'.format(key),
                               getattr(self, key))

    def add_link(self, questionnaire, symm=True):
        """
        Add a link to another Questionnaire. This actually creates two
        entries in the link table to make the reference symmetrical.

        https://charlesleifer.com/blog/self-referencing-many-many-through/

        Args:
            ``questionnaire`` (questionnaire.models.Questionnaire): The
            questionnaire to link to.

        Kwargs:
            ``symm`` (bool): Whether or not to add the symmetrical link
            (to avoid recursion).

        Returns:
            ``questionnaire.models.Questionnaire``. The updated
            questionnaire.
        """
        link, created = QuestionnaireLink.objects.get_or_create(
            from_questionnaire=self,
            from_status=self.status,
            to_questionnaire=questionnaire,
            to_status=questionnaire.status)
        if symm:
            # avoid recursion by passing `symm=False`
            questionnaire.add_link(self, symm=False)
        return questionnaire

    def remove_link(self, questionnaire, symm=True):
        """
        Remove a link to another Questionnaire. This actually removes
        both links (also the symmetrical one).

        https://charlesleifer.com/blog/self-referencing-many-many-through/

        Args:
            ``questionnaire`` (questionnaire.models.Questionnaire): The
            questionnaire to remove.

        Kwargs:
            ``symm`` (bool): Whether or not to remove the symmetrical
            link (to avoid recursion).
        """
        QuestionnaireLink.objects.filter(
            from_questionnaire=self, to_questionnaire=questionnaire).delete()
        if symm:
            # avoid recursion by passing `symm=False`
            questionnaire.remove_link(self, symm=False)

    def __str__(self):
        return json.dumps(self.data)

    @classmethod
    def has_questionnaires_for_code(cls, code: str) -> bool:
        return cls.objects.filter(code=code).exists()

    @classmethod
    def lock_questionnaire(cls, code: str, user: settings.AUTH_USER_MODEL):
        """
        If the questionnaire is not locked, or locked by given user: lock the
        questionnaire for this user - else raise an error.

        """
        qs_locks = Lock.with_status.is_blocked(code, for_user=user)

        if qs_locks.exists():
            raise QuestionnaireLockedException(qs_locks.first().user)
        else:
            Lock.objects.create(questionnaire_code=code, user=user)

    def can_edit(self, user: settings.AUTH_USER_MODEL) -> bool:
        has_questionnaires = self.has_questionnaires_for_code(self.code)
        qs_locks = Lock.with_status.is_blocked(self.code, for_user=user)
        return has_questionnaires and not qs_locks.exists()

    def unlock_questionnaire(self):
        Lock.objects.filter(questionnaire_code=self.code).update(
            is_finished=True)

    def get_blocked_message(self, user: settings.AUTH_USER_MODEL) -> tuple:
        """
        Get status and message for blocked status (blocked or can be edited).
        """
        locks = Lock.with_status.is_blocked(code=self.code, for_user=user)

        if not locks.exists():
            return SUCCESS, _(u"This questionnaire can be edited.")
        else:
            return WARNING, _(u"This questionnaire is "
                              u"locked for editing by {user}.".format(
                                  user=locks.first().user.get_display_name()))

    # Properties for the get_metadata function.
    def _get_role_list(self, role):
        members = []
        for member in self.members.filter(questionnairemembership__role=role):
            members.append({
                'id': member.id,
                'name': str(member),
            })
        return members

    @cached_property
    def editors(self):
        return self._get_role_list(settings.QUESTIONNAIRE_EDITOR)

    @cached_property
    def compilers(self):
        return self._get_role_list(settings.QUESTIONNAIRE_COMPILER)

    @cached_property
    def reviewers(self):
        return self._get_role_list(settings.QUESTIONNAIRE_REVIEWER)

    @cached_property
    def status_property(self):
        status = next((x for x in STATUSES if x[0] == self.status), (None, ''))
        status_code = next((x for x in STATUSES_CODES if x[0] == self.status),
                           (None, ''))
        return status_code[1], status[1]

    @cached_property
    def translations(self):
        return list(
            self.questionnairetranslation_set.values_list('language',
                                                          flat=True))

    @cached_property
    def original_locale(self):
        translation = self.questionnairetranslation_set.filter(
            original_language=True).first()
        if translation:
            return translation.language
        else:
            return None

    @cached_property
    def links_property(self):
        """
        Collect all info about linked questionnaire and structure it according to language.
        This follows a often used pattern of questionnaire data.

        Returns: list

        """
        links = []
        current_language = get_language()

        for link in self.links.filter(status=settings.QUESTIONNAIRE_PUBLIC):

            link_configuration = get_configuration(
                code=link.configuration.code,
                edition=link.configuration.edition)
            name_data = link_configuration.get_questionnaire_name(link.data)

            try:
                original_language = link.questionnairetranslation_set.first(
                ).language
            except AttributeError:
                original_language = settings.LANGUAGES[0][0]  # 'en'

            names = {}
            urls = {}
            for code, language in settings.LANGUAGES:
                activate(code)
                names[code] = name_data.get(code,
                                            name_data.get(original_language))
                urls[code] = link.get_absolute_url()

                if code == original_language:
                    names['default'] = names[code]
                    urls['default'] = urls[code]

            links.append({
                'code': link.code,
                'configuration': link_configuration.keyword,
                'name': names,
                'url': urls,
            })

        activate(current_language)
        return links

    @cached_property
    def flags_property(self):
        flags = []
        for flag in self.flags.all():
            flags.append({
                'flag': flag.flag,
                'name': flag.get_flag_display(),
                'helptext': flag.get_helptext(),
            })
        return flags

    @cached_property
    def has_release(self):
        """
        Check if any version of this questionnaire was published.

        Returns: boolean

        """
        return self.status == settings.QUESTIONNAIRE_PUBLIC or self._meta.model.with_status.not_deleted(
        ).filter(code=self.code,
                 status=settings.QUESTIONNAIRE_PUBLIC).exists()
コード例 #14
0
class Inmueble(models.Model):
    creador = models.ForeignKey('auth.User')

    email = models.EmailField(null=True, blank=False)
    info = models.TextField(null=True, blank=True)
    fecha_creacion = models.DateTimeField(auto_now_add=True)
    fecha_publicacion = models.DateTimeField(blank=True, null=True)

    titulo = models.CharField(max_length=60, blank=False)
    descripcion = models.CharField(max_length=20, null=True, blank=True)

    direccion = models.CharField(max_length=150, blank=False)
    calle = models.CharField(max_length=150, blank=False)
    altura = models.CharField(max_length=6, blank=False)
    pais = models.ForeignKey(Pais, on_delete=models.CASCADE)
    ciudad = models.ForeignKey(Ciudad, on_delete=models.CASCADE)
    barrio = models.ForeignKey(Barrio, on_delete=models.CASCADE)

    metros_terreno = models.CharField(max_length=5, null=True, blank=True)
    metros_cubiertos = models.CharField(max_length=5, null=True, blank=True)
    antiguedad = models.CharField(max_length=2, blank=False)

    banos = models.CharField(max_length=5, null=True, blank=True)
    habitaciones = models.CharField(max_length=5, null=True, blank=True)
    ambientes = models.CharField(max_length=2, blank=False)
    plantas = models.CharField(max_length=2, blank=False)
    pileta = models.CharField(max_length=2, blank=False)
    cochera = models.CharField(max_length=2, blank=False)
    patio = models.CharField(max_length=2, blank=False)

    precio = models.CharField(max_length=10, blank=False)
    location = models.PointField(u"longitude/latitude",
                                 geography=True,
                                 blank=True,
                                 null=True)
    gis = models.GeoManager()
    objects = models.Manager()
    slug = AutoSlugField(populate_from='titulo', max_length=255)
    uuid = ext_fields.UUIDField(auto=True)

    def publish(self):
        self.fecha_publicacion = timezone.now()
        self.save()

    def __str__(self):
        return self.titulo

    def save(self, **kwargs):
        if not self.location:
            address = u'%s %s' % (self.ciudad.nombre, self.direccion)
            address = address.encode('utf-8')
            geocoder = GoogleV3()
            try:
                _, latlon = geocoder.geocode(address)
            except (URLError, GeocoderQueryError, ValueError):
                pass
            else:
                point = "POINT(%s %s)" % (latlon[1], latlon[0])
                self.location = geos.fromstr(point)
        super(Inmueble, self).save()

    class Meta:
        verbose_name_plural = "Inmuebles"
コード例 #15
0
class Layer(models.Model):
    class Meta(object):
        verbose_name = "Couche de données"
        verbose_name_plural = "Couches de données"

    # Managers
    # ========

    objects = models.Manager()
    vector = VectorLayerManager()
    raster = RasterLayerManager()

    # Champs atributaires
    # ===================

    name = models.SlugField(
        verbose_name="Nom de la couche",
        max_length=100,
        editable=False,
        primary_key=True,
    )

    resource = models.ForeignKey(
        to='Resource',
        verbose_name="Ressource",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
    )

    TYPE_CHOICES = (
        ('raster', 'raster'),
        ('vector', 'vector'),
    )

    type = models.CharField(
        verbose_name="Type",
        max_length=6,
        null=True,
        blank=True,
        choices=TYPE_CHOICES,
    )

    bbox = models.PolygonField(
        verbose_name="Rectangle englobant",
        null=True,
        blank=True,
        srid=4171,
    )

    def __str__(self):
        return self.resource.__str__()

    # Propriétés
    # ==========

    @property
    def layername(self):
        return self.mra_info['name']

    @property
    def geometry_type(self):
        return {
            'POLYGON': 'Polygone',
            'POINT': 'Point',
            'LINESTRING': 'Ligne',
            'RASTER': 'Raster',
        }.get(self.mra_info['type'], None)

    @property
    def is_enabled(self):
        return self.mra_info['enabled']

    @property
    def title(self):
        return self.mra_info['title']

    @property
    def abstract(self):
        return self.mra_info['abstract']

    @property
    def styles(self):
        return self.mra_info['styles']['styles']

    @property
    def id(self):
        return self.name

    @property
    def filename(self):
        if self.type == 'vector':
            # Peut-être quelque chose à retourner ici ?
            return None
        if self.type == 'raster':
            x = str(self.resource.ckan_id)
            _filename = os.path.join(CKAN_STORAGE_PATH, x[:3], x[3:6],
                                     self.resource.filename.split('/')[-1])
            if os.path.isfile(_filename):
                filename = os.path.join(MAPSERV_STORAGE_PATH, x[:3], x[3:6],
                                        self.resource.filename.split('/')[-1])
            else:
                filename = os.path.join(MAPSERV_STORAGE_PATH, x[:3], x[3:6],
                                        x[6:])
            return filename

    # Méthodes héritées
    # =================

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        organisation = self.resource.dataset.organisation
        ws_name = organisation.slug

        try:
            l = MRAHandler.get_layer(self.name)
        except MraBaseError:
            return

        # Récupération des informations de couche vecteur
        # ===============================================

        if self.type == 'vector':
            try:
                ft = MRAHandler.get_featuretype(ws_name, 'public', self.name)
            except MraBaseError:
                return
            if not l or not ft:
                return

            ll = ft['featureType']['latLonBoundingBox']
            bbox = [[ll['miny'], ll['minx']], [ll['maxy'], ll['maxx']]]
            attributes = [
                item['name'] for item in ft['featureType']['attributes']
            ]
            default_style_name = l['defaultStyle']['name']
            styles = [{
                'name': 'default',
                'text': 'Style par défaut',
                'url': l['defaultStyle']['href'].replace('json', 'sld'),
                'sld': MRAHandler.get_style(l['defaultStyle']['name'])
            }]
            if l.get('styles'):
                for style in l.get('styles')['style']:
                    styles.append({
                        'name': style['name'],
                        'text': style['name'],
                        'url': style['href'].replace('json', 'sld'),
                        'sld': MRAHandler.get_style(style['name'])
                    })

        # Récupération des informations de couche raster
        # ==============================================

        elif self.type == 'raster':
            try:
                c = MRAHandler.get_coverage(ws_name, self.name, self.name)
            except MraBaseError:
                return
            if not l or not c:
                return

            ll = c['coverage']['latLonBoundingBox']
            bbox = [[ll['miny'], ll['minx']], [ll['maxy'], ll['maxx']]]
            attributes = []
            default_style_name = None
            styles = []

        # Puis..
        self.mra_info = {
            'name': l['name'],
            'title': l['title'],
            'type': l['type'],
            'enabled': l['enabled'],
            'abstract': l['abstract'],
            'bbox': bbox,
            'attributes': attributes,
            'styles': {
                'default': default_style_name,
                'styles': styles
            }
        }

    def save(self, *args, synchronize=False, **kwargs):
        # Synchronisation avec le service OGC en fonction du type de données
        if self.type == 'vector':
            self.save_vector_layer()
        elif self.type == 'raster':
            self.save_raster_layer()

        # Puis sauvegarde
        super().save(*args, **kwargs)
        self.handle_enable_ows_status()
        self.handle_layergroup()

        if synchronize:
            self.synchronize()

    def delete(self, *args, current_user=None, **kwargs):
        with_user = current_user

        # On supprime la ressource CKAN
        if with_user:
            username = with_user.username
            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan_user:
                ckan_user.delete_resource(self.name)
        else:
            CkanHandler.delete_resource(self.name)

        # On supprime les ressources MRA
        try:
            MRAHandler.del_layer(self.name)
            ws_name = self.resource.dataset.organisation.slug
            if self.type == 'vector':
                MRAHandler.del_featuretype(ws_name, 'public', self.name)
            if self.type == 'raster':
                MRAHandler.del_coverage(ws_name, self.name, self.name)
                # MRAHandler.del_coveragestore(ws_name, self.name)
        except Exception as e:
            logger.error(e)
            pass

        # On supprime la table de données PostGIS
        try:
            drop_table(self.name)
        except Exception as e:
            logger.error(e)
            pass

        # Puis on supprime l'instance
        super().delete(*args, **kwargs)

    # Autres méthodes
    # ===============

    def save_raster_layer(self, *args, **kwargs):
        """Synchronizer la couche de données matricielle avec le service OGC via MRA."""
        organisation = self.resource.dataset.organisation
        ws_name = organisation.slug
        cs_name = self.name

        if self.pk:
            try:
                Layer.objects.get(pk=self.pk)
            except Layer.DoesNotExist:
                pass
            else:
                # On vérifie si l'organisation du jeu de données a changée,
                # auquel cas il est nécessaire de supprimer les objets MRA
                # afin de les recréer dans le bon workspace (c-à-d Mapfile).
                previous_layer = MRAHandler.get_layer(self.name)
                regex = '/workspaces/(?P<ws_name>[a-z_\-]+)/coveragestores/'

                matched = re.search(regex, previous_layer['resource']['href'])
                if matched:
                    previous_ws_name = matched.group('ws_name')
                    if not ws_name == previous_ws_name:
                        MRAHandler.del_layer(self.name)
                        MRAHandler.del_coverage(previous_ws_name, cs_name,
                                                self.name)

        MRAHandler.get_or_create_workspace(organisation)
        MRAHandler.get_or_create_coveragestore(ws_name,
                                               cs_name,
                                               filename=self.filename)
        MRAHandler.get_or_create_coverage(ws_name,
                                          cs_name,
                                          self.name,
                                          enabled=True,
                                          title=self.resource.title,
                                          abstract=self.resource.description)

    def save_vector_layer(self, *args, **kwargs):
        """Synchronizer la couche de données vectorielle avec le service OGC via MRA."""
        organisation = self.resource.dataset.organisation
        ws_name = organisation.slug
        ds_name = 'public'

        if self.pk:
            try:
                Layer.objects.get(pk=self.pk)
            except Layer.DoesNotExist:
                pass
            else:
                # On vérifie si l'organisation du jeu de données a changée,
                # auquel cas il est nécessaire de supprimer les objets MRA
                # afin de les recréer dans le bon workspace (c-à-d Mapfile).
                previous_layer = MRAHandler.get_layer(self.name)
                regex = '/workspaces/(?P<ws_name>[a-z_\-]+)/datastores/'

                matched = re.search(regex, previous_layer['resource']['href'])
                if matched:
                    previous_ws_name = matched.group('ws_name')
                    if not ws_name == previous_ws_name:
                        MRAHandler.del_layer(self.name)
                        MRAHandler.del_featuretype(previous_ws_name, ds_name,
                                                   self.name)

        MRAHandler.get_or_create_workspace(organisation)
        MRAHandler.get_or_create_datastore(ws_name, ds_name)
        MRAHandler.get_or_create_featuretype(
            ws_name,
            ds_name,
            self.name,
            enabled=True,
            title=self.resource.title,
            abstract=self.resource.description)

    def synchronize(self, with_user=None):
        """Synchronizer le jeu de données avec l'instance de CKAN."""
        # 'with_user' n'est pas utiliser dans ce contexte

        # Définition des propriétés de la « ressource »
        # =============================================

        id = self.name
        name = 'Aperçu cartographique'.format(name=self.resource.title)
        description = self.resource.description
        organisation = self.resource.dataset.organisation

        base_url = OWS_URL_PATTERN.format(
            organisation=organisation.slug).replace('?', '')

        getlegendgraphic = (
            '{base_url}?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic'
            '&LAYER={layer}&FORMAT=image/png').format(base_url=base_url,
                                                      layer=id)

        api = {
            'url': base_url,
            'typename': id,
            'getlegendgraphic': getlegendgraphic
        }

        try:
            DEFAULT_SRID = settings.DEFAULTS_VALUES['SRID']
        except Exception:
            DEFAULT_SRID = 4326
        else:
            SupportedCrs = apps.get_model(app_label='idgo_admin',
                                          model_name='SupportedCrs')
            try:
                SupportedCrs.objects.get(auth_name='EPSG',
                                         auth_code=DEFAULT_SRID)
            except SupportedCrs.DoesNotExist:
                DEFAULT_SRID = 4326

        if self.type == 'vector':
            if self.resource.format_type.extension.lower() in ('json',
                                                               'geojson'):
                outputformat = 'shapezip'  # Il faudrait être sûr que le format existe avec le même nom !
            elif self.resource.format_type.extension.lower() in ('zip', 'tar'):
                outputformat = 'geojson'  # Il faudrait être sûr que le format existe avec le même nom !

            api[outputformat] = (
                '{base_url}?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature'
                '&TYPENAME={typename}&OUTPUTFORMAT={outputformat}&CRSNAME=EPSG:{srid}'
            ).format(base_url=base_url,
                     typename=id,
                     outputformat=outputformat,
                     srid=str(DEFAULT_SRID))

        CkanHandler.update_resource(str(self.resource.ckan_id),
                                    api=json.dumps(api))
        CkanHandler.push_resource_view(title=name,
                                       description=description,
                                       resource_id=str(self.resource.ckan_id),
                                       view_type='geo_view')

    def handle_enable_ows_status(self):
        """Gérer le statut d'activation de la couche de données SIG."""
        ws_name = self.resource.dataset.organisation.slug
        if self.resource.ogc_services:
            MRAHandler.enable_layer(ws_name, self.name)
            # TODO: Comment on gère les ressources CKAN service ???
        else:
            MRAHandler.disable_layer(ws_name, self.name)
            # TODO: Comment on gère les ressources CKAN service ???

    def handle_layergroup(self):
        dataset = self.resource.dataset
        layers = list(
            itertools.chain.from_iterable([
                qs for qs in [
                    resource.get_layers()
                    for resource in dataset.get_resources()
                ]
            ]))
        # TODO remplacer par `layers = dataset.get_layers()`

        MRAHandler.create_or_update_layergroup(
            dataset.organisation.slug, {
                'name': dataset.slug,
                'title': dataset.title,
                'abstract': dataset.description,
                'layers': [layer.name for layer in layers]
            })
コード例 #16
0
class Poi(models.Model):
    "Misto - bod v mape"
    author = models.ForeignKey(User,
                               verbose_name="Autor",
                               on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True,
                                      verbose_name="Posledni zmena")

    nazev = models.CharField(max_length=255,
                             verbose_name=u"název",
                             help_text=u"Přesný název místa.")

    # Relationships
    znacka = models.ForeignKey(
        Znacka,
        limit_choices_to={
            'status__show_TU': 'True',
            'vrstva__status__show_TU': 'True'
        },
        verbose_name=u"značka",
        help_text="Zde vyberte ikonu, která se zobrazí na mapě.",
        related_name="pois",
        on_delete=models.CASCADE)
    status = models.ForeignKey(
        Status,
        default=2,
        help_text="Status místa; určuje, kde všude se místo zobrazí.",
        on_delete=models.CASCADE)
    vlastnosti = models.ManyToManyField(
        'Vlastnost',
        blank=True,
        null=True,
        limit_choices_to={'status__show_TU': 'True'},
        help_text=
        "Určete, jaké má místo vlastnosti. Postupujte podle manuálu.<br/>")

    # "dulezitost" - modifikator minimalniho zoomu, ve kterem se misto zobrazuje.
    dulezitost = models.SmallIntegerField(
        default=0,
        verbose_name=u"důležitost",
        help_text=
        u"""Modifikátor minimalniho zoomu, ve kterém se místo zobrazuje (20+ bude vidět vždy).<br/>
                               Cíl je mít výběr základních objektů viditelných ve velkých měřítcích
                               a zabránit přetížení mapy značkami v přehledce.<br/>
                               Lze použít pro placenou reklamu! ("Váš podnik bude vidět hned po otevření mapy")"""
    )

    # Geographical intepretation
    geom = models.GeometryField(
        verbose_name=u"poloha",
        srid=4326,
        help_text=
        u"""Vložení bodu: Klikněte na tužku s plusem a umístěte bod na mapu."""
    )
    #Kreslení linie: Klikněte na ikonu linie a klikáním do mapy určete lomenou čáru. Kreslení ukončíte dvouklikem.<br/>
    #Kreslení oblasti: Klikněte na ikonu oblasti a klikáním do mapy definujte oblast. Kreslení ukončíte dvouklikem.<br/>
    #Úprava vložených objektů: Klikněte na první ikonu a potom klikněte na objekt v mapě. Tažením přesouváte body, body uprostřed úseků slouží k vkládání nových bodů do úseku.""")
    objects = models.Manager()

    # Own content (facultative)
    desc = models.TextField(
        null=True,
        blank=True,
        verbose_name=u"popis",
        help_text=u"Text, který se zobrazí na mapě po kliknutí na ikonu.")
    desc_extra = models.TextField(
        null=True,
        blank=True,
        verbose_name=u"podrobný popis",
        help_text="Text, který rozšiřuje informace výše.")
    url = models.URLField(null=True,
                          blank=True,
                          help_text=u"Odkaz na webovou stránku místa.")
    address = models.CharField(max_length=255,
                               null=True,
                               blank=True,
                               verbose_name=u"adresa",
                               help_text=u"Adresa místa (ulice, číslo domu)")
    remark = models.TextField(
        null=True,
        blank=True,
        verbose_name=u"interní poznámka",
        help_text=u"Interní informace o objektu, které se nebudou zobrazovat.")

    # navzdory nazvu jde o fotku v plnem rozliseni
    foto_thumb = models.ImageField(
        null=True,
        blank=True,
        upload_to='foto',
        storage=SlugifyFileSystemStorage(),
        verbose_name=u"fotka",
        help_text=u"Nahrajte fotku v plné velikosti.",
    )
    # zde se ulozi slugy vsech vlastnosti, aby se pri renederovani kml
    # nemusel delat db dotaz pro kazde Poi na jeho vlastnosti
    vlastnosti_cache = models.CharField(max_length=255, null=True, blank=True)

    sit_geom = models.GeometryField(verbose_name=u"SIT poloha",
                                    srid=4326,
                                    blank=True,
                                    null=True,
                                    help_text=u"Původní poloha podle SITu")

    viditelne = ViditelneManager()

    class Meta:
        permissions = [
            ("can_only_own_data_only", "Can only edit his own data"),
        ]
        verbose_name = "místo"
        verbose_name_plural = "místa"

    def __str__(self):
        return self.nazev

    def save_vlastnosti_cache(self):
        self.vlastnosti_cache = u",".join(
            [v.slug for v in self.vlastnosti.filter(status__show=True)])
        self.save()

    def get_absolute_url(self):
        return "/misto/%i/" % self.id

    def save(self, *args, **kwargs):
        self.created_at = datetime.datetime.now()
        super(Poi, self).save(*args, **kwargs)
コード例 #17
0
ファイル: models.py プロジェクト: conwayb/aol
class NHDLake(models.Model):
    # FYI: We add an hstore field (called changed_on) in a migration that tracks
    # when each field was updated (which is triggered with a trigger -- also
    # defined in a migration)

    reachcode = models.CharField(max_length=32, primary_key=True)
    title = models.CharField(max_length=255, blank=True)
    permanent_id = models.CharField(max_length=64)
    fdate = models.DateField()
    ftype = models.IntegerField()
    fcode = models.IntegerField()
    shape_length = models.FloatField()
    shape_area = models.FloatField()
    resolution = models.IntegerField()
    gnis_id = models.CharField(max_length=32)
    gnis_name = models.CharField(max_length=255)
    area_sq_km = models.FloatField()
    elevation = models.FloatField()
    parent = models.ForeignKey('self', null=True, db_column="parent", blank=True)
    aol_page = models.IntegerField(null=True, blank=True)
    body = models.TextField()

    fishing_zone = models.ForeignKey('FishingZone', null=True)
    huc6 = models.ForeignKey('HUC6', null=True, blank=True)
    county_set = models.ManyToManyField('County', through="LakeCounty")
    plants = models.ManyToManyField('Plant', through="LakePlant")

    # denormalized fields
    # unfortunately, for performance reasons, we need to cache whether a lake
    # has plant data, has mussels, was in the original AOL, has docs, has
    # photos etc
    has_mussels = models.BooleanField(default=False, blank=True)
    has_plants = models.BooleanField(default=False, blank=True)
    has_docs = models.BooleanField(default=False, blank=True)
    has_photos = models.BooleanField(default=False, blank=True)
    # some lakes in the NHD are not in oregon, so we cache this value so we
    # don't have to join on the lake_county table
    is_in_oregon = models.BooleanField(default=False, blank=True)

    objects = NHDLakeManager()
    unfiltered = models.Manager()

    class Meta:
        db_table = 'nhd'

    def __str__(self):
        return self.title or self.gnis_name or self.pk

    @classmethod
    def update_cached_fields(cls):
        """
        Important lakes are lakes with plant data, mussel data, photos docs, etc.
        We cache these booleans (has_mussels, has_plants, etc) on the model
        itself for performance reasons, so this class method needs to be called
        to refresh thos booleans.

        It also refreshes the is_in_oregon flag
        """
        cursor = connection.cursor()
        cursor.execute("""
            SELECT
                reachcode,
                MAX(has_plants) AS has_plants,
                MAX(has_docs) AS has_docs,
                MAX(has_photos) AS has_photos,
                MAX(has_aol_page) AS has_aol_page,
                MAX(has_mussels) AS has_mussels
            FROM (
                -- get all reachcodes for lakes with plants
                SELECT reachcode, 1 AS has_plants, 0 AS has_docs, 0 AS has_photos, 0 AS has_aol_page, 0 AS has_mussels FROM "lake_plant" GROUP BY reachcode HAVING COUNT(*) >= 1
                UNION
                -- get all reachcodes for lakes with documents
                SELECT reachcode, 0 AS has_plants, 1 AS has_docs, 0 AS has_photos, 0 AS has_aol_page, 0 AS has_mussels FROM "document" GROUP BY reachcode HAVING COUNT(*) >= 1
                UNION
                -- get all reachcodes for lakes with photos
                SELECT reachcode, 0 AS has_plants, 0 AS has_docs, 1 AS has_photos, 0 AS has_aol_page, 0 AS has_mussels FROM "photo" GROUP BY reachcode HAVING COUNT(*) >= 1
                UNION
                -- get all original AOL lakes
                SELECT reachcode, 0 AS has_plants, 0 AS has_docs, 0 AS has_photos, 1 AS has_aol_page, 0 AS has_mussels FROM "nhd" WHERE aol_page IS NOT NULL
                UNION
                SELECT DISTINCT reachcode, 0 AS has_plants, 0 AS has_docs, 0 AS has_photos, 0 AS has_aol_page, 1 AS has_mussels FROM mussels.observation INNER JOIN "lake_geom" ON (ST_BUFFER(ST_TRANSFORM(observation.the_geom, 3644), %s) && lake_geom.the_geom)
            ) k
            GROUP BY reachcode
        """, [DISTANCE_FROM_ITEM]) # noqa
        for row in dictfetchall(cursor):
            NHDLake.unfiltered.filter(reachcode=row['reachcode']).update(
                has_plants=row['has_plants'],
                has_docs=row['has_docs'],
                has_photos=row['has_photos'],
                has_mussels=row['has_mussels']
            )

        # now update the is_in_oregon flag
        cursor.execute("""
            WITH foo AS (SELECT COUNT(*) AS the_count, reachcode FROM lake_county GROUP BY reachcode)
            UPDATE nhd SET is_in_oregon = foo.the_count > 0 FROM foo WHERE foo.reachcode = nhd.reachcode
        """)

    @property
    def area(self):
        """Returns the number of acres this lake is"""
        if not hasattr(self, "_area"):
            cursor = connections['default'].cursor()
            # 43560 is the number of square feet in an arre
            cursor.execute("SELECT ST_AREA(the_geom)/43560 FROM lake_geom WHERE reachcode = %s", (self.reachcode,))
            self._area = cursor.fetchone()[0]
        return self._area

    @property
    def perimeter(self):
        """Returns the number of acres this lake is"""
        if not hasattr(self, "_perimeter"):
            cursor = connections['default'].cursor()
            # 5280 is the number of feet in a mile
            cursor.execute("SELECT ST_PERIMETER(the_geom)/5280 FROM lake_geom WHERE reachcode = %s", (self.reachcode,))
            self._perimeter = cursor.fetchone()[0]
        return self._perimeter

    @property
    def bounding_box(self):
        if not hasattr(self, "_bbox"):
            lakes = LakeGeom.objects.raw("""SELECT reachcode, Box2D(ST_Envelope(st_expand(the_geom,1000))) as coords from lake_geom WHERE reachcode = %s""", (self.pk,))  # noqa
            lake = list(lakes)[0]
            self._bbox = re.sub(r'[^0-9.-]', " ", lake.coords).split()
        return self._bbox

    @property
    def counties(self):
        """Return a nice comma separated list of the counties this lake belongs to"""
        if not hasattr(self, "_counties"):
            self._counties = ", ".join(c.name for c in self.county_set.all())
        return self._counties

    @counties.setter
    def counties(self, value):
        """
        We need a setter since the raw query we perform in the manager class
        generates the comma separated list of counties in the query itself
        """
        self._counties = value

    @property
    def watershed_tile_url(self):
        """
        Returns the URL to the watershed tile thumbnail from the arcgis
        server for this lake
        """
        # get the bounding box of the huc6 geom for the lake. The magic 300
        # here is from the original AOL
        results = HUC6.objects.raw("""
        SELECT Box2D(st_envelope(st_expand(the_geom, 300))) AS bbox, huc6.huc6_id
        FROM huc6 WHERE huc6.huc6_id = %s
        """, (self.huc6_id,))

        try:
            bbox = list(results)[0].bbox
        except IndexError:
            # this lake does not have a watershed
            return None

        return self._bbox_thumbnail_url(bbox)

    @property
    def basin_tile_url(self):
        """
        Return the URL to the lakebasin tile thumbnail from the arcgis server
        """
        # the magic 1000 here is from the original AOL too
        results = LakeGeom.objects.raw("""
        SELECT Box2D(st_envelope(st_expand(the_geom,1000))) as bbox, reachcode
        FROM lake_geom where reachcode = %s
        """, (self.pk,))

        bbox = results[0].bbox
        return self._bbox_thumbnail_url(bbox)

    def _bbox_thumbnail_url(self, bbox):
        """
        Take a boundingbox string from postgis, for example:
        BOX(727773.25 1372170,829042.75 1430280.75)
        and build the URL to a tile of that bounding box in the arcgis server
        """
        # extract out the numbers from the bbox, and comma separate them
        bbox = re.sub(r'[^0-9.-]', " ", bbox).split()
        bbox = ",".join(bbox)
        path = "export?bbox=%s&bboxSR=&layers=&layerdefs=&size=&imageSR=&format=jpg&transparent=false&dpi=&time=&layerTimeOptions=&f=image"
        return settings.TILE_URL + (path % bbox)

    @property
    def mussels(self):
        """
        This queries the mussel DB for any mussels that are within a certain
        distance of this lake. It returns a comma separated string of the
        status of the mussels
        """
        if not hasattr(self, "_mussels"):
            cursor = connection.cursor()
            cursor.execute("""
                SELECT
                    DISTINCT
                    specie.name as species,
                    date_checked,
                    agency.name as agency
                FROM
                    mussels.observation
                INNER JOIN
                    mussels.specie USING(specie_id)
                INNER JOIN
                    mussels.agency USING(agency_id)
                WHERE
                    ST_BUFFER(ST_TRANSFORM(the_geom, 3644), %s) && (SELECT the_geom FROM lake_geom WHERE reachcode = %s)
                ORDER BY date_checked DESC
            """, (DISTANCE_FROM_ITEM, self.pk))
            results = []
            for row in cursor:
                results.append({
                    "species": row[0],
                    "date_checked": row[1],
                    "source": row[2]
                })
            self._mussels = results

        return self._mussels
コード例 #18
0
ファイル: models.py プロジェクト: manonthemat/froide
class PublicBody(models.Model):
    name = models.CharField(_("Name"), max_length=255)
    other_names = models.TextField(_("Other names"), default="", blank=True)
    slug = models.SlugField(_("Slug"), max_length=255)
    description = models.TextField(_("Description"), blank=True)
    url = models.URLField(_("URL"), null=True, blank=True, max_length=500)

    parent = models.ForeignKey('PublicBody',
                               null=True,
                               blank=True,
                               default=None,
                               on_delete=models.SET_NULL,
                               related_name="children")
    root = models.ForeignKey('PublicBody',
                             null=True,
                             blank=True,
                             default=None,
                             on_delete=models.SET_NULL,
                             related_name="descendants")
    depth = models.SmallIntegerField(default=0)

    classification = models.ForeignKey(Classification,
                                       null=True,
                                       blank=True,
                                       on_delete=models.SET_NULL)

    email = models.EmailField(_("Email"), blank=True, default='')
    fax = models.CharField(max_length=50, blank=True)
    contact = models.TextField(_("Contact"), blank=True)
    address = models.TextField(_("Address"), blank=True)
    website_dump = models.TextField(_("Website Dump"), null=True, blank=True)
    request_note = models.TextField(_("request note"), blank=True)

    file_index = models.CharField(_("file index"), max_length=1024, blank=True)
    org_chart = models.CharField(_("organisational chart"),
                                 max_length=1024,
                                 blank=True)

    _created_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                    verbose_name=_("Created by"),
                                    blank=True,
                                    null=True,
                                    related_name='public_body_creators',
                                    on_delete=models.SET_NULL)
    _updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                    verbose_name=_("Updated by"),
                                    blank=True,
                                    null=True,
                                    related_name='public_body_updaters',
                                    on_delete=models.SET_NULL)
    created_at = models.DateTimeField(_("Created at"), default=timezone.now)
    updated_at = models.DateTimeField(_("Updated at"), default=timezone.now)
    confirmed = models.BooleanField(_("confirmed"), default=True)

    number_of_requests = models.IntegerField(_("Number of requests"),
                                             default=0)
    site = models.ForeignKey(Site,
                             verbose_name=_("Site"),
                             null=True,
                             on_delete=models.SET_NULL,
                             default=settings.SITE_ID)

    wikidata_item = models.CharField(max_length=50, blank=True)

    jurisdiction = models.ForeignKey(Jurisdiction,
                                     verbose_name=_('Jurisdiction'),
                                     blank=True,
                                     null=True,
                                     on_delete=models.SET_NULL)

    geo = models.PointField(null=True, blank=True, geography=True)
    regions = models.ManyToManyField(GeoRegion, blank=True)

    laws = models.ManyToManyField(
        FoiLaw, verbose_name=_("Freedom of Information Laws"))
    tags = TaggableManager(through=TaggedPublicBody, blank=True)
    categories = TaggableManager(through=CategorizedPublicBody,
                                 verbose_name=_("categories"),
                                 blank=True)

    non_filtered_objects = models.Manager()
    objects = PublicBodyManager()
    published = objects

    class Meta:
        ordering = ('name', )
        verbose_name = _("Public Body")
        verbose_name_plural = _("Public Bodies")

    serializable_fields = ('id', 'name', 'slug', 'request_note_html',
                           'description', 'url', 'email', 'contact', 'address',
                           'domain', 'number_of_requests')

    def __str__(self):
        return self.name

    @property
    def created_by(self):
        return self._created_by

    @property
    def updated_by(self):
        return self._updated_by

    @property
    def domain(self):
        if self.url and self.url.count('/') > 1:
            return self.url.split("/")[2]
        return None

    @property
    def all_names(self):
        names = [self.name, self.other_names]
        if self.jurisdiction:
            names.extend([self.jurisdiction.name, self.jurisdiction.slug])
        return ' '.join(names)

    @property
    def request_note_html(self):
        return markdown(self.request_note)

    @property
    def tag_list(self):
        return edit_string_for_tags(self.tags.all())

    @property
    def default_law(self):
        # FIXME: Materialize this?
        return self.get_applicable_law()

    def get_applicable_law(self, law_type=None):
        return get_applicable_law(pb=self, law_type=law_type)

    def get_absolute_url(self):
        return reverse('publicbody-show', kwargs={"slug": self.slug})

    def get_absolute_short_url(self):
        return reverse('publicbody-publicbody_shortlink',
                       kwargs={'obj_id': self.pk})

    def get_absolute_domain_url(self):
        return "%s%s" % (settings.SITE_URL, self.get_absolute_url())

    def get_absolute_domain_short_url(self):
        return "%s%s" % (settings.SITE_URL, self.get_absolute_short_url())

    def get_mediator(self):
        law = self.default_law
        if law is None:
            return None
        return law.mediator

    def get_label(self):
        return mark_safe(
            '%(name)s - <a href="%(url)s" target="_blank" '
            'class="info-link">%(detail)s</a>' % {
                "name": escape(self.name),
                "url": self.get_absolute_url(),
                "detail": _("More Info")
            })

    def as_data(self, request=None):
        from .api_views import PublicBodyListSerializer
        if request is None:
            ctx = get_fake_api_context()
        else:
            ctx = {'request': request}
        return PublicBodyListSerializer(self, context=ctx).data

    @property
    def children_count(self):
        return len(PublicBody.objects.filter(parent=self))

    @classmethod
    def export_csv(cls, queryset):

        fields = ("id", "name", "email", "fax", "contact", "address", "url",
                  ('classification', lambda x: x.classification.name
                   if x.classification else None), "jurisdiction__slug",
                  ("categories",
                   lambda x: edit_string_for_tags(x.categories.all())),
                  "other_names", "website_dump", "description", "request_note",
                  "parent__name",
                  ('regions',
                   lambda obj: ','.join(str(x.id) for x in obj.regions.all())))

        return export_csv(queryset, fields)
コード例 #19
0
class Subsidiary(WithGalleryMixin, models.Model):
    """Pobočka"""
    class Meta:
        verbose_name = _("Pobočka organizace")
        verbose_name_plural = _("Pobočky organizací")

    address = Address()
    company = ChainedForeignKey(
        "Company",
        related_name="subsidiaries",
        null=False,
        blank=False,
    )
    city = models.ForeignKey(
        City,
        verbose_name=_("Soutěžní město"),
        help_text=_(
            "Váš tým se zařadí do žebříčků za nejbližší soutěžní město."),
        null=False,
        blank=False,
        on_delete=models.CASCADE,
    )
    active = models.BooleanField(
        verbose_name=_("Aktivní"),
        default=True,
        null=False,
    )

    box_addressee_name = models.CharField(
        verbose_name=_("Jméno adresáta krabice pro pobočku"),
        help_text=
        _("Jmené osoby, která převezme krabici s tričky a zajistí jeich rozdělení na této pobočce. Nemusí se účastnit soutěže."
          ),
        max_length=30,
        null=True,
        blank=True,
    )
    box_addressee_telephone = models.CharField(
        verbose_name=_("Telefon adresáta krabice pro pobočku"),
        max_length=30,
        null=True,
        blank=True,
    )
    box_addressee_email = models.EmailField(
        verbose_name=_("Email adresáta krabice pro pobočku"),
        null=True,
        blank=True,
    )
    gallery = models.ForeignKey(
        "photologue.Gallery",
        verbose_name=_("Galerie fotek"),
        null=True,
        blank=True,
        on_delete=models.CASCADE,
    )
    icon = models.ForeignKey(
        "photologue.Photo",
        verbose_name=_("Ikona"),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )

    objects = models.Manager()
    active_objects = ActiveManager()

    def __str__(self):
        return "%s - %s" % (get_address_string(self.address), self.city)

    def name(self):
        return get_address_string(self.address)

    def get_recipient_string(self):
        """makes recipient from address_recipient and company name"""
        if self.address_recipient:
            if (self.address_recipient.lower().strip() ==
                    self.company.name.lower().strip()):
                return self.address_recipient
            else:
                return "%s (%s)" % (self.address_recipient, self.company.name)
        else:
            return self.company.name

    def clean(self):
        Address.clean(self.address, self, Subsidiary)
        if (self.box_addressee_name or self.box_addressee_email
                or self.box_addressee_telephone):
            if not self.box_addressee_name:
                raise ValidationError({
                    "box_addressee_name":
                    _("Pokud vyplňujete adresáta krabice, vyplňte prosím i jeho jméno"
                      )
                })
            if not self.box_addressee_email:
                raise ValidationError({
                    "box_addressee_email":
                    _("Pokud vyplňujete adresáta krabice, vyplňte prosím i jeho e-mail"
                      )
                })
            if not self.box_addressee_telephone:
                raise ValidationError({
                    "box_addressee_telephone":
                    _("Pokud vyplňujete adresáta krabice, vyplňte prosím i jeho telefon"
                      )
                })
コード例 #20
0
ファイル: models.py プロジェクト: mohanpillimitla/FIND_WAY
class BusStation(models.Model):
    name = models.CharField(max_length=20)
    location = models.PointField(srid=4326,null=True,blank=True)
    address = models.CharField(max_length=50)
    bus_station_id=models.CharField(max_length=10)
    objects=models.Manager()
コード例 #21
0
ファイル: models.py プロジェクト: pieterprovoost/vespa-watch
class AbstractObservation(models.Model):
    originates_in_vespawatch = models.BooleanField(
        default=True,
        help_text=
        "The observation was first created in VespaWatch, not iNaturalist")
    taxon = models.ForeignKey(Taxon,
                              on_delete=models.PROTECT,
                              blank=True,
                              null=True)
    observation_time = models.DateTimeField(verbose_name=_("Observation date"),
                                            validators=[no_future])
    comments = models.TextField(
        verbose_name=_("Comments"),
        blank=True,
        help_text=
        _("Comments are public: use them to describe your observation and help verification."
          ))

    latitude = models.FloatField(
        validators=[MinValueValidator(-90),
                    MaxValueValidator(90)],
        verbose_name=_("Latitude"))
    longitude = models.FloatField(
        validators=[MinValueValidator(-180),
                    MaxValueValidator(180)],
        verbose_name=_("Longitude"))

    inaturalist_id = models.BigIntegerField(verbose_name=_("iNaturalist ID"),
                                            blank=True,
                                            null=True)
    inaturalist_species = models.CharField(
        verbose_name=_("iNaturalist species"),
        max_length=100,
        blank=True,
        null=True)  # TODO: check if this is still in use or useful
    inat_vv_confirmed = models.BooleanField(
        blank=True,
        null=True)  # The community ID of iNaturalist says it's Vespa Velutina

    # Observer info
    observer_name = models.CharField(verbose_name=_("Name"),
                                     max_length=255,
                                     blank=True,
                                     null=True)
    observer_email = models.EmailField(verbose_name=_("Email address"),
                                       blank=True,
                                       null=True)
    observer_phone = models.CharField(verbose_name=_("Telephone number"),
                                      max_length=20,
                                      blank=True,
                                      null=True)

    created_at = models.DateTimeField(default=timezone.now)

    # Managers
    objects = models.Manager()  # The default manager.
    from_inat_objects = InatCreatedObservationsManager()
    from_vespawatch_objects = VespawatchCreatedObservationsManager()
    new_vespawatch_objects = VespawatchNewlyCreatedObservationsManager()

    class Meta:
        abstract = True
        # We got some duplicates and don't exactly know why, this is an attempt to block them without being too
        # aggresive and introduce bugs (hence the limited number of fields).
        unique_together = [
            'taxon', 'observation_time', 'latitude', 'longitude', 'comments',
            'inaturalist_id'
        ]

    @property
    def vernacular_names_in_all_languages(self):
        """Returns a dict such as: {'en': XXXX, 'nl': YYYY}"""
        vn = {}
        for lang in settings.LANGUAGES:
            code = lang[0]
            vn[code] = getattr(self.taxon, f'vernacular_name_{code}')
        return vn

    @property
    def display_vernacular_name(self):
        if self.taxon:
            return _(self.taxon.vernacular_name)
        else:
            return ''

    @property
    def display_scientific_name(self):
        if self.taxon:
            return self.taxon.name
        else:
            return self.inaturalist_species or _('Unknown')

    @property
    def can_be_edited_in_admin(self):
        if self.originates_in_vespawatch:
            if self.exists_in_inaturalist:
                return False
            else:
                return True
        else:  # Comes from iNaturalist: we can never delete
            return False

    @property
    def can_be_edited_or_deleted(self):
        """Return True if this observation can be edited in Vespa-Watch (admin, ...)"""
        return self.originates_in_vespawatch  # We can't edit obs that comes from iNaturalist (they're never pushed).

    @property
    def taxon_can_be_locally_changed(self):
        if self.originates_in_vespawatch and self.exists_in_inaturalist:
            return False  # Because we rely on community: info is always pulled and never pushed

        return True

    @property
    def exists_in_inaturalist(self):
        return self.inaturalist_id is not None

    @property
    def inaturalist_obs_url(self):
        if self.exists_in_inaturalist:
            return f'https://www.inaturalist.org/observations/{self.inaturalist_id}'

        return None

    def has_warnings(self):
        return len(self.warnings.all()) > 0

    has_warnings.boolean = True

    def _params_for_inat(self):
        """(Create/update): Common ground for the pushed data to iNaturalist.

        taxon_id is not part of it because we rely on iNaturalist to correct the identification, if necessary.
        All the rest is pushed.
        """

        vespawatch_evidence_value = 'nest' if self.__class__ == Nest else 'individual'

        ofv = [{
            'observation_field_id': settings.VESPAWATCH_ID_OBS_FIELD_ID,
            'value': self.pk
        }, {
            'observation_field_id': settings.VESPAWATCH_EVIDENCE_OBS_FIELD_ID,
            'value': vespawatch_evidence_value
        }]

        if vespawatch_evidence_value == 'individual' and self.behaviour:
            ofv.append(
                {
                    'observation_field_id':
                    settings.VESPAWATCH_BEHAVIOUR_OBS_FIELD_ID,
                    'value': self.get_behaviour_display()
                }
            )  # TODO: get_behaviour_display(): what will happen to push if we translate the values for the UI

        return {
            'observed_on_string':
            self.observation_time.isoformat(),
            'time_zone':
            'Brussels',
            'description':
            self.comments,
            'latitude':
            self.latitude,
            'longitude':
            self.longitude,
            'observation_field_values_attributes': [{
                'observation_field_id':
                settings.VESPAWATCH_ID_OBS_FIELD_ID,
                'value':
                self.pk
            }, {
                'observation_field_id':
                settings.VESPAWATCH_EVIDENCE_OBS_FIELD_ID,
                'value':
                vespawatch_evidence_value
            }]
        }

    def flag_warning(self, text):
        if text in [x.text for x in self.warnings.all()]:
            return  # warning already set
        if self.__class__.__name__ == 'Nest':
            warning = NestObservationWarning(text=text,
                                             datetime=now(),
                                             observation=self)
            warning.save()
        elif self.__class__.__name__ == 'Individual':
            warning = IndividualObservationWarning(text=text,
                                                   datetime=now(),
                                                   observation=self)
            warning.save()

    def flag_based_on_inat_data(self, inat_observation_data):
        """
        The observation was no longer found on iNaturalist with our general filters.
        Check why, and flag this observation
        """
        # Project is vespawatch?
        if not settings.VESPAWATCH_PROJECT_ID in inat_observation_data[
                'project_ids']:
            self.flag_warning('not in vespawatch project')

        # Taxon known in VW?
        returned_taxon_id = ''
        if 'community_taxon_id' in inat_observation_data and inat_observation_data[
                'community_taxon_id']:
            returned_taxon_id = inat_observation_data['community_taxon_id']
        elif 'taxon' in inat_observation_data:
            if 'id' in inat_observation_data['taxon']:
                returned_taxon_id = inat_observation_data['taxon']['id']
        if returned_taxon_id not in [
                y for x in Taxon.objects.all()
                for y in x.inaturalist_pull_taxon_ids
        ]:
            self.flag_warning('unknown taxon')

    def update_from_inat_data(self, inat_observation_data):
        # Check the vespawatch_evidence
        # ------
        # If the observation is a nest but the vespawatch evidence is not nest => flag the nest
        if 'ofvs' in inat_observation_data:
            vw_evidence_list = [
                x['value'] for x in inat_observation_data['ofvs']
                if x['field_id'] == settings.VESPAWATCH_EVIDENCE_OBS_FIELD_ID
            ]
            if len(vw_evidence_list) > 0:
                vw_evidence = vw_evidence_list[0]

                if self.__class__.__name__ == 'Nest':
                    if vw_evidence != 'nest':
                        self.flag_warning('individual at inaturalist')
                # If the observation is an individual but the vespawatch evidence is a nest and the observation originates in vespawatch => delete the individual and create a nest
                elif self.__class__.__name__ == 'Individual':
                    if vw_evidence == 'nest':
                        if self.originates_in_vespawatch:
                            self.flag_warning('nest at inaturalist')
                        else:
                            create_observation_from_inat_data(
                                inat_observation_data)
                            self.delete()
                            return

        # Update taxon data and set inat_vv_confirmed (use inat_data_confirms_vv() )
        self.inat_vv_confirmed = inat_data_confirms_vv(inat_observation_data)

        # Update photos
        # -------------
        # When we pull again and the API returns additional images, those are not added. This is done
        # because we insert a UUID in the filename when we pull it. The result of that is that we cannot
        # compare that image with the image url that we retrieve from iNaturalist. So to prevent adding
        # the same image again and again with subsequent pulls, we only add images when the observation
        # has none.
        if len(self.pictures.all()) == 0:
            for photo in inat_observation_data['photos']:
                self.assign_picture_from_url(photo['url'])

        # Update location
        self.latitude = inat_observation_data['geojson']['coordinates'][1]
        self.longitude = inat_observation_data['geojson']['coordinates'][0]

        # Update time
        # -------------
        observation_time = dateparser.parse(
            inat_observation_data['observed_on_string'],
            settings={'TIMEZONE': inat_observation_data['observed_time_zone']})
        if observation_time is None:
            # Sometimes, dateparser doesn't understand the string but we have the bits and pieces in
            # inaturalist_data['observed_on_details']
            details = inat_observation_data['observed_on_details']
            observation_time = datetime(
                year=details['year'],
                month=details['month'],
                day=details['day'],
                hour=details['hour']
            )  # in the observed cases, we had nothing more precise than the hour

        # Sometimes, the time is naive (even when specifying it to dateparser), because (for the detected cases, at least)
        # The time is 00:00:00. In that case we make it aware to avoid Django warnings (in the local time zone since all
        # observations occur in Belgium
        if is_naive(observation_time):
            # Some dates (apparently)
            observation_time = make_aware(observation_time)

        self.observation_time = observation_time

        self.comments = inat_observation_data['description'] or ''

        # Update taxon
        # -------------
        try:
            self.inaturalist_species = ''
            taxon = get_taxon_from_inat_taxon_id(
                inat_observation_data['taxon']['id'])
            self.taxon = taxon
        except Taxon.DoesNotExist:
            self.taxon = None
            self.inaturalist_species = inat_observation_data['taxon'][
                'name'] if 'name' in inat_observation_data['taxon'] else ''

        self.save()

    def create_at_inaturalist(self, access_token, user_agent):
        """Creates a new observation at iNaturalist for this observation

        It will update the current object so self.inaturalist_id is properly set.
        On the other side, it will also set the vespawatch_id observation field so the observation can be found from
        the iNaturalist record.

        :param access_token: as returned by pyinaturalist.rest_api.get_access_token(
        """

        params_only_for_create = {
            'taxon_id': self.taxon.inaturalist_push_taxon_id
        }  # TODO: with the new sync, does it still makes sense to separate the create/update parameters?

        params = {
            'observation': {
                **params_only_for_create,
                **self._params_for_inat()
            }
        }

        r = create_observations(params=params,
                                access_token=access_token,
                                user_agent=user_agent)
        self.inaturalist_id = r[0]['id']
        self.save()
        self.push_attached_pictures_at_inaturalist(access_token=access_token,
                                                   user_agent=user_agent)

    def get_photo_filename(self, photo_url):
        # TODO: Find a cleaner solution to this
        # It seems the iNaturalist only returns small thumbnails such as
        # 'https://static.inaturalist.org/photos/1960816/square.jpg?1444437211'
        # We can circumvent the issue by hacking the URL...
        photo_url = photo_url.replace('square.jpg', 'large.jpg')
        photo_url = photo_url.replace('square.jpeg', 'large.jpeg')
        photo_filename = photo_url[photo_url.rfind("/") + 1:].split('?', 1)[0]
        return photo_filename

    def assign_picture_from_url(self, photo_url):
        photo_filename = self.get_photo_filename(photo_url)
        if photo_filename not in [x.image.name for x in self.pictures.all()]:
            if self.__class__ == Nest:
                photo_obj = NestPicture()
            else:
                photo_obj = IndividualPicture()

            photo_content = ContentFile(requests.get(photo_url).content)

            photo_obj.observation = self
            photo_obj.image.save(photo_filename, photo_content)
            photo_obj.save()

    def push_attached_pictures_at_inaturalist(self, access_token, user_agent):
        if self.inaturalist_id:
            for picture in self.pictures.all():
                add_photo_to_observation(observation_id=self.inaturalist_id,
                                         file_object=picture.image.read(),
                                         access_token=access_token,
                                         user_agent=user_agent)

    def get_taxon_name(self):
        if self.taxon:
            return self.taxon.name
        else:
            return ''

    @property
    def formatted_observation_date(self):
        # We need to be aware of the timezone, hence the defaultfilter trick
        return defaultfilters.date(self.observation_time, 'Y-m-d')

    @property
    def observation_time_iso(self):
        return self.observation_time.isoformat()

    def save(self, *args, **kwargs):
        # Let's make sure model.clean() is called on each save(), for validation
        self.full_clean()

        return super(AbstractObservation, self).save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        if self.originates_in_vespawatch and self.exists_in_inaturalist:
            InatObsToDelete.objects.create(inaturalist_id=self.inaturalist_id)

        return super(AbstractObservation, self).delete(*args, **kwargs)
コード例 #22
0
class Sequence(models.Model):
    unique_id = models.UUIDField(default=uuid.uuid4,
                                 editable=False,
                                 unique=True)
    user = models.ForeignKey(UserModel, on_delete=models.CASCADE)
    camera_make = models.ForeignKey(CameraMake,
                                    on_delete=models.CASCADE,
                                    null=True,
                                    blank=True)
    captured_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(null=True, blank=True)
    seq_key = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        verbose_name="Mapillary Sequence Key",
    )
    pano = models.BooleanField(default=False)
    user_key = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        verbose_name="Mapillary User Key",
    )
    username = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        verbose_name="Mapillary Username",
    )
    geometry_coordinates = models.LineStringField(null=True,
                                                  blank=True,
                                                  srid=4326)
    geometry_coordinates_ary = ArrayField(ArrayField(
        models.FloatField(default=1)),
                                          null=True,
                                          blank=True)
    coordinates_cas = ArrayField(models.FloatField(default=0),
                                 null=True,
                                 blank=True)
    coordinates_image = ArrayField(models.CharField(default='',
                                                    max_length=100),
                                   null=True,
                                   blank=True)
    is_uploaded = models.BooleanField(default=False)
    is_private = models.BooleanField(default=False)
    updated_at = models.DateTimeField(default=datetime.now, blank=True)

    name = models.CharField(max_length=100, default='')
    description = models.TextField(default='')
    transport_type = models.ForeignKey(TransType,
                                       on_delete=models.CASCADE,
                                       null=True)
    tag = models.ManyToManyField(Tag)

    image_count = models.IntegerField(default=0)

    is_mapillary = models.BooleanField(default=True)
    is_published = models.BooleanField(default=True)
    is_image_download = models.BooleanField(default=False)
    is_map_feature = models.BooleanField(default=False)

    google_street_view = models.BooleanField(default=False)
    strava = models.CharField(max_length=50, null=True, blank=True)

    distance = models.FloatField(null=True, blank=True)

    objects = models.Manager()
    vector_tiles = CustomSequenceMVTManager(
        geo_col='geometry_coordinates',
        select_columns=['seq_key', 'unique_id'],
        is_show_id=False,
        source_layer='mtp-sequences')

    def get_absolute_url(self):
        from django.urls import reverse
        return reverse('sequence.sequence_detail',
                       kwargs={'unique_id': str(self.unique_id)})

    def get_image_count(self):
        if self.coordinates_image is not None:
            return len(self.coordinates_image)
        else:
            return 0

    def get_tag_str(self):
        tags = []
        if self.tag.all().count() == 0:
            return ''
        for tag in self.tag.all():
            if tag and tag.is_actived:
                tags.append(tag.name)

        if len(tags) > 0:
            return ', '.join(tags)
        else:
            return ''

    def get_tags(self):
        tags = []
        if self.tag.all().count() == 0:
            return ''
        for tag in self.tag.all():
            if tag and tag.is_actived:
                tags.append(tag.name)
        return tags

    def get_short_description(self):
        description = self.description
        if len(description) > 100:
            return description[0:100] + '...'
        else:
            return description

    def get_first_image_key(self):
        if len(self.coordinates_image) > 0:
            return self.coordinates_image[0]
        else:
            return ''

    def get_mapillary_username(self):
        return self.username

    def get_like_count(self):
        liked_guidebook = SequenceLike.objects.filter(sequence=self)
        if not liked_guidebook:
            return 0
        else:
            return liked_guidebook.count()

    def get_distance(self):
        all_distance = 0
        if self.geometry_coordinates_ary is None:
            return all_distance

        if len(self.geometry_coordinates_ary) > 0:
            first_point = self.geometry_coordinates_ary[0]
            for i in range(len(self.geometry_coordinates_ary) - 1):
                if i == 0:
                    continue
                second_point = self.geometry_coordinates_ary[i]
                d = distance(first_point, second_point)
                first_point = second_point
                all_distance += d
            all_distance = "%.3f" % all_distance
        return all_distance

    def get_cover_image(self):
        image_keys = self.coordinates_image
        if image_keys is None:
            return None
        if len(image_keys) > 0:
            return image_keys[0]
        else:
            return None

    def get_first_point_lat(self):
        if self.geometry_coordinates_ary is None:
            return None
        lat = self.geometry_coordinates_ary[0][1]
        return lat

    def get_first_point_lng(self):
        if self.geometry_coordinates_ary is None:
            return None
        lng = self.geometry_coordinates_ary[0][0]
        return lng
コード例 #23
0
ファイル: models.py プロジェクト: Raoh-san/sdi
def get_manager(schema):
    m = models.Manager().db_manager(schema)
    # print('Created Manager On DB: {} {}'.format(schema, m.uuid))
    return m
コード例 #24
0
class Image(models.Model):
    unique_id = models.UUIDField(default=uuid.uuid4,
                                 editable=False,
                                 unique=True)
    user = models.ForeignKey(UserModel, on_delete=models.CASCADE)

    camera_make = models.ForeignKey(CameraMake,
                                    on_delete=models.CASCADE,
                                    null=True,
                                    blank=True)
    camera_model = models.ForeignKey(CameraModel,
                                     on_delete=models.CASCADE,
                                     null=True,
                                     blank=True)
    cas = models.FloatField(default=0)
    captured_at = models.DateTimeField(null=True, blank=True)
    sequence = models.ForeignKey(Sequence,
                                 on_delete=models.CASCADE,
                                 null=True,
                                 blank=True)
    seq_key = models.CharField(max_length=100, default='')
    image_key = models.CharField(max_length=100)
    pano = models.BooleanField(default=False)
    user_key = models.CharField(max_length=100, default='')
    username = models.CharField(max_length=100, default='')
    organization_key = models.CharField(max_length=255, null=True)
    is_uploaded = models.BooleanField(default=False)
    is_private = models.BooleanField(default=False)
    is_mapillary = models.BooleanField(default=True)
    lat = models.FloatField(default=0)
    lng = models.FloatField(default=0)
    ele = models.FloatField(default=0)
    type = models.CharField(max_length=50, default='Point')

    point = models.PointField(null=True, blank=True)

    mapillary_image = models.ImageField(upload_to=image_directory_path,
                                        null=True,
                                        blank=True)

    image_label = models.ManyToManyField(LabelType, through='ImageLabel')

    map_feature_keys = ArrayField(ArrayField(models.CharField(max_length=50)),
                                  null=True,
                                  blank=True)
    map_feature_values = ArrayField(ArrayField(
        models.CharField(max_length=50)),
                                    null=True,
                                    blank=True)

    objects = models.Manager()
    vector_tiles = CustomImageMVTManager(
        geo_col='point',
        select_columns=['image_key', 'unique_id'],
        is_show_id=False,
        source_layer='mtp-images')

    def get_sequence_by_key(self):
        if self.seq_key != '':
            sequence = Sequence.objects.get(seq_key=self.seq_key)
            if sequence is None or not sequence:
                return None
            return sequence
        return None
コード例 #25
0
ファイル: models.py プロジェクト: eliasdata/dataselectie
class KadastraalObject(models.Model):
    id = models.CharField(max_length=60, primary_key=True)
    aanduiding = models.CharField(max_length=17)

    kadastrale_gemeente = models.ForeignKey(KadastraleGemeente,
                                            related_name="kadastrale_objecten",
                                            on_delete=models.CASCADE)

    sectie = models.ForeignKey(KadastraleSectie,
                               related_name="kadastrale_objecten",
                               on_delete=models.CASCADE)

    date_modified = models.DateTimeField(auto_now=True)

    perceelnummer = models.IntegerField()
    indexletter = models.CharField(max_length=1)
    indexnummer = models.IntegerField()
    soort_grootte = models.ForeignKey(SoortGrootte,
                                      null=True,
                                      on_delete=models.CASCADE)
    grootte = models.IntegerField(null=True)
    koopsom = models.IntegerField(null=True)
    koopsom_valuta_code = models.CharField(max_length=50, null=True)
    koopjaar = models.CharField(max_length=15, null=True)
    meer_objecten = models.NullBooleanField(default=None)
    cultuurcode_onbebouwd = models.ForeignKey(CultuurCodeOnbebouwd,
                                              null=True,
                                              on_delete=models.CASCADE)
    cultuurcode_bebouwd = models.ForeignKey(CultuurCodeBebouwd,
                                            null=True,
                                            on_delete=models.CASCADE)

    register9_tekst = models.TextField()
    status_code = models.CharField(max_length=50)
    toestandsdatum = models.DateField(null=True)
    voorlopige_kadastrale_grens = models.NullBooleanField(default=None)
    in_onderzoek = models.TextField(null=True)

    poly_geom = geo.MultiPolygonField(srid=SRID_RD, null=True)
    point_geom = geo.PointField(srid=SRID_RD, null=True)

    voornaamste_gerechtigde = models.ForeignKey(Eigenaar,
                                                null=True,
                                                on_delete=models.CASCADE)

    verblijfsobjecten = models.ManyToManyField(
        bag.Verblijfsobject,
        through='KadastraalObjectVerblijfsobjectRelatie',
        related_name="kadastrale_objecten")

    g_percelen = models.ManyToManyField('KadastraalObject',
                                        through=APerceelGPerceelRelatie,
                                        through_fields=('a_perceel',
                                                        'g_perceel'),
                                        related_name="a_percelen")

    buurten = models.ManyToManyField(bag.Buurt,
                                     through='EigendomBuurt',
                                     through_fields=('kadastraal_object',
                                                     'buurt'),
                                     related_name="eigendommen")

    wijken = models.ManyToManyField(bag.Buurtcombinatie,
                                    through='EigendomWijk',
                                    through_fields=('kadastraal_object',
                                                    'buurt_combi'),
                                    related_name="eigendommen")

    ggws = models.ManyToManyField(bag.Gebiedsgerichtwerken,
                                  through='EigendomGGW',
                                  through_fields=('kadastraal_object', 'ggw'),
                                  related_name="eigendommen")

    stadsdelen = models.ManyToManyField(bag.Stadsdeel,
                                        through='EigendomStadsdeel',
                                        through_fields=('kadastraal_object',
                                                        'stadsdeel'),
                                        related_name="eigendommen")

    objects = geo.Manager()

    class Meta:
        managed = False
        ordering = ('kadastrale_gemeente__id', 'sectie', 'perceelnummer',
                    '-indexletter', 'indexnummer')

    def __str__(self):
        return self.get_aanduiding_spaties()

    def get_aanduiding_spaties(self):
        return kadaster.get_aanduiding_spaties(self.kadastrale_gemeente.id,
                                               self.sectie.sectie,
                                               self.perceelnummer,
                                               self.indexletter,
                                               self.indexnummer)
コード例 #26
0
class NonStandardManager(models.Model):
    name = models.CharField(max_length=30)

    manager = models.Manager()
コード例 #27
0
ファイル: hearing.py プロジェクト: City-of-Turku/kerrokantasi
class Hearing(StringIdBaseModel, TranslatableModel):
    open_at = models.DateTimeField(verbose_name=_('opening time'),
                                   default=timezone.now)
    close_at = models.DateTimeField(verbose_name=_('closing time'),
                                    default=timezone.now)
    force_closed = models.BooleanField(verbose_name=_('force hearing closed'),
                                       default=False)
    translations = TranslatedFields(
        title=models.CharField(verbose_name=_('title'), max_length=255),
        borough=models.CharField(verbose_name=_('borough'),
                                 blank=True,
                                 default='',
                                 max_length=200),
    )
    servicemap_url = models.CharField(verbose_name=_('service map URL'),
                                      default='',
                                      max_length=255,
                                      blank=True)
    geojson = GeoJSONField(blank=True, null=True, verbose_name=_('area'))
    geometry = models.GeometryField(blank=True,
                                    null=True,
                                    verbose_name=_('area geometry'))
    organization = models.ForeignKey(Organization,
                                     verbose_name=_('organization'),
                                     related_name="hearings",
                                     blank=True,
                                     null=True,
                                     on_delete=models.PROTECT)
    labels = models.ManyToManyField("Label",
                                    verbose_name=_('labels'),
                                    blank=True)
    followers = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        verbose_name=_('followers'),
        help_text=_('users who follow this hearing'),
        related_name='followed_hearings',
        blank=True,
        editable=False)
    slug = AutoSlugField(
        verbose_name=_('slug'),
        populate_from='title',
        editable=True,
        unique=True,
        blank=True,
        help_text=_(
            'You may leave this empty to automatically generate a slug'))
    n_comments = models.IntegerField(verbose_name=_('number of comments'),
                                     blank=True,
                                     default=0,
                                     editable=False)
    contact_persons = models.ManyToManyField(ContactPerson,
                                             verbose_name=_('contact persons'),
                                             related_name='hearings')
    project_phase = models.ForeignKey(ProjectPhase,
                                      verbose_name=_('project phase'),
                                      related_name='hearings',
                                      on_delete=models.PROTECT,
                                      null=True,
                                      blank=True)

    objects = BaseModelManager.from_queryset(HearingQueryset)()
    original_manager = models.Manager()

    class Meta:
        verbose_name = _('hearing')
        verbose_name_plural = _('hearings')

    def __str__(self):
        return (self.title or self.id)

    @property
    def closed(self):
        return self.force_closed or not (self.open_at <= now() <=
                                         self.close_at)

    def check_commenting(self, request):
        if self.closed:
            raise ValidationError(
                _("%s is closed and does not allow comments anymore") % self,
                code="hearing_closed")

    def check_voting(self, request):
        if self.closed:
            raise ValidationError(
                _("%s is closed and does not allow voting anymore") % self,
                code="hearing_closed")

    @property
    def preview_code(self):
        if not self.pk:
            return None
        return get_hmac_b64_encoded(self.pk)

    @property
    def preview_url(self):
        if not (self.preview_code
                and hasattr(settings, 'DEMOCRACY_UI_BASE_URL')):
            return None
        url = urljoin(settings.DEMOCRACY_UI_BASE_URL,
                      '/hearing/%s/?preview=%s' % (self.pk, self.preview_code))
        return url

    def save(self, *args, **kwargs):
        slug_field = self._meta.get_field('slug')

        # we need to manually use autoslug utils here with ModelManager, because automatic slug populating
        # uses our default manager, which can lead to a slug collision between this and a deleted hearing
        self.slug = generate_unique_slug(slug_field, self, self.slug,
                                         Hearing.original_manager)

        self.geometry = get_geometry_from_geojson(self.geojson)

        super().save(*args, **kwargs)

    def recache_n_comments(self):
        new_n_comments = (self.sections.all().aggregate(
            Sum('n_comments')).get('n_comments__sum') or 0)
        if new_n_comments != self.n_comments:
            self.n_comments = new_n_comments
            self.save(update_fields=("n_comments", ))

    def get_main_section(self):
        try:
            return self.sections.get(type__identifier=InitialSectionType.MAIN)
        except ObjectDoesNotExist:
            return None

    def is_visible_for(self, user):
        if self.published and self.open_at < now():
            return True
        if not user.is_authenticated:
            return False
        if user.is_superuser:
            return True
        user_organization = user.get_default_organization()
        if not (user_organization and self.organization):
            return False
        return self.organization in user.admin_organizations.all()

    def soft_delete(self, using=None):
        # we want deleted hearings to give way to new ones, the original slug from a deleted hearing
        # is now free to use
        self.slug += '-deleted'
        self.save()
        super().soft_delete(using=using)
コード例 #28
0
class Station(Gpoint):
    owner = models.ForeignKey(
        Lentity,
        related_name="owned_stations",
        on_delete=models.CASCADE,
        verbose_name=pgettext_lazy("Entity that owns the station", "Owner"),
    )
    start_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=pgettext_lazy("Station start date", "Start date"),
    )
    end_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=pgettext_lazy("Station end date", "End date"),
    )
    overseer = models.CharField(max_length=30, blank=True, verbose_name=_("Overseer"))
    # The following two fields are only useful when USERS_CAN_ADD_CONTENT
    # is set.
    creator = models.ForeignKey(
        User,
        null=True,
        blank=True,
        related_name="created_stations",
        on_delete=models.CASCADE,
        verbose_name=pgettext_lazy(
            "User who has full permissions on station", "Administrator"
        ),
    )
    maintainers = models.ManyToManyField(
        User,
        blank=True,
        related_name="maintaining_stations",
        verbose_name=_("Maintainers"),
    )

    objects = models.Manager()
    on_site = CurrentSiteManager()
    f_dependencies = ["Gpoint"]

    class Meta:
        verbose_name = _("Station")
        verbose_name_plural = _("Stations")

    @property
    def last_update_naive(self):
        def get_last_update_naive():
            result = self.last_update
            if result is not None:
                result = result.replace(tzinfo=None)
            return result

        return cache.get_or_set(
            f"station_last_update_naive_{self.id}", get_last_update_naive
        )

    @property
    def last_update(self):
        def get_last_update():
            from .timeseries import Timeseries

            timeseries = Timeseries.objects.filter(timeseries_group__gentity_id=self.id)
            result = None
            for t in timeseries:
                t_end_date = t.end_date
                if t_end_date is None:
                    continue
                if result is None or t_end_date > result:
                    result = t_end_date
            return result

        return cache.get_or_set(f"station_last_update_{self.id}", get_last_update)
コード例 #29
0
class Feature(models.Model):

    STATUS_CHOICES = (
        ("draft", "Brouillon"),
        ("pending", "En attente de publication"),
        ("published", "Publié"),
        ("archived", "Archivé"),
    )

    feature_id = models.UUIDField(
        "Identifiant", primary_key=True, editable=False, default=uuid.uuid4)

    title = models.CharField("Titre", max_length=128, null=True, blank=True)

    description = models.TextField("Description", blank=True, null=True)

    status = models.CharField(
        "Statut", choices=STATUS_CHOICES, max_length=50,
        default="draft")

    created_on = models.DateTimeField("Date de création", null=True, blank=True)

    updated_on = models.DateTimeField("Date de maj", null=True, blank=True)

    archived_on = models.DateField(
        "Date d'archivage automatique", null=True, blank=True)

    deletion_on = models.DateField(
        "Date de suppression automatique", null=True, blank=True)

    creator = models.ForeignKey(
        to=settings.AUTH_USER_MODEL, verbose_name="Créateur",
        on_delete=models.SET_NULL, null=True, blank=True)

    project = models.ForeignKey("geocontrib.Project", on_delete=models.CASCADE)

    feature_type = models.ForeignKey("geocontrib.FeatureType", on_delete=models.CASCADE)

    geom = models.GeometryField("Géométrie", srid=4326)

    feature_data = JSONField(blank=True, null=True)

    objects = models.Manager()

    handy = AvailableFeaturesManager()

    class Meta:
        verbose_name = "Signalement"
        verbose_name_plural = "Signalements"

    def clean(self):
        if self.feature_data and not isinstance(self.feature_data, dict):
            raise ValidationError('Format de donnée invalide')

    def save(self, *args, **kwargs):
        if self._state.adding is True:
            self.created_on = timezone.now()
        self.updated_on = timezone.now()
        super().save(*args, **kwargs)

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

    def get_absolute_url(self):

        return reverse('geocontrib:feature_update', kwargs={
            'slug': self.project.slug, 'feature_type_slug': self.feature_type.slug,
            'feature_id': self.feature_id})

    def get_view_url(self):

        return reverse('geocontrib:feature_detail', kwargs={
            'slug': self.project.slug, 'feature_type_slug': self.feature_type.slug,
            'feature_id': self.feature_id})

    @property
    def custom_fields_as_list(self):
        CustomField = apps.get_model(app_label='geocontrib', model_name="CustomField")
        custom_fields = CustomField.objects.filter(feature_type=self.feature_type)
        res = []
        if custom_fields.exists():
            for row in custom_fields.order_by('position').values('name', 'label', 'field_type'):
                value = ''
                if isinstance(self.feature_data, dict):
                    value = self.feature_data.get(row['name'])
                res.append({
                    'label': row['label'],
                    'field_type': row['field_type'],
                    'value': value
                })
        return res

    @property
    def display_creator(self):
        res = "Utilisateur supprimé"
        if self.creator:
            res = self.creator.get_full_name() or self.creator.username
        return res
コード例 #30
0
class Shop(models.Model):
    objects = models.Manager()
    name = models.CharField(max_length=100)
    location = models.PointField() #represents a pair of longitude and latitude coordinates.
    address = models.CharField(max_length=100)
    city = models.CharField(max_length=50)