Пример #1
0
class TreeImportEvent(GenericImportEvent):
    """
    A TreeImportEvent represents an attempt to upload a csv containing
    tree/plot information
    """

    import_schema_version = 2  # Update if any column header name changes
    import_type = 'tree'

    plot_length_conversion_factor = models.FloatField(default=1.0)
    plot_width_conversion_factor = models.FloatField(default=1.0)
    diameter_conversion_factor = models.FloatField(default=1.0)
    tree_height_conversion_factor = models.FloatField(default=1.0)
    canopy_height_conversion_factor = models.FloatField(default=1.0)

    class Meta:
        app_label = 'importer'

    def row_set(self):
        return self.treeimportrow_set

    def __unicode__(self):
        return _('Tree Import #%s') % self.pk

    def get_udf_column_name(self, udf_def):
        name = self._get_udf_name(udf_def)
        return name.lower()

    def _get_udf_name(self, udf_def):
        # Prefix with model name, e.g. "Density" -> "Tree: Density"
        model_name = udf_def.model_type
        if model_name == 'Plot':
            model_name = 'Planting Site'
        return "%s: %s" % (model_name, udf_def.name)

    def _get_udf_names(self):
        def udf_names(model_name):
            return tuple(
                self._get_udf_name(udf_def)
                for udf_def in udf_defs(self.instance, model_name)
                if not udf_def.iscollection)

        return udf_names('Plot') + udf_names('Tree')

    def ordered_legal_fields(self):
        udf_names = self._get_udf_names()
        udf_names = tuple(n.lower() for n in udf_names)
        return fields.trees.ALL + udf_names

    def ordered_legal_fields_title_case(self):
        udf_names = self._get_udf_names()
        return fields.title_case(fields.trees.ALL) + udf_names

    def _required_fields(self):
        return {fields.trees.POINT_X, fields.trees.POINT_Y}

    def legal_and_required_fields(self):
        legal_fields = set(self.ordered_legal_fields())
        return legal_fields, self._required_fields()

    def legal_and_required_fields_title_case(self):
        legal_fields = set(self.ordered_legal_fields_title_case())
        return legal_fields, fields.title_case(self._required_fields())
Пример #2
0
class DataPoint(models.Model):
    location = models.PointField()
    uSv = models.FloatField()
    time = models.IntegerField()
Пример #3
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
Пример #4
0
class Pavement(models.Model):
    Aerodrome_Entity = models.ForeignKey(Aerodrome_Entity,null=True,on_delete=models.SET_NULL)
    Pavement_Name = models.CharField(max_length=100)
    Width = models.FloatField(null=True)
    Shoulder_Width = models.FloatField(null=True)
    Design_Types = [('f','Flexible Design'),('r','Rigid Pavement')]
    Pavement_Design_Type = models.CharField(max_length=1,choices=Design_Types,null=True)
    Subgrade_Density = models.FloatField(null=True)
    Subgrade_Soil_Classification = models.CharField(max_length=100,null=True)
    Soil_Shear_Strength = models.FloatField(null=True)
    Soil_DCP_Test_Result = models.FloatField(null=True)
    Soil_CPT_Test_Result = models.FloatField(null=True)
    Soil_Percolation_Rate = models.FloatField(null=True)
    SubBase_Material = models.CharField(max_length=100,null=True)
    SubBase_Thickness = models.FloatField(null=True)
    Joint_Spacing = models.FloatField(null=True)
    SubBase_Base_Seperation_Material = models.CharField(max_length=100,null=True)
    Base_Material = models.CharField(max_length=100,null=True)
    Base_Thickness = models.CharField(max_length=100,null=True)
    Concrete_Compressive_Strength = models.FloatField(null=True)
    Asphalt_Thickness = models.FloatField(null=True)
    Binder_Thickness = models.FloatField(null=True)
    Wearing_Thickness = models.FloatField(null=True)
    Drainage_Longitudinal_Slope = models.FloatField(null=True)
    Drainage_Cross_Slope = models.FloatField(null=True) 
    

    def __str__(self):
        return self.Pavement_Name

    class Meta:
        ordering=['Pavement_Name']
        verbose_name_plural = "Pavements"
Пример #5
0
class Language(CulturalModel):
    """
    family

    aliases (comma separated)
    total_schools

    avg_hrs_wk_languages_in_school

    ece_programs
    avg_hrs_wk_languages_in_ece
    language_nests
    avg_hrs_wk_languages_in_language_nests
    community_adult_language_classes
    language_audio (should include speaker, recorder, date recorded fields)
    greeting_audio (should include speaker, recorder, date recorded fields)
    fv_guid
    fv_url
    """

    family = models.ForeignKey(LanguageFamily,
                               null=True,
                               on_delete=models.SET_NULL,
                               blank=True)
    total_schools = models.IntegerField(default=0)
    avg_hrs_wk_languages_in_school = models.FloatField(default=0)
    ece_programs = models.IntegerField(default=0)
    avg_hrs_wk_languages_in_ece = models.FloatField(default=0)
    language_nests = models.IntegerField(default=0)
    avg_hrs_wk_languages_in_language_nests = models.FloatField(default=0)
    community_adult_language_classes = models.IntegerField(default=0)
    language_audio = models.ForeignKey(
        Recording,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="languages",
    )
    greeting_audio = models.ForeignKey(
        Recording,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="greeting_languages",
    )
    fv_guid = models.CharField(max_length=40, blank=True, default="")
    fv_archive_link = models.URLField(max_length=255, blank=True, default="")

    color = models.CharField(max_length=31, default="")
    regions = models.CharField(max_length=255, default="", blank=True)
    sleeping = models.BooleanField(default=False)

    notes = models.TextField(default="", blank=True)

    # Deprecated (switch to CommunityLanguageStats)
    fluent_speakers = models.IntegerField(
        default=0)  # sum of field_tm_lna2_on_fluent_sum_value
    some_speakers = models.IntegerField(
        default=0)  # field_tm_lna2_on_some_sum_value
    learners = models.IntegerField(
        default=0)  # sum of field_tm_lna2_on_lrn_sum_value
    pop_total_value = models.IntegerField(
        default=0)  # sum of field_tm_lna2_pop_total_value

    geom = models.PolygonField(null=True, default=None, blank=True)
    bbox = models.PolygonField(null=True, default=None, blank=True)

    # Deprecated, use recording instead.
    audio_file = models.FileField(null=True, blank=True)
Пример #6
0
class TrailSection(models.Model):
    objectid = models.IntegerField(null=True, blank=True)
    trailsection_id = models.AutoField(primary_key=True)
    shape = models.GeometryField(null=True, blank=True, srid=4326, dim=3)
    hikster_creation = models.IntegerField(null=True, blank=True)
    # 2017/07/11 Matty: in_trail field was used to decide which trail section should be shown on Map
    # in_trail = models.IntegerField(default=0)
    """
    2017/07/11 Matty Wang
    Changes made to Trail Section Model due to Hikster decision of implementing DB level triggers as Geotrek
    to automatically split/merge paths
    Geotrek is an open source project: https://github.com/GeotrekCE/Geotrek-admin

    older entries that existed before adding date_insert and date_update were given default value of the date
    when the new model is implemented
    """

    date_insert = models.DateTimeField(auto_now_add=True, editable=False)
    date_update = models.DateTimeField(auto_now=True, editable=False)
    departure = models.CharField(null=True,
                                 blank=True,
                                 default="",
                                 max_length=250)
    arrival = models.CharField(null=True,
                               blank=True,
                               default="",
                               max_length=250)
    valid = models.BooleanField(default=True)
    visible = models.BooleanField(default=True)
    name = models.CharField(null=True, blank=True, max_length=20)
    comments = models.TextField(null=True, blank=True)
    # external_id was introduced here because it appeared in Geotrek's triggers; not sure yet how relevant it is for us
    external_id = models.CharField(max_length=128, blank=True, null=True)
    shape_2d = models.LineStringField(blank=True,
                                      null=True,
                                      srid=4326,
                                      dim=2,
                                      spatial_index=False)
    ascent = models.IntegerField(default=0, null=True,
                                 blank=True)  # denivellee_positive
    descent = models.IntegerField(default=0, null=True,
                                  blank=True)  # denivellee_negative
    min_elevation = models.IntegerField(default=0, null=True,
                                        blank=True)  # altitude_minimum
    max_elevation = models.IntegerField(default=0, null=True,
                                        blank=True)  # altitude_maximum
    slope = models.FloatField(null=True, blank=True, default=0.0)  # pente
    lgth = models.FloatField(default=0.0, null=True, blank=True)
    trailsection_activities_uuid = models.CharField(max_length=60,
                                                    null=True,
                                                    blank=True)

    objects_with_eager_loading = TrailSectionManager()
    objects = models.Manager()

    def __str__(self):
        return f"{self.trailsection_id} - {self.name}"

    @property
    def activity_ids(self):
        return self.activities.values_list("activity__id", flat=True)
Пример #7
0
class Trip(models.Model):
    """Jízdy"""
    DIRECTIONS = [
        ('trip_to', _(u"Tam")),
        ('trip_from', _(u"Zpět")),
        ('recreational', _(u"Výlet")),
    ]
    DIRECTIONS_DICT = dict(DIRECTIONS)

    class Meta:
        verbose_name = _("Jízda")
        verbose_name_plural = _("Jízdy")
        unique_together = (("user_attendance", "date", "direction"),)
        ordering = ('date', '-direction')
    objects = BulkUpdateManager()

    user_attendance = models.ForeignKey(
        'UserAttendance',
        related_name="user_trips",
        null=True,
        blank=False,
        default=None,
        on_delete=models.CASCADE,
    )
    direction = models.CharField(
        verbose_name=_(u"Směr cesty"),
        choices=DIRECTIONS,
        max_length=20,
        default=None,
        null=False,
        blank=False,
    )
    date = models.DateField(
        verbose_name=_(u"Datum cesty"),
        default=datetime.date.today,
        null=False,
    )
    commute_mode = models.ForeignKey(
        'CommuteMode',
        verbose_name=_("Dopravní prostředek"),
        on_delete=models.CASCADE,
        default=1,
        null=False,
        blank=False,
    )
    track = models.MultiLineStringField(
        verbose_name=_(u"trasa"),
        help_text=MAP_DESCRIPTION,
        srid=4326,
        null=True,
        blank=True,
        geography=True,
    )
    gpx_file = models.FileField(
        verbose_name=_(u"GPX soubor"),
        help_text=_(
            mark_safe(
                "Zadat trasu nahráním souboru GPX. "
                "Pro vytvoření GPX souboru s trasou můžete použít vyhledávání na naší "
                "<a href='https://mapa.prahounakole.cz/#hledani' target='_blank'>mapě</a>."
            ),
        ),
        upload_to=normalize_gpx_filename,
        blank=True,
        null=True,
        max_length=512,
    )
    distance = models.FloatField(
        verbose_name=_(u"Ujetá vzdálenost (km)"),
        null=True,
        blank=True,
        default=None,
        validators=[
            MaxValueValidator(1000),
            MinValueValidator(0),
        ],
    )
    duration = models.PositiveIntegerField(
        verbose_name=_("Doba v sekundách"),
        null=True,
        blank=True,
    )
    from_application = models.BooleanField(
        verbose_name=_(u"Nahráno z aplikace"),
        default=False,
        null=False,
    )
    source_application = models.CharField(
        verbose_name=_("Zdrojová aplikace"),
        max_length=255,
        null=True,
        blank=True,
    )
    source_id = models.CharField(
        verbose_name=_("Identifikátor v původní aplikaci"),
        max_length=255,
        null=True,
        blank=True,
    )
    created = models.DateTimeField(
        verbose_name=_(u"Datum vytvoření"),
        auto_now_add=True,
        null=True,
    )
    updated = models.DateTimeField(
        verbose_name=_(u"Datum poslední změny"),
        auto_now=True,
        null=True,
    )

    def active(self):
        return self.user_attendance.campaign.day_active(self.date)

    def get_commute_mode_display(self):
        if self.commute_mode.slug == 'no_work' and self.date > util.today():
            return _('Dovolená')
        return str(self.commute_mode)

    def get_direction_display(self):
        return self.DIRECTIONS_DICT[self.direction]

    def get_application_link(self):
        app_links = {
            "strava": "https://www.strava.com/",
            "urbancyclers": "https://play.google.com/store/apps/details?id=com.umotional.bikeapp",
            "SuperLife": "https://play.google.com/store/apps/details?id=cz.cncenter.superlife",
        }
        if self.source_application in app_links:
            return app_links[self.source_application]

    def get_trip_link(self):
        if self.source_application == 'strava':
            return "<a href='%sactivities/%s'>View on Strava</a>" % (self.get_application_link(), self.source_id)
        return ""
Пример #8
0
class Trek(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Topology):
    topo_object = models.OneToOneField(Topology, parent_link=True,
                                       db_column='evenement')
    departure = models.CharField(verbose_name=_(u"Departure"), max_length=128, blank=True,
                                 help_text=_(u"Departure description"), db_column='depart')
    arrival = models.CharField(verbose_name=_(u"Arrival"), max_length=128, blank=True,
                               help_text=_(u"Arrival description"), db_column='arrivee')
    description_teaser = models.TextField(verbose_name=_(u"Description teaser"), blank=True,
                                          help_text=_(u"A brief summary (map pop-ups)"), db_column='chapeau')
    description = models.TextField(verbose_name=_(u"Description"), blank=True, db_column='description',
                                   help_text=_(u"Complete description"))
    ambiance = models.TextField(verbose_name=_(u"Ambiance"), blank=True, db_column='ambiance',
                                help_text=_(u"Main attraction and interest"))
    access = models.TextField(verbose_name=_(u"Access"), blank=True, db_column='acces',
                              help_text=_(u"Best way to go"))
    disabled_infrastructure = models.TextField(verbose_name=_(u"Disabled infrastructure"), db_column='handicap',
                                               blank=True, help_text=_(u"Any specific infrastructure"))
    duration = models.FloatField(verbose_name=_(u"Duration"), default=0, blank=True, db_column='duree',
                                 help_text=_(u"In hours (1.5 = 1 h 30, 24 = 1 day, 48 = 2 days)"),
                                 validators=[MinValueValidator(0)])
    is_park_centered = models.BooleanField(verbose_name=_(u"Is in the midst of the park"), db_column='coeur',
                                           help_text=_(u"Crosses center of park"))
    advised_parking = models.CharField(verbose_name=_(u"Advised parking"), max_length=128, blank=True, db_column='parking',
                                       help_text=_(u"Where to park"))
    parking_location = models.PointField(verbose_name=_(u"Parking location"), db_column='geom_parking',
                                         srid=settings.SRID, spatial_index=False, blank=True, null=True)
    public_transport = models.TextField(verbose_name=_(u"Public transport"), blank=True, db_column='transport',
                                        help_text=_(u"Train, bus (see web links)"))
    advice = models.TextField(verbose_name=_(u"Advice"), blank=True, db_column='recommandation',
                              help_text=_(u"Risks, danger, best period, ..."))
    themes = models.ManyToManyField(Theme, related_name="treks",
                                    db_table="o_r_itineraire_theme", blank=True, null=True, verbose_name=_(u"Themes"),
                                    help_text=_(u"Main theme(s)"))
    networks = models.ManyToManyField('TrekNetwork', related_name="treks",
                                      db_table="o_r_itineraire_reseau", blank=True, null=True, verbose_name=_(u"Networks"),
                                      help_text=_(u"Hiking networks"))
    practice = models.ForeignKey('Practice', related_name="treks",
                                 blank=True, null=True, verbose_name=_(u"Practice"), db_column='pratique')
    accessibilities = models.ManyToManyField('Accessibility', related_name="treks",
                                             db_table="o_r_itineraire_accessibilite", blank=True, null=True,
                                             verbose_name=_(u"Accessibility"))
    route = models.ForeignKey('Route', related_name='treks',
                              blank=True, null=True, verbose_name=_(u"Route"), db_column='parcours')
    difficulty = models.ForeignKey('DifficultyLevel', related_name='treks',
                                   blank=True, null=True, verbose_name=_(u"Difficulty"), db_column='difficulte')
    web_links = models.ManyToManyField('WebLink', related_name="treks",
                                       db_table="o_r_itineraire_web", blank=True, null=True, verbose_name=_(u"Web links"),
                                       help_text=_(u"External resources"))
    related_treks = models.ManyToManyField('self', through='TrekRelationship',
                                           verbose_name=_(u"Related treks"), symmetrical=False,
                                           help_text=_(u"Connections between treks"),
                                           related_name='related_treks+')  # Hide reverse attribute
    information_desks = models.ManyToManyField(tourism_models.InformationDesk, related_name='treks',
                                               db_table="o_r_itineraire_renseignement", blank=True, null=True,
                                               verbose_name=_(u"Information desks"),
                                               help_text=_(u"Where to obtain information"))
    points_reference = models.MultiPointField(verbose_name=_(u"Points of reference"), db_column='geom_points_reference',
                                              srid=settings.SRID, spatial_index=False, blank=True, null=True)
    source = models.ManyToManyField('common.RecordSource',
                                    blank=True, related_name='treks',
                                    verbose_name=_("Source"), db_table='o_r_itineraire_source')
    portal = models.ManyToManyField('common.TargetPortal',
                                    blank=True, related_name='treks',
                                    verbose_name=_("Portal"), db_table='o_r_itineraire_portal')
    eid = models.CharField(verbose_name=_(u"External id"), max_length=128, blank=True, null=True, db_column='id_externe')
    eid2 = models.CharField(verbose_name=_(u"Second external id"), max_length=128, blank=True, null=True, db_column='id_externe2')

    objects = Topology.get_manager_cls(models.GeoManager)()

    category_id_prefix = 'T'
    capture_map_image_waitfor = '.poi_enum_loaded.services_loaded.info_desks_loaded.ref_points_loaded'

    class Meta:
        db_table = 'o_t_itineraire'
        verbose_name = _(u"Trek")
        verbose_name_plural = _(u"Treks")
        ordering = ['name']

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_map_image_url(self):
        return ('trekking:trek_map_image', [], {'pk': str(self.pk), 'lang': get_language()})

    def get_map_image_path(self):
        basefolder = os.path.join(settings.MEDIA_ROOT, 'maps')
        if not os.path.exists(basefolder):
            os.makedirs(basefolder)
        return os.path.join(basefolder, '%s-%s-%s.png' % (self._meta.module_name, self.pk, get_language()))

    @models.permalink
    def get_document_public_url(self):
        """ Override ``geotrek.common.mixins.PublishableMixin``
        """
        return ('trekking:trek_document_public', [], {'lang': get_language(), 'pk': self.pk, 'slug': self.slug})

    @property
    def related(self):
        return self.related_treks.exclude(deleted=True).exclude(pk=self.pk).distinct()

    @classproperty
    def related_verbose_name(cls):
        return _("Related treks")

    @property
    def relationships(self):
        # Does not matter if a or b
        return TrekRelationship.objects.filter(trek_a=self)

    @property
    def published_relationships(self):
        return self.relationships.filter(trek_b__published=True)

    @property
    def poi_types(self):
        if settings.TREKKING_TOPOLOGY_ENABLED:
            # Can't use values_list and must add 'ordering' because of bug:
            # https://code.djangoproject.com/ticket/14930
            values = self.pois.values('ordering', 'type')
        else:
            values = self.pois.values('type')
        pks = [value['type'] for value in values]
        return POIType.objects.filter(pk__in=set(pks))

    @property
    def length_kilometer(self):
        return "%.1f" % (self.length / 1000.0)

    @property
    def networks_display(self):
        return ', '.join([unicode(n) for n in self.networks.all()])

    @property
    def districts_display(self):
        return ', '.join([unicode(d) for d in self.districts])

    @property
    def themes_display(self):
        return ', '.join([unicode(n) for n in self.themes.all()])

    @property
    def city_departure(self):
        cities = self.cities
        return unicode(cities[0]) if len(cities) > 0 else ''

    def kml(self):
        """ Exports trek into KML format, add geometry as linestring and POI
        as place marks """
        kml = simplekml.Kml()
        # Main itinerary
        geom3d = self.geom_3d.transform(4326, clone=True)  # KML uses WGS84
        line = kml.newlinestring(name=self.name,
                                 description=plain_text(self.description),
                                 coords=geom3d.coords)
        line.style.linestyle.color = simplekml.Color.red  # Red
        line.style.linestyle.width = 4  # pixels
        # Place marks
        for poi in self.pois:
            place = poi.geom_3d.transform(settings.API_SRID, clone=True)
            kml.newpoint(name=poi.name,
                         description=plain_text(poi.description),
                         coords=[place.coords])
        return kml.kml()

    def has_geom_valid(self):
        """A trek should be a LineString, even if it's a loop.
        """
        return super(Trek, self).has_geom_valid() and self.geom.geom_type.lower() == 'linestring'

    @property
    def duration_pretty(self):
        return trekking_tags.duration(self.duration)

    @classproperty
    def duration_pretty_verbose_name(cls):
        return _("Formated duration")

    @classmethod
    def path_treks(cls, path):
        treks = cls.objects.existing().filter(aggregations__path=path)
        # The following part prevents conflict with default trek ordering
        # ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
        return treks.order_by('topo_object').distinct('topo_object')

    @classmethod
    def topology_treks(cls, topology):
        if settings.TREKKING_TOPOLOGY_ENABLED:
            qs = cls.overlapping(topology)
        else:
            area = topology.geom.buffer(settings.TREK_POI_INTERSECTION_MARGIN)
            qs = cls.objects.existing().filter(geom__intersects=area)
        return qs

    @classmethod
    def published_topology_treks(cls, topology):
        return cls.topology_treks(topology).filter(published=True)

    # Rando v1 compat
    @property
    def usages(self):
        return [self.practice] if self.practice else []

    @classmethod
    def get_create_label(cls):
        return _(u"Add a new trek")

    @property
    def parents(self):
        return Trek.objects.filter(trek_children__child=self, deleted=False)

    @property
    def parents_id(self):
        parents = self.trek_parents.values_list('parent__id', flat=True)
        return list(parents)

    @property
    def children(self):
        return Trek.objects.filter(trek_parents__parent=self, deleted=False).order_by('trek_parents__order')

    @property
    def children_id(self):
        """
        Get children IDs
        """
        children = self.trek_children.order_by('order')\
                                     .values_list('child__id',
                                                  flat=True)
        return list(children)

    def previous_id_for(self, parent):
        children_id = parent.children_id
        index = children_id.index(self.id)
        if index == 0:
            return None
        return children_id[index - 1]

    def next_id_for(self, parent):
        children_id = parent.children_id
        index = children_id.index(self.id)
        if index == len(children_id) - 1:
            return None
        return children_id[index + 1]

    @property
    def previous_id(self):
        """
        Dict of parent -> previous child
        """
        return {parent.id: self.previous_id_for(parent) for parent in self.parents.filter(published=True, deleted=False)}

    @property
    def next_id(self):
        """
        Dict of parent -> next child
        """
        return {parent.id: self.next_id_for(parent) for parent in self.parents.filter(published=True, deleted=False)}

    def clean(self):
        """
        Custom model validation
        """
        if self.pk in self.trek_children.values_list('child__id', flat=True):
            raise ValidationError(_(u"Cannot use itself as child trek."))

    @property
    def prefixed_category_id(self):
        if settings.SPLIT_TREKS_CATEGORIES_BY_PRACTICE and self.practice:
            return '{prefix}{id}'.format(prefix=self.category_id_prefix, id=self.practice.id)
        else:
            return self.category_id_prefix

    def distance(self, to_cls):
        if self.practice and self.practice.distance is not None:
            return self.practice.distance
        else:
            return settings.TOURISM_INTERSECTION_MARGIN

    def is_public(self):
        for parent in self.parents:
            if parent.any_published:
                return True
        return self.any_published

    @property
    def picture_print(self):
        picture = super(Trek, self).picture_print
        if picture:
            return picture
        for poi in self.published_pois:
            picture = poi.picture_print
            if picture:
                return picture

    def save(self, *args, **kwargs):
        if self.pk is not None and kwargs.get('update_fields', None) is None:
            field_names = set()
            for field in self._meta.concrete_fields:
                if not field.primary_key and not hasattr(field, 'through'):
                    field_names.add(field.attname)
            old_trek = Trek.objects.get(pk=self.pk)
            if self.geom is not None and old_trek.geom.equals_exact(self.geom, tolerance=0.00001):
                field_names.remove('geom')
            if self.geom_3d is not None and old_trek.geom_3d.equals_exact(self.geom_3d, tolerance=0.00001):
                field_names.remove('geom_3d')
            return super(Trek, self).save(update_fields=field_names, *args, **kwargs)
        super(Trek, self).save(*args, **kwargs)

    @property
    def portal_display(self):
        return ', '.join([unicode(portal) for portal in self.portal.all()])

    @property
    def source_display(self):
        return ','.join([unicode(source) for source in self.source.all()])
Пример #9
0
class Campaign(Pricable, models.Model):
    """kampaň"""
    class Meta:
        verbose_name = _(u"kampaň")
        verbose_name_plural = _(u"kampaně")
        permissions = (("can_see_application_links",
                        "Can see application links"), )
        ordering = ('-id', )

    name = models.CharField(
        unique=True,
        verbose_name=_(u"Jméno kampaně"),
        max_length=60,
        null=False,
    )
    slug = models.SlugField(
        unique=True,
        verbose_name=u"Doména v URL",
        blank=False,
    )
    slug_identifier = models.SlugField(
        unique=True,
        verbose_name="Identifikátor kampaně",
        blank=True,
        null=True,
    )
    previous_campaign = models.ForeignKey(
        'Campaign',
        verbose_name=_(u"Předchozí kampaň"),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )
    email_footer = models.TextField(
        verbose_name=_(u"Patička uživatelských e-mailů"),
        default="",
        max_length=5000,
        null=True,
        blank=True,
    )
    mailing_list_id = models.CharField(
        verbose_name=_(u"ID mailing listu"),
        max_length=60,
        default="",
        blank=True,
        null=False,
    )
    show_application_links = models.BooleanField(
        verbose_name=_("Ukázat odkazy na aplikace"),
        default=False,
        null=False,
    )
    mailing_list_enabled = models.NullBooleanField(
        verbose_name=_(u"Povolit mailing list"),
        default=None,
        null=True,
        blank=True,
        unique=
        True,  # Enabling mailing lists on more campaigns cause problems. This prevents it until it is fixed.
    )
    extra_agreement_text = models.TextField(
        verbose_name=_("Další text pro uživatelské souhlas"),
        blank=True,
        default="",
    )
    days_active = models.PositiveIntegerField(
        verbose_name=_("Počet minulých dní, které jdou zapisovat"),
        default=7,
        blank=False,
        null=False,
    )
    minimum_rides_base = models.PositiveIntegerField(
        verbose_name=_(u"Minimální základ počtu jízd"),
        help_text=
        _(u"Minimální počet jízd, které je nutné si zapsat, aby bylo možné dosáhnout 100% jízd"
          ),
        default=25,
        blank=False,
        null=False,
    )
    minimum_percentage = models.PositiveIntegerField(
        verbose_name=_(
            u"Minimální procento pro kvalifikaci do pravidelnostní soutěže"),
        default=66,
        blank=False,
        null=False,
    )
    trip_plus_distance = models.PositiveIntegerField(
        verbose_name=_(u"Maximální navýšení vzdálenosti"),
        help_text=_(
            u"Počet kilometrů, o které je možné prodloužit si jednu jízdu"),
        default=5,
        blank=True,
        null=True,
    )
    tracking_number_first = models.PositiveIntegerField(
        verbose_name=_(u"První číslo řady pro doručování balíčků"),
        default=0,
        blank=False,
        null=False,
    )
    tracking_number_last = models.PositiveIntegerField(
        verbose_name=_(u"Poslední číslo řady pro doručování balíčků"),
        default=999999999,
        blank=False,
        null=False,
    )
    package_height = models.PositiveIntegerField(
        verbose_name=_(u"Výška balíku"),
        default=1,
        blank=True,
        null=True,
    )
    package_width = models.PositiveIntegerField(
        verbose_name=_(u"Šířka balíku"),
        default=26,
        blank=True,
        null=True,
    )
    package_depth = models.PositiveIntegerField(
        verbose_name=_(u"Hloubka balíku"),
        default=35,
        blank=True,
        null=True,
    )
    package_max_count = models.PositiveIntegerField(
        verbose_name=_("Maximální počet triček v krabici"),
        default=50,
        blank=True,
        null=True,
    )
    package_weight = models.FloatField(
        verbose_name=_(u"Váha balíku"),
        null=True,
        blank=True,
        default=0.25,
        validators=[
            MaxValueValidator(1000),
            MinValueValidator(0),
        ],
    )
    invoice_sequence_number_first = models.PositiveIntegerField(
        verbose_name=_(u"První číslo řady pro faktury"),
        default=1,
        blank=False,
        null=False,
    )
    invoice_sequence_number_last = models.PositiveIntegerField(
        verbose_name=_(u"Poslední číslo řady pro faktury"),
        default=999999999,
        blank=False,
        null=False,
    )
    benefitial_admission_fee = models.FloatField(
        verbose_name=_(u"Benefiční startovné"),
        null=False,
        default=0,
    )
    benefitial_admission_fee_company = models.FloatField(
        verbose_name=_(u"Benefiční startovné pro organizace"),
        null=False,
        default=0,
    )
    free_entry_cases_html = models.TextField(
        verbose_name=_(u"Případy, kdy je startovné zdarma"),
        null=True,
        blank=True,
    )
    club_membership_integration = models.BooleanField(
        verbose_name=_("Povolit integraci s klubem přátel?"),
        default=True,
    )
    track_required = models.BooleanField(
        verbose_name=_("Je povinné zadávat trasu"),
        default=True,
        null=False,
    )
    tracks = models.BooleanField(
        verbose_name=_("Umožnit soutěžícím uložit trasu?"),
        default=True,
    )
    recreational = models.BooleanField(
        verbose_name=_("Lze zadávat i výlety"),
        default=False,
    )
    wp_api_url = models.URLField(
        default="http://www.dopracenakole.cz",
        verbose_name=_("Adresa pro Wordpress API se články"),
        null=True,
        blank=True,
    )
    wp_api_date_from = models.DateField(
        verbose_name=_(
            "Datum, od kterého se zobrazují příspěvky z Wordpress API se články"
        ),
        null=True,
        blank=True,
    )
    web = models.URLField(
        verbose_name=_("Web kampáně"),
        default="http://www.dopracenakole.cz",
        blank=True,
    )
    contact_email = models.CharField(
        verbose_name=_("Kontaktní e-mail"),
        default="*****@*****.**",
        max_length=80,
        blank=False,
    )
    sitetree_postfix = models.CharField(
        verbose_name=_("Postfix pro menu"),
        max_length=60,
        null=False,
        blank=True,
        default="",
    )

    LANGUAGE_PREFIXES = [
        ('dpnk', _("Do práce na kole")),
        ('dsnk', _("Do školy na kole")),
    ]
    language_prefixes = models.CharField(
        verbose_name=_("Jazyková sada"),
        choices=LANGUAGE_PREFIXES,
        max_length=16,
        null=False,
        blank=False,
        default='dpnk',
    )
    max_team_members = models.PositiveIntegerField(
        verbose_name=_("Počet lidí v týmu"),
        default=5,
        blank=True,
        null=True,
    )

    sandwich_type = models.ForeignKey(
        PdfSandwichType,
        null=True,
        blank=True,
        default='',
        on_delete=models.SET_NULL,
    )
    team_diploma_sandwich_type = models.ForeignKey(
        PdfSandwichType,
        related_name='team_diploma_campaign',
        null=True,
        blank=True,
        default='',
        on_delete=models.SET_NULL,
    )

    def sitetree_postfix_maintree(self):
        if self.sitetree_postfix:
            return "maintree_%s" % self.sitetree_postfix
        else:
            return "maintree"

    def __str__(self):
        return self.name

    def competitors_choose_team(self):
        return self.max_team_members > 1

    def too_much_members(self, member_count):
        if self.max_team_members is None:
            return False
        return member_count > self.max_team_members

    def day_active(self, day):
        """ Return if this day can be changed by user """
        day_today = util.today()
        try:
            entry_phase = self.phase('entry_enabled')
            if not entry_phase.is_actual():
                return False
        except Phase.DoesNotExist:
            pass
        return ((day <= day_today) and
                (day > day_today - datetime.timedelta(days=self.days_active)))

    def vacation_day_active(self, day):
        """ Return if this day can be added as vacation """
        day_today = util.today()
        last_day = self.competition_phase().date_to
        return ((day <= last_day) and (day > day_today))

    def possible_vacation_days(self):
        """ Return days, that can be added as vacation """
        competition_phase = self.competition_phase()
        return [
            d for d in util.daterange(competition_phase.date_from,
                                      competition_phase.date_to)
            if self.vacation_day_active(d)
        ]

    def user_attendances_for_delivery(self):
        from t_shirt_delivery.models import PackageTransaction
        return UserAttendance.objects.filter(
            campaign=self,
            payment_status__in=('done', 'no_admission'),
            t_shirt_size__ship=True,
        ).exclude(
            transactions__packagetransaction__status__in=PackageTransaction.
            shipped_statuses, ).exclude(team=None, ).annotate(
                payment_created=Max('transactions__payment__created'),
            ).order_by('payment_created', ).distinct()

    def get_directions(self):
        if self.recreational:
            return ('trip_to', 'trip_from', 'recreational')
        else:
            return ('trip_to', 'trip_from')

    @denormalized(models.BooleanField, default=True)
    @depend_on_related('t_shirt_delivery.TShirtSize',
                       type='backward',
                       foreign_key='campaign')
    def has_any_tshirt(self):
        return self.tshirtsize_set.exists()

    def phase(self, phase_type):
        """
        Return phase of given type from this campaign.
        @phase_type Type of phase.
        """
        @cached(60)
        def get_phase(pk, phase_type):
            return self.phase_set.get(phase_type=phase_type)

        return get_phase(self.pk, phase_type)

    def competition_phase(self):
        return self.phase('competition')
Пример #10
0
class Campaign(Pricable, models.Model):
    """kampaň"""

    class Meta:
        verbose_name = _("kampaň")
        verbose_name_plural = _("kampaně")
        permissions = (("can_see_application_links", "Can see application links"),)
        ordering = ("-id",)
        unique_together = [
            ("mailing_list_type", "mailing_list_id"),
            ("campaign_type", "year"),
        ]

    campaign_type = models.ForeignKey(
        "CampaignType",
        verbose_name=_("Typ kampaně"),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="campaigns",
    )
    year = models.CharField(
        unique=False,
        verbose_name=_("Ročník kampaně"),
        max_length=60,
        null=False,
        default=datetime.datetime.now().year,
    )
    slug = models.SlugField(
        unique=True,
        verbose_name="Doména v URL",
        blank=False,
    )
    slug_identifier = models.SlugField(
        unique=True,
        verbose_name="Identifikátor kampaně",
        blank=True,
        null=True,
    )
    previous_campaign = models.ForeignKey(
        "Campaign",
        verbose_name=_("Předchozí kampaň"),
        help_text=_(
            "Kampaň, ze které se přebírá velikost trička, nazev týmu atd... při vytváření nové účasti v kampani"
        ),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )
    email_footer = models.TextField(
        verbose_name=_("Patička uživatelských e-mailů"),
        default="",
        max_length=5000,
        null=True,
        blank=True,
    )
    mailing_list_id = models.CharField(
        verbose_name=_("ID mailing listu"),
        max_length=60,
        default="",
        blank=True,
        null=False,
    )
    mailing_list_type = models.CharField(
        verbose_name=_("ID mailing listu"),
        choices=[
            (None, _("Disabled")),
            ("campaign_monitor", _("Campaign monitor")),
            ("ecomail", _("EcoMail")),
        ],
        max_length=60,
        default=None,
        blank=True,
        null=True,
    )
    show_application_links = models.BooleanField(
        verbose_name=_("Ukázat odkazy na aplikace"),
        default=False,
        null=False,
    )
    mailing_list_enabled = models.NullBooleanField(
        verbose_name=_("Povolit mailing list"),
        default=None,
        null=True,
        blank=True,
        unique=True,  # Enabling mailing lists on more campaigns cause problems. This prevents it until it is fixed.
    )
    extra_agreement_text = models.TextField(
        verbose_name=_("Další text pro uživatelské souhlas"),
        blank=True,
        default="",
    )
    days_active = models.PositiveIntegerField(
        verbose_name=_("Počet minulých dní, které jdou zapisovat"),
        default=7,
        blank=False,
        null=False,
    )
    minimum_rides_base = models.PositiveIntegerField(
        verbose_name=_("Minimální základ počtu jízd"),
        help_text=_(
            "Minimální počet jízd, které je nutné si zapsat, aby bylo možné dosáhnout 100% jízd"
        ),
        default=25,
        blank=False,
        null=False,
    )
    minimum_percentage = models.PositiveIntegerField(
        verbose_name=_("Minimální procento pro kvalifikaci do pravidelnostní soutěže"),
        default=66,
        blank=False,
        null=False,
    )
    trip_plus_distance = models.PositiveIntegerField(
        verbose_name=_("Maximální navýšení vzdálenosti"),
        help_text=_("Počet kilometrů, o které je možné prodloužit si jednu jízdu"),
        default=5,
        blank=True,
        null=True,
    )
    tracking_number_first = models.PositiveIntegerField(
        verbose_name=_("První číslo řady pro doručování balíčků"),
        default=0,
        blank=False,
        null=False,
    )
    tracking_number_last = models.PositiveIntegerField(
        verbose_name=_("Poslední číslo řady pro doručování balíčků"),
        default=999999999,
        blank=False,
        null=False,
    )
    package_height = models.PositiveIntegerField(
        verbose_name=_("Výška balíku"),
        default=1,
        blank=True,
        null=True,
    )
    package_width = models.PositiveIntegerField(
        verbose_name=_("Šířka balíku"),
        default=26,
        blank=True,
        null=True,
    )
    package_depth = models.PositiveIntegerField(
        verbose_name=_("Hloubka balíku"),
        default=35,
        blank=True,
        null=True,
    )
    package_max_count = models.PositiveIntegerField(
        verbose_name=_("Maximální počet triček v krabici"),
        default=50,
        blank=True,
        null=True,
    )
    package_weight = models.FloatField(
        verbose_name=_("Váha balíku"),
        null=True,
        blank=True,
        default=0.25,
        validators=[
            MaxValueValidator(1000),
            MinValueValidator(0),
        ],
    )
    invoice_sequence_number_first = models.PositiveIntegerField(
        verbose_name=_("První číslo řady pro faktury"),
        default=1,
        blank=False,
        null=False,
    )
    invoice_sequence_number_last = models.PositiveIntegerField(
        verbose_name=_("Poslední číslo řady pro faktury"),
        default=999999999,
        blank=False,
        null=False,
    )
    benefitial_admission_fee = models.FloatField(
        verbose_name=_("Benefiční startovné"),
        null=False,
        default=0,
    )
    benefitial_admission_fee_company = models.FloatField(
        verbose_name=_("Benefiční startovné pro organizace"),
        null=False,
        default=0,
    )
    free_entry_cases_html = models.TextField(
        verbose_name=_("Případy, kdy je startovné zdarma"),
        null=True,
        blank=True,
    )
    club_membership_integration = models.BooleanField(
        verbose_name=_("Povolit integraci s klubem přátel?"),
        default=True,
    )
    track_required = models.BooleanField(
        verbose_name=_("DEPRECATED"),
        default=False,
        null=False,
    )
    tracks = models.BooleanField(
        verbose_name=_("Umožnit soutěžícím uložit trasu?"),
        default=True,
    )
    recreational = models.BooleanField(
        verbose_name=_("Lze zadávat i výlety"),
        default=False,
    )
    wp_api_date_from = models.DateField(
        verbose_name=_(
            "Datum, od kterého se zobrazují příspěvky z Wordpress API se články"
        ),
        null=True,
        blank=True,
    )
    max_team_members = models.PositiveIntegerField(
        verbose_name=_("Počet lidí v týmu"),
        default=5,
        blank=True,
        null=True,
    )

    sandwich_type = models.ForeignKey(
        PdfSandwichType,
        null=True,
        blank=True,
        default="",
        on_delete=models.SET_NULL,
    )
    team_diploma_sandwich_type = models.ForeignKey(
        PdfSandwichType,
        related_name="team_diploma_campaign",
        null=True,
        blank=True,
        default="",
        on_delete=models.SET_NULL,
    )
    city_in_campaign_diploma_sandwich_type = models.ForeignKey(
        PdfSandwichType,
        related_name="city_in_campaign_diploma_campaign",
        null=True,
        blank=True,
        default="",
        on_delete=models.SET_NULL,
    )

    def display_name(self):
        if self.name:
            return self.name
        if self.campaign_type is None:
            return "No campaign type " + str(self.year)
        return self.campaign_type.name + " " + str(self.year)

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

    def tagline(self):
        return self.campaign_type.tagline % str(self.year)

    def competitors_choose_team(self):
        return self.max_team_members > 1

    def too_much_members(self, member_count):
        if self.max_team_members is None:
            return False
        return member_count > self.max_team_members

    def active(self):
        return self.day_active(util.today())

    def entry_enabled_end(self):
        return self.phase("entry_enabled").date_to

    def day_active(self, day, day_today=None):
        """Return if this day can be changed by user"""
        try:
            entry_phase = self.phase("entry_enabled")
            if not entry_phase.is_actual():
                return False
        except Phase.DoesNotExist:
            pass
        competition_phase = self.phase("competition")
        return self.day_recent(day, day_today) and competition_phase.day_in_phase(day)

    def day_recent(self, day, day_today=None):
        """
        Returns true if the current day is today or in the recent past. Recent beting defined by "campaign.days_active".
        """
        if day_today is None:
            day_today = util.today()
        return (day <= day_today) and (
            day > self._first_possibly_active_day(day_today=day_today)
        )

    def _first_possibly_active_day(self, day_today=None):
        if day_today is None:
            day_today = util.today()
        return day_today - datetime.timedelta(days=self.days_active)

    def vacation_day_active(self, day):
        """Return if this day can be added as vacation"""
        day_today = util.today()
        last_day = self.competition_phase().date_to
        return (day <= last_day) and (day > day_today)

    def possible_vacation_days(self):
        """Return days, that can be added as vacation"""

        @cached(60)
        def get_days(pk):
            competition_phase = self.competition_phase()
            return [
                d
                for d in util.daterange(
                    competition_phase.date_from, competition_phase.date_to
                )
                if self.vacation_day_active(d)
            ]

        return get_days(self.pk)

    def user_attendances_for_delivery(self):
        from t_shirt_delivery.models import PackageTransaction

        return (
            UserAttendance.objects.filter(
                campaign=self,
                payment_status__in=("done", "no_admission"),
                t_shirt_size__ship=True,
            )
            .exclude(
                transactions__packagetransaction__status__in=PackageTransaction.shipped_statuses,
            )
            .exclude(
                team=None,
            )
            .annotate(
                payment_created=Max("transactions__payment__created"),
            )
            .order_by(
                "payment_created",
            )
            .distinct()
        )

    def get_complementary_school_campaign(self):
        @cached(60)
        def get_campaign(pk):
            try:
                return Campaign.objects.get(year=self.year, campaign_type__slug="skoly")
            except Campaign.DoesNotExist:
                return None

        return get_campaign(self.pk)

    def get_complementary_main_campaign(self):
        try:
            return Campaign.objects.get(year=self.year, campaign_type__slug="dpnk")
        except Campaign.DoesNotExist:
            return None

    def get_base_url(self, request=None):
        return util.get_base_url(request, self.slug)

    def get_directions(self):
        if self.recreational:
            return ("trip_to", "trip_from", "recreational")
        else:
            return ("trip_to", "trip_from")

    @denormalized(models.BooleanField, default=True)
    @depend_on_related(
        "t_shirt_delivery.TShirtSize", type="backward", foreign_key="campaign"
    )
    def has_any_tshirt(self):
        return self.tshirtsize_set.exists()

    def phase(self, phase_type):
        """
        Return phase of given type from this campaign.
        @phase_type Type of phase.
        """

        @cached(60)
        def get_phase(pk, phase_type):
            try:
                return self.phase_set.get(phase_type=phase_type)
            except Phase.DoesNotExist:
                return False

        result = get_phase(self.pk, phase_type)
        if not result:
            get_phase.invalidate(self.pk, phase_type)
            raise Phase.DoesNotExist
        return result

    def competition_phase(self):
        return self.phase("competition")

    #############################################
    # DEPRECATED ################################
    #############################################
    name = models.CharField(
        unique=False,
        verbose_name=_("Deprecated: Jméno kampaně"),
        max_length=60,
        null=True,
    )
    wp_api_url = models.URLField(
        default="http://www.dopracenakole.cz",
        verbose_name=_("Deprecated: Adresa pro Wordpress API se články"),
        null=True,
        blank=True,
    )
    web = models.URLField(
        verbose_name=_("Deprecated: Web kampáně"),
        default="http://www.dopracenakole.cz",
        blank=True,
        null=True,
    )
    contact_email = models.CharField(
        verbose_name=_("Deprecated: Kontaktní e-mail"),
        default="*****@*****.**",
        max_length=80,
        blank=True,
        null=True,
    )
    sitetree_postfix = models.CharField(
        verbose_name=_("Deprecated: Postfix pro menu"),
        max_length=60,
        null=True,
        blank=True,
        default="",
    )

    LANGUAGE_PREFIXES = [
        ("dpnk", _("Do práce na kole")),
        ("dsnk", _("Do školy na kole")),
    ]
    language_prefixes = models.CharField(
        verbose_name=_("Deprecated: Jazyková sada"),
        choices=LANGUAGE_PREFIXES,
        max_length=16,
        null=False,
        blank=False,
        default="dpnk",
    )
    main_color = ColorField(
        default="#1EA04F",
        verbose_name="Deprecated: Hlavní barva kampaně",
    )
Пример #11
0
class NHDLake(models.Model):
    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 __unicode__(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()
        results = 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])
        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,))
            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
Пример #12
0
class place(models.Model):
    city = models.CharField(max_length=50, blank=True, null=True)
    district = models.CharField(max_length=50, blank=True, null=True)
    street = models.CharField(max_length=50, blank=True, null=True)
    house = models.CharField(max_length=20, blank=True, null=True)
    lat = models.FloatField(blank=True, null=True)
    lon = models.FloatField(blank=True, null=True)

    def __unicode__(self):
        name = ''
        if self.city:
            name += self.city + ' '
        elif self.district:
            name += self.district + ' '
        elif self.street:
            name += self.street + ' '
        elif self.house:
            name += self.house + ' '
        return unicode(name)

    def es_repr(self):
        data = {}
        mapping = es_mappings[self.__class__.__name__]
        data['_id'] = self.pk
        for field_name in mapping['properties'].keys():
            data[field_name] = self.field_es_repr(field_name)
        return data

    def field_es_repr(self, field_name):
        mapping = es_mappings[self.__class__.__name__]
        config = mapping['properties'][field_name]

        field_es_value = getattr(self, field_name)

        return field_es_value

    @classmethod
    def get_es_index(cls):
        return model_es_indices[cls.__name__]['index_name']

    @classmethod
    def get_es_type(cls):
        return model_es_indices[cls.__name__]['type']

    @classmethod
    def es_search(cls,
                  term,
                  srch_fields=['city', 'district', 'street', 'house']):
        es = settings.ES_CLIENT
        query = cls.gen_query(term, srch_fields)
        print json.dumps(query, ensure_ascii=False)
        recs = []
        res = es.search(index=cls.get_es_index(),
                        doc_type=cls.get_es_type(),
                        body=query)
        if res['hits']['total'] > 0:
            print 'found %s' % res['hits']['total']
            ids = [c['_id'] for c in res['hits']['hits']]
            clauses = ' '.join(
                ['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(ids)])
            ordering = 'CASE %s END' % clauses
            recs = cls.objects.filter(id__in=ids).extra(
                select={'ordering': ordering}, order_by=('ordering', ))
            print recs[0]
        return recs

    @classmethod
    def gen_query(cls, term, srch_fields):
        val = term
        query = {
            "query": {
                "filtered": {
                    "query": {
                        "bool": {
                            "should": [{
                                "multi_match": {
                                    "type": "cross_fields",
                                    "fields": ["city"],
                                    "fuzziness": "AUTO",
                                    "query": term,
                                    "boost": 25
                                }
                            }, {
                                "multi_match": {
                                    "type": "cross_fields",
                                    "fields": ["district"],
                                    "fuzziness": "AUTO",
                                    "query": term,
                                    "boost": 25
                                }
                            }, {
                                "multi_match": {
                                    "type": "cross_fields",
                                    "fields": ["street"],
                                    "fuzziness": "AUTO",
                                    "query": term,
                                    "boost": 5
                                }
                            }, {
                                "multi_match": {
                                    "type": "cross_fields",
                                    "fields": ["house"],
                                    "query": term
                                }
                            }]
                        }
                    }
                }
            },
            "size": 10,
        }
        return json.dumps(query)
Пример #13
0
class Presentation(models.Model):
    """GP prescribing products. Import from BNF codes file from BSA.
    ADQs imported from BSA data.

    Where codes have changed or otherwise been mapped, the
    `replaced_by` field has a value.

    """

    bnf_code = models.CharField(
        max_length=15, primary_key=True, validators=[isAlphaNumeric]
    )
    name = models.CharField(max_length=200)
    is_generic = models.NullBooleanField(default=None)
    is_current = models.BooleanField(default=True)
    replaced_by = models.ForeignKey(
        "self", null=True, blank=True, on_delete=models.PROTECT
    )

    # An ADQ is the assumed average maintenance dose per day for a
    # drug used for its main indication in adults.
    #
    # If a presentation's ADQ is "20mg", and its `quantity` field is
    # measured in 10 mg tablets, then the `adq_per_quantity` whould be
    # 2.  In other words, `adq_per_quantity` is a factor to apply to
    # `quantity`, to obtain an ADQ.
    #
    # See https://github.com/ebmdatalab/openprescribing/issues/934 for
    # more detail
    adq_per_quantity = models.FloatField(null=True, blank=True)

    # Usually `quantity` measures something that comes *in* a pack e.g. "number
    # of tablets" or "number of ml of liquid". (Note this is "pack" in the DM+D
    # sense were a bottle and pump are both "packs"). Occasionally though,
    # `quantity` measures the number of packs itself. This field is set by the
    # `set_quantity_means_pack` management command and should not be modified
    # by anything else, especially not by hand.
    quantity_means_pack = models.NullBooleanField(default=None)

    # The name of the corresponding product (or product pack) in dm+d.  This
    # tends to be more user-friendly than the names in the BNF.  See
    # set_dmd_names in import_dmd command for details of how this is set.
    dmd_name = models.CharField(max_length=255, null=True)

    objects = PresentationManager()

    def __str__(self):
        return "%s: %s" % (self.bnf_code, self.product_name)

    def save(self, *args, **kwargs):
        if len(self.bnf_code) > 10:
            code = self.bnf_code[9:11]
            is_generic = code == "AA"
        else:
            is_generic = None
        self.is_generic = is_generic
        super(Presentation, self).save(*args, **kwargs)

    @property
    def current_version(self):
        """BNF codes are replaced over time.

        Return the most recent version the code.
        """
        version = self
        next_version = self.replaced_by
        seen = []
        while next_version:
            if next_version in seen:
                break  # avoid loops
            else:
                seen.append(next_version)
                version = next_version
                next_version = version.replaced_by
        return version

    def tariff_categories(self):
        """Return all tariff categories for this presentation."""
        vmpps = VMPP.objects.filter(bnf_code=self.bnf_code)
        return DtPaymentCategory.objects.filter(dtinfo__vmpp__in=vmpps).distinct()

    def tariff_categories_descr(self):
        """Return a description of the presentation's tariff category/ies."""
        return ", ".join(tc.descr for tc in self.tariff_categories())

    def availability_restrictions(self):
        """Return all availability restrictions for this presentation."""
        amps = AMP.objects.filter(bnf_code=self.bnf_code)
        return AvailabilityRestriction.objects.filter(amp__in=amps).distinct()

    def availability_restrictions_descr(self):
        """Return a description of the presentation's availabilty restriction/s.

        If any AMPs have "None" as their availability restriction, we
        consider that the presentation itself has no availability restriction.
        """
        descrs = [ar.descr for ar in self.availability_restrictions()]
        if "None" in descrs:
            return "None"
        else:
            return ", ".join(descrs)

    def prescribability_statuses(self):
        """Return all prescribability statuses for this presentation.
        """
        vmps = VMP.objects.filter(bnf_code=self.bnf_code)
        return VirtualProductPresStatus.objects.filter(vmp__in=vmps).distinct()

    def prescribability_statuses_descr(self):
        """Return a description of the presentation's prescribability status/es."""
        return ", ".join(ps.descr for ps in self.prescribability_statuses())

    def dmd_info(self):
        """Return dictionary of information about this presentation extracted
        from the dm+d data."""

        info = {
            "tariff_categories": self.tariff_categories_descr(),
            "availability_restrictions": self.availability_restrictions_descr(),
            "prescribability_statuses": self.prescribability_statuses_descr(),
        }
        return {k: v for k, v in info.items() if v}

    @property
    def product_name(self):
        return self.dmd_name or self.name

    @classmethod
    def names_for_bnf_codes(cls, bnf_codes):
        """
        Given a list of BNF codes return a dictionary mapping those codes to their
        DM&D names
        """
        name_map = cls.objects.filter(bnf_code__in=bnf_codes).values_list(
            "bnf_code", Coalesce("dmd_name", "name")
        )
        return dict(name_map)
Пример #14
0
class Country(models.Model):
    slug = models.CharField(max_length=150)
    name = models.CharField(max_length=150)
    featurecla = models.CharField(max_length=32)
    soviso = models.CharField(max_length=100)
    scalerank = models.IntegerField()
    sovereignt = models.CharField(max_length=200)
    sov_a3 = models.CharField(max_length=200)
    level = models.FloatField()
    type = models.CharField(max_length=200)
    sortname = models.CharField(max_length=200)
    adm0_a3 = models.CharField(max_length=200)
    name_sm = models.CharField(max_length=200)
    name_lng = models.CharField(max_length=200)
    terr = models.CharField(max_length=200)
    parentheti = models.CharField(max_length=200)
    name_alt = models.CharField(max_length=200)
    local_lng = models.CharField(max_length=200)
    local_sm = models.CharField(max_length=200)
    former = models.CharField(max_length=200)
    abbrev = models.CharField(max_length=200)
    fips_10 = models.CharField(max_length=200)
    iso_a2 = models.CharField(max_length=200)
    iso_a3 = models.CharField(max_length=200)
    iso_n3 = models.FloatField()
    map_color = models.FloatField()
    people = models.FloatField()
    gdp_usdm = models.FloatField()
    itu = models.CharField(max_length=200)
    ioc = models.CharField(max_length=200)
    fifa = models.CharField(max_length=200)
    ds = models.CharField(max_length=200)
    wmo = models.CharField(max_length=200)
    
    gaul = models.FloatField()
    marc = models.CharField(max_length=200)
    stanag1059 = models.CharField(max_length=200)
    gw_id = models.FloatField()
    dial = models.FloatField()
    internet = models.CharField(max_length=3)
    cog = models.CharField(max_length=5)
    actual = models.CharField(max_length=1)
    capay = models.CharField(max_length=5)
    crpay = models.CharField(max_length=5)
    ani = models.CharField(max_length=4)
    libenr = models.CharField(max_length=50)
    ancnom = models.CharField(max_length=20)
    pays_r_gio = models.CharField(max_length=50)
    comment = models.CharField(max_length=260)
    
    
    # Multipolygon since Polygon fields in Shapefiles can be Multipolygons
    mpoly = models.MultiPolygonField()
    objects = models.GeoManager()

    # So the model is pluralized correctly in the admin.
    class Meta:
        verbose_name_plural = "Countries"

    # Returns the string representation of the model.
    def __unicode__(self):
        return self.name
    
    def save(self, *args, **kwargs):
        from django.template.defaultfilters import slugify
        self.slug = slugify(self.name)
        super(self.__class__, self).save(*args, **kwargs) # Call the "real" save() method.
Пример #15
0
class Activity(models.Model):
    name = models.CharField(max_length=250, null=False)
    flat_pace = models.FloatField(verbose_name="flat pace (M)",
                                  null=False,
                                  default=1)
    ascent_pace = models.FloatField(verbose_name="ascent pace (M)",
                                    null=False,
                                    default=1)
    descent_pace = models.FloatField(verbose_name="descent pace (M)",
                                     null=False,
                                     default=1)
    dev1 = models.FloatField(verbose_name="dev 1 (M)", null=False, default=1)
    dev2 = models.FloatField(verbose_name="dev 2 (M)", null=False, default=1)
    dev3 = models.FloatField(verbose_name="dev 3 (M)", null=False, default=1)
    dev4 = models.FloatField(verbose_name="dev 4 (M)", null=False, default=1)
    distance1 = models.FloatField(verbose_name="distance 1 (KM)",
                                  null=False,
                                  default=1)
    distance2 = models.FloatField(verbose_name="distance 2 (KM)",
                                  null=False,
                                  default=1)
    distance3 = models.FloatField(verbose_name="distance 3 (KM)",
                                  null=False,
                                  default=1)
    distance4 = models.FloatField(verbose_name="distance 4 (KM)",
                                  null=False,
                                  default=1)

    class Meta:
        verbose_name = "Activity"
        verbose_name_plural = "Activities"

    def __str__(self):
        return "Activity {0}: {1}".format(self.pk, self.name)
Пример #16
0
class Circuit(mixins.ObjectWithPictureMixin, AuditableModel):
    """
    Circuit class, collection of places and topics
    """

    name = models.CharField(
        verbose_name=strings.CIRCUIT_NAME,
        max_length=256,
    )

    slug = AutoSlugField(
        verbose_name=strings.CIRCUIT_SLUG,
        populate_from='name',
        unique=False,
        editable=False,
    )

    remixed_from = models.ForeignKey(
        'self',
        verbose_name=strings.CIRCUIT_REMIXED_FROM,
        blank=True,
        null=True,
    )

    category = models.IntegerField(
        verbose_name=strings.CIRCUIT_CATEGORY,
        choices=constants.CIRCUIT_CATEGORY_CHOICES,
    )

    description = models.CharField(
        verbose_name=strings.CIRCUIT_DESCRIPTION,
        max_length=512,
        blank=True,
        null=True,
    )

    author = models.ForeignKey(
        User,
        verbose_name=strings.CIRCUIT_AUTHOR,
    )

    rating = models.FloatField(
        verbose_name=strings.CIRCUIT_RATING,
        default=0.0,
    )

    picture = ImageField(
        verbose_name=strings.CIRCUIT_PICTURE,
        upload_to=uuid_based_picture_name('pictures/circuits'),
        blank=True,
        null=True,
    )

    # Relationship with Topic
    topics = models.ManyToManyField(
        Topic,
        verbose_name=strings.CIRCUIT_TOPICS,
        related_name='circuits',
        null=True,
        blank=True,
    )

    visits = generic.GenericRelation(
        Visit,
        verbose_name=strings.CIRCUIT_VISITS,
    )

    published = models.BooleanField(
        verbose_name=strings.CIRCUIT_PUBLISHED,
        default=True,
    )

    highlighted = models.BooleanField(
        verbose_name=strings.CIRCUIT_HIGHLIGHTED,
        default=False,
    )

    source = models.PositiveIntegerField(
        choices=constants.CIRCUIT_SOURCE_CHOICES,
        default=constants.CIRCUIT_SOURCE_CHOICES.WORLDRAT_USERS,
        blank=True,
        null=True,
    )

    adult_content = models.BooleanField(
        verbose_name=strings.CIRCUIT_ADULT_CONTENT,
        default=False,
    )

    #Relation to comments model
    comments = generic.GenericRelation(Comment, object_id_field='object_pk')

    objects = CircuitManager()

    def __unicode__(self):
        return u'%s' % (self.name, )

    def delete(self):
        """ Extension of parent delete method """
        # in case circuit is remix of some other circuit
        if self.remixed_from:
            # Send signal to update Redis DB
            circuit_remix_deleted.send(sender=self, remixed_circuit_id=self.pk)
        # Send signal to update Redis DB
        circuit_deleted.send(sender=self)
        # call parent method
        super(Circuit, self).delete()

    def save(self):
        """ Extension of parent save method """
        # Signal to verify updated data
        circuit_updated.send(sender=self)
        # if circuit has 0 stops make published = False
        if self.circuit_stops.count() == 0:
            self.published = False
        else:
            self.published = True
        # Call parent method
        super(Circuit, self).save()
        # Send signal to update Redis DB
        circuit_created.send(sender=self)
        # position fixer method
        self.fix_stops_position()

    class Meta:
        verbose_name = strings.CIRCUIT_VERBOSE_NAME
        verbose_name_plural = strings.CIRCUIT_VERBOSE_NAME_PLURAL

    def stats(self):
        """ Returns circuit stats obtained from Redis """
        R = RedisStatsQuery()
        return {
            'visit_count': R.circuit_visits(self.pk),
            'favorite_count': R.circuit_fav_count(self.pk),
            'remix_count': R.circuit_remix_count(self.pk),
            #'comment_count': self.comments.count()
        }

    def fix_stops_position(self):
        stops = []
        for stop in self.circuit_stops.all():
            stops.append(stop)
        # super magical sorting function
        stops.sort(key=lambda CircuitStop: CircuitStop.place.coordinates.x)
        # set new position to stop
        counter = 1
        for stop in stops:
            stop.position = counter
            stop.save()
            counter += 1

    def get_data(self):
        pic = self.get_picture(settings.THUMB_SMALL_SIZE)
        return {
            'id': self.id,
            'name': self.name,
            'category': self.category,
            'category_display': self.get_category_display(),
            'description': self.description,
            'adult_content': self.adult_content,
            'picture_url': pic['url'],
            'picture_ratio_hw': pic['ratio_hw'],
        }

    def to_json(self):
        """Return a JSON representation for easy storage and reuse in the
        template.
        """
        return json.dumps(self.get_data())

    def get_update_url(self):
        return reverse('circuit_update_controller_resource',
                       kwargs={'circuit_id': self.id})

    @property
    def verbose_category(self):
        return unicode(constants.CIRCUIT_CATEGORY_CHOICES[self.category][1])

    def get_visitors(self):
        """
        Returns a QuerySet containing all the User objects
        who visited this circuit
        """
        user_id_list = []

        for uv in self.visits.all():
            if uv.visitor.id not in user_id_list:
                user_id_list.append(uv.visitor.id)

        return User.objects.filter(id__in=user_id_list)

    def get_places(self):
        """
        Returns a QuerySet containing the related places
        """
        raw_places = self.circuit_stops.values('place')
        places = []
        for elem in raw_places:
            places.append(elem['place'])

        return Place.objects.filter(pk__in=places)

    def get_raters(self):
        """
        Returns a QuerySet containing the Users that rated this circuit
        """
        raw_users = self.circuit_ratings.values('user')
        users = []
        for elem in raw_users:
            users.append(elem['user'])

        return User.objects.filter(id_in=users)

    def get_circuit_rating(self, user):
        try:
            circuit_rating = CircuitRating.objects.get(circuit=self, user=user)
            return circuit_rating
        except CircuitRating.DoesNotExist:
            return None

    def register_vote(self, user, vote):
        cr = self.get_circuit_rating(user)
        is_pending = (vote == CircuitRating.VOTE_TYPE_CHOICES.PENDING)

        if cr:
            print cr.vote, vote
            if is_pending:
                cr.delete()
            elif cr.vote != vote:
                cr.vote = vote
                cr.save()
            return

        # Add only if it's an upvote or a downvote
        if is_pending:
            return
        cr = CircuitRating(
            circuit=self,
            user=user,
            vote=vote,
        )
        cr.save()

    def register_upvote(self, user):
        vote = CircuitRating.VOTE_TYPE_CHOICES.UPVOTE
        return self.register_vote(user, vote)

    def register_downvote(self, user):
        vote = CircuitRating.VOTE_TYPE_CHOICES.DOWNVOTE
        return self.register_vote(user, vote)

    def reset_vote(self, user):
        vote = CircuitRating.VOTE_TYPE_CHOICES.PENDING
        return self.register_vote(user, vote)

    def get_vote(self, user):
        """Returns 1, -1 or 0 according if the vote of `user` is an upvote,
        downvote or none.
        """
        cr = self.get_circuit_rating(user)
        if not cr:
            return 0
        if cr.vote == CircuitRating.VOTE_TYPE_CHOICES.UPVOTE:
            return 1
        if cr.vote == CircuitRating.VOTE_TYPE_CHOICES.DOWNVOTE:
            return -1
        return 0

    def arrange_positions(self, uuid_list):
        missing = []
        current = OrderedDict()
        qs = self.circuit_stops.all()

        for cs in qs:
            current[cs.uuid] = cs

        found = 0
        unspecified = 0
        updated = 0
        new_order = []

        position = 0

        # Update position of circuit stops included
        # in the list of UUIDs
        for uuid in uuid_list:
            position += 1
            if uuid in current:
                found += 1
                cs = current[uuid]
                if cs.position != position:
                    cs.position = position
                    cs.save()
                    updated += 1
                del (current[uuid])
                new_order.append(uuid)
            else:
                missing.append(uuid)

        # Remaining circuit stops
        for uuid in current:
            position += 1
            cs = current[uuid]
            if cs.position != position:
                cs.position = position
                cs.save()
                updated += 1
                unspecified += 1
            del (current[uuid])
            new_order.append(uuid)

        results = OrderedDict()
        results['found'] = found
        results['unspecified'] = unspecified
        results['updated'] = updated
        results['new_order'] = new_order
        results['missing'] = missing

        return results

    def calculate_rating(self):
        """
        sets the member rating to the % of upvotes and downvotes
        """
        all_ct_ratings = self.circuit_ratings.values('vote')

        if len(all_ct_ratings):
            all_votes = []
            for vote in all_ct_ratings:
                all_votes.append(vote['vote'])

            upvotes = 0
            for vote in all_votes:
                if vote == 1:
                    upvotes += 1

            self.rating = (upvotes * 100) / len(all_votes)
            self.save()

    def get_absolute_url(self):
        return reverse(
            'circuit_detail_with_slug',
            #'circuit_detail_without_slug',
            kwargs={
                'circuit_id': self.pk,
                'slug': self.slug,
            })

    def get_restful_url(self):
        return "%s%s" % (settings.API_V1_PREFIX.rstrip('/'),
                         reverse('circuit_resource',
                                 kwargs={'circuit_id': self.id}))

    def get_restful_link_metadata(self):
        metadata = OrderedDict()
        metadata['href'] = self.get_restful_url()
        metadata['rel'] = 'alternate'
        metadata['title'] = self.name
        metadata['type'] = 'application/json'
        return metadata

    def get_last_position(self):
        """ Checks for greater position
            ad returns the integer of it
        """
        return self.circuit_stops.count()

    def is_authorized(self, user):
        if self.author == user:
            return True
        elif user.is_staff:
            return True
        return False

    # TODO: method not needed, not allowing default circuit now
    @staticmethod
    def create_default_circuit(author):
        circuit = Circuit(name=strings.DEFAULT_CIRCUIT_NAME,
                          category=constants.DEFAULT_CIRCUIT_CATEGORY,
                          author=author)
        circuit.save()
        return circuit

    def get_category_object(self):
        return CircuitCategory(self.category)

    @staticmethod
    def delete_empty_citcuits():
        """
        deletes all circuits with no stops associated to it, created
        to wipe nexstop empty circuits
        """
        all_cts = Circuit.objects.all()
        for ct in all_cts:
            if len(ct.get_places()) == 0:
                ct.delete()

    def remix(self,
              new_author,
              new_title,
              new_category,
              new_description=None,
              adult_content=False):
        """
        Returns a Copy of the current circuit and stops with a new id, unsaved.
        new_author: UserProfile
        """
        new_circuit = Circuit()
        new_circuit.name = new_title
        new_circuit.author = new_author
        new_circuit.category = new_category
        new_circuit.description = new_description
        new_circuit.picture = self.picture
        if adult_content:
            new_circuit.adult_content = True

        if self.remixed_from:
            new_circuit.remixed_from = self.remixed_from
        else:
            new_circuit.remixed_from = self

        new_circuit.save()
        for stop in self.circuit_stops.all():
            new_stop = CircuitStop()
            new_stop.circuit = new_circuit
            new_stop.place = stop.place
            new_stop.description = u''
            new_stop.position = stop.position
            new_stop.picture = stop.picture
            new_stop.save()

        # Send signal to update Redis DB
        circuit_remixed.send(sender=self, remixed_circuit_id=new_circuit.pk)
        return new_circuit

    def get_coordinates_box(self):
        min_lat = None
        max_lat = None
        min_lng = None
        max_lng = None
        # Get min and max latitude
        for stop in self.circuit_stops.all():
            lat = stop.lat
            lng = stop.lng
            # Minimal latitude
            if min_lat is None:
                min_lat = lat
            elif lat < min_lat:
                min_lat = lat
            # Maximal latitude
            if max_lat is None:
                max_lat = lat
            elif lat > max_lat:
                max_lat = lat
            # Minimal longitude
            if min_lng is None:
                min_lng = lng
            elif lng < min_lng:
                min_lng = lng
            # Maximal longitude
            if max_lng is None:
                max_lng = lng
            elif lng > max_lng:
                max_lng = lng
        result = OrderedDict()
        result['lat'] = OrderedDict()
        result['lat']['min'] = min_lat
        result['lat']['max'] = max_lat
        result['lng'] = OrderedDict()
        result['lng']['min'] = min_lng
        result['lng']['max'] = max_lng
        return result

    def get_followers(self):
        return [profile.user for profile in self.follower_profiles.all()]

    @staticmethod
    # FIXME: @mathiasbc returns duplicated circuits, must fix it
    def filter_by_gmac(gmac):
        """ gmac = GMAC instance """
        stops = CircuitStop.filter_by_gmac(gmac)
        cts = Circuit.objects.filter(circuit_stops__in=stops)
        circuits = []
        for ct in cts:
            if ct not in circuits:
                circuits.append(ct)
        return circuits

    @staticmethod
    def filter_by_gmacs(gmacs):
        stops = []
        for gmac in gmacs:
            stops += Circuit.filter_by_gmac(gmac)
        return stops
Пример #17
0
class Trail(models.Model):
    PATH_TYPES = (
        (0, "Non determine"),
        (1, "Aller simple"),
        (2, "Boucle"),
        (3, "Aller-retour"),
    )

    id_field = "trail_id"
    index_type = index_types.TYPE_TRAIL

    objectid = models.IntegerField(null=True, blank=True)
    trail_id = models.AutoField(primary_key=True)
    slug = models.SlugField(max_length=300, default="", blank=True)
    trail_type = models.IntegerField(default=1)
    name = models.CharField(max_length=250, null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    total_length = models.FloatField(null=True, blank=True)
    min_elevation = models.IntegerField(default=0, null=True,
                                        blank=True)  # altitude_minimum
    max_elevation = models.IntegerField(default=0, null=True,
                                        blank=True)  # altitude_maximum
    path_type = models.IntegerField(choices=PATH_TYPES, null=True, blank=True)
    height_positive = models.IntegerField(null=True, blank=True)
    height_negative = models.IntegerField(null=True, blank=True)
    height_difference = models.IntegerField(null=True, blank=True)
    private = models.BooleanField(default=False)
    hikster_creation = models.IntegerField(null=True, blank=True)
    shape = models.GeometryField(srid=4326, null=True, blank=True, dim=3)
    opening_dates = JSONField(null=True, blank=True)
    last_modified = models.DateField(auto_now=True)

    # Related fields
    location = models.ForeignKey(
        "location.Location",
        related_name="trails",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
    )
    region = models.ForeignKey("location.Location",
                               null=True,
                               blank=True,
                               on_delete=models.SET_NULL)
    trail_sections = models.ManyToManyField(TrailSection, blank=True)

    # Managers
    objects = models.Manager()
    objects_with_eager_loading = TrailManager()

    shape_2d = models.GeometryField(srid=4326, null=True, blank=True, dim=2)

    @property
    def object_type(self):
        return self.__class__.__name__

    def format_duration(self, duration):
        return functions.pretty_time_delta(duration.total_seconds())

    def __str__(self):
        value = f"{self.trail_id} Trail name: {self.name}"

        if self.location:
            value = f"{value} - Park: {self.location.pk}"

        return value

    def save(self, *args, **kwargs):
        self.slug = original = slugify(self.name)

        for x in itertools.count(1):
            if not Trail.objects.filter(slug=self.slug).exists():
                break
            self.slug = "%s-%d" % (original, x)

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

    @property
    def activity_names(self):
        return self.activities.values_list("activity__name", flat=True)

    @property
    def banner(self):
        return self.images.banners().first()

    @property
    def activity_ids(self):
        return self.activities.values_list("activity__id", flat=True)

    @property
    def markers(self):
        event_trail_sections = list(
            EventTrailSection.objects.filter(evnt=self.event).values(
                "start_position", "end_position",
                "trailsection").order_by("order"))
        return event_trail_sections
Пример #18
0
class Gps_points(models.Model):
    location = models.PointField()
    temprature = models.FloatField(default=20)
    date = models.DateTimeField(default=datetime.now, blank=True)
Пример #19
0
class Peak(models.Model):
    location = models.PointField(null=False, blank=False)
    elevation = models.FloatField(null=False,
                                  blank=False,
                                  validators=[validators.MinValueValidator(0)])
    name = models.CharField(max_length=128, null=False, blank=False)
Пример #20
0
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'
        ]

    @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)
Пример #21
0
class Aerodrome_Utility_Sewage_Line(models.Model):
    Aerodrome_Entity = models.ForeignKey(Aerodrome_Entity,null=True,on_delete=models.SET_NULL)
    Line_Size= models.FloatField()
    Remark = models.TextField()
    Line_geom = models.LineStringField()
Пример #22
0
class Sink(models.Model):

    TYPE_CHOICES = (
        ("CATCHMENT", "Catchment Basin"),
        ("SINKHOLE", "Sinkhole/Karst Feature"),
        ("QUARRY", "Quarry"),
        ("DC", "Ditch/Culvert"),
        ("FOUNDATION", "Building Foundation"),
        ("OTHER", "Other"),
        ("UNKNOWN", "Unknown"),
    )

    CON_CHOICES = (
        ("PROBABLE", "Probable"),
        ("POSSIBLE", "Possible"),
    )

    DEPTH_CAT_CHOICES = (
        ("0-1", "0-1 ft"),
        ("1-2", "1-2 ft"),
        ("2-5", "2-5 ft"),
        ("5+", "5+ ft"),
    )

    sink_id = models.IntegerField(null=True, blank=True)
    sink_type = models.CharField(max_length=20,
                                 choices=TYPE_CHOICES,
                                 blank=True)
    dem_check = models.IntegerField(null=True, blank=True)
    img_check = models.IntegerField(null=True, blank=True)
    evidence = models.CharField(max_length=1, blank=True, null=True)
    depth = models.FloatField(null=True, blank=True)
    depth_cat = models.CharField(max_length=20,
                                 choices=DEPTH_CAT_CHOICES,
                                 null=True,
                                 blank=True)
    elevation = models.FloatField(null=True, blank=True)
    in_nfhl = models.NullBooleanField()
    in_row = models.NullBooleanField()
    bm_hs = models.BooleanField(default=False)
    bm_aerial = models.BooleanField(default=False)
    bm_tpi = models.BooleanField(default=False)
    bm_usgs = models.BooleanField(default=False)
    field_chk = models.BooleanField(default=False)
    field_eval = models.CharField(max_length=20,
                                  choices=CON_CHOICES,
                                  blank=True,
                                  null=True)
    confidence = models.CharField(max_length=20,
                                  choices=CON_CHOICES,
                                  blank=True,
                                  null=True)
    comment = models.TextField(max_length=254, blank=True, null=True)
    last_update = models.DateTimeField(auto_now=True)
    event_no = models.IntegerField(null=True, blank=True)
    geom = models.PointField(null=True)

    def save(self, *args, **kwargs):
        if self.depth is not None:
            if self.depth < 1:
                self.depth_cat = "0-1"
            elif self.depth < 2:
                self.depth_cat = "1-2"
            elif self.depth < 5:
                self.depth_cat = "2-5"
            else:
                self.depth_cat = "5+"
        super(Sink, self).save(*args, **kwargs)
        return
Пример #23
0
class Energyusage(models.Model):
    energy_type = models.CharField(
        choices=(
            ("national_en", "National system"),
            ("renewable_en", "Renewable"),
            ("both_en", "Both"),
            ("national_ro", "Sistem Național"),
            ("renewable_ro", "Regenerabilă"),
            ("both_ro", "Amândouă"),
        ),
        max_length=12,
        null=True,
        blank=True,
        verbose_name="What type of energy do you use?",
    )
    more_renewable = models.CharField(
        choices=(
            ("yes_en", "Yes"),
            ("no_en", "No"),
            ("yes_ro", "Da"),
            ("no_ro", "Nu"),
        ),
        max_length=6,
        null=True,
        blank=True,
        verbose_name="Would you like to use more renewable energy?",
    )
    renewable_type = models.CharField(
        choices=(
            ("solar_en", "Solar"),
            ("wind_en", "Wind"),
            ("water_en", "Water"),
            ("geothermal_en", "Geothermal"),
            ("bio_en", "Bio"),
            ("other_en", "Other"),
            ("solar_ro", "Solar"),
            ("wind_ro", "Vânt"),
            ("water_ro", "Apă"),
            ("geothermal_ro", "Geotermală"),
            ("bio_ro", "Bio"),
            ("other_ro", "Alte"),
        ),
        max_length=13,
        null=True,
        blank=True,
        verbose_name="What type of renewable energy do you use?",
    )
    toggle = models.CharField(
        choices=(
            ("gps", "Folosește GPS / Use GPS"),
            ("interactive", "Punct pe hartă / Point on Map"),
            ("manual", "Introducere manuală / Enter Manually"),
        ),
        max_length=11,
        null=True,
        blank=True,
        verbose_name="Location Mode",
    )
    geometry = models.PointField(
        srid=4326,
        null=True,
        blank=True,
        verbose_name="Location",
    )
    latitude = models.FloatField(
        null=True,
        blank=True,
        verbose_name="Latitude",
    )
    longitude = models.FloatField(
        null=True,
        blank=True,
        verbose_name="Longitude",
    )
    accuracy = models.FloatField(
        null=True,
        blank=True,
        verbose_name="GPS Accuracy",
    )

    class Meta:
        verbose_name = "energyusage"
        verbose_name_plural = "energyusages"
Пример #24
0
class Well(models.Model):

    wi_unique_well_no = models.CharField(primary_key=True,
                                         max_length=6,
                                         verbose_name="WI Unique Well ID")
    watr_seq_no = models.IntegerField(null=True,
                                      blank=True,
                                      verbose_name="Water Seq No.")
    dnr_lat_dd_amt = models.FloatField(null=True,
                                       blank=True,
                                       verbose_name="DNR Lat.")
    dnr_long_dd_amt = models.FloatField(null=True,
                                        blank=True,
                                        verbose_name="DNR Long.")
    survey_township = models.IntegerField(null=True,
                                          blank=True,
                                          verbose_name="Survey Township")
    survey_range = models.IntegerField(null=True,
                                       blank=True,
                                       verbose_name="Survey Range")
    survey_range_dir = models.CharField(max_length=1,
                                        null=True,
                                        blank=True,
                                        verbose_name="Survey Range Dir.")
    survey_section = models.IntegerField(null=True,
                                         blank=True,
                                         verbose_name="Survey Section")
    q_section = models.CharField(max_length=2,
                                 null=True,
                                 blank=True,
                                 verbose_name="Q Section")
    qq_section = models.CharField(max_length=2,
                                  null=True,
                                  blank=True,
                                  verbose_name="QQ Section")
    well_addr = models.CharField(max_length=100,
                                 null=True,
                                 blank=True,
                                 verbose_name="Well Address")
    owner_mailing_addr = models.CharField(max_length=60,
                                          blank=True,
                                          null=True,
                                          verbose_name="Owner Mailing Address")
    esri_oid = models.IntegerField(null=True,
                                   blank=True,
                                   verbose_name="ESRI OID")
    muni = models.CharField(max_length=45,
                            blank=True,
                            null=True,
                            verbose_name="Municipality")
    well_depth_amt = models.FloatField(null=True,
                                       blank=True,
                                       verbose_name="Well Depth")
    well_depth_amt_text = models.CharField(max_length=45,
                                           null=True,
                                           blank=True,
                                           verbose_name="Well Depth - text")
    constructor_name = models.CharField(max_length=60,
                                        blank=True,
                                        null=True,
                                        verbose_name="Constructor Name")
    well_complete_date = models.DateField(blank=True,
                                          null=True,
                                          verbose_name="Well Completion Date")
    well_status = models.CharField(max_length=15,
                                   blank=True,
                                   null=True,
                                   verbose_name="Well Status")
    static_depth_amt = models.FloatField(null=True,
                                         blank=True,
                                         verbose_name="Static Depth")
    static_depth_above_below = models.CharField(
        max_length=25,
        blank=True,
        null=True,
        verbose_name="Static Depth Above Below")
    location_method = models.CharField(max_length=25,
                                       blank=True,
                                       null=True,
                                       verbose_name="Location Method")
    casing_depth_amt = models.FloatField(null=True,
                                         blank=True,
                                         verbose_name="Casing Depth")
    casing_depth_amt_txt = models.CharField(max_length=45,
                                            blank=True,
                                            null=True,
                                            verbose_name="Casing Depth - text")
    decade_complete = models.CharField(max_length=15,
                                       blank=True,
                                       null=True,
                                       verbose_name="Decade Completed")
    well_constr_url = models.CharField(max_length=115,
                                       blank=True,
                                       null=True,
                                       verbose_name="WCR URL")
    sample_db_url = models.CharField(max_length=650,
                                     blank=True,
                                     null=True,
                                     verbose_name="Sample DB URL")
    geom = models.PointField(null=True, verbose_name="Location")
    geo_corrected = models.BooleanField(max_length=650,
                                        blank=True,
                                        null=True,
                                        verbose_name="Geometry corrected?")
    geo_corrected_by = models.CharField(max_length=100,
                                        blank=True,
                                        null=True,
                                        verbose_name="Geometry corrected by")
    geo_corrected_time = models.DateTimeField(
        blank=True, null=True, verbose_name="Geometry corrected on")

    def __str__(self):
        return self.pk

    def save(self, *args, **kwargs):
        url = "https://prodoasext.dnr.wi.gov/inter1/pk_wr583_sample_query.p_sample_list?"\
        "i_county=HIDDEN&i_township=HIDDEN&i_range=HIDDEN&i_range_dir=&i_section=HIDDEN"\
        f"&i_wuwn=HIDDEN&i_wuwn={self.wi_unique_well_no}&i_wuwn=&i_wuwn=&i_wuwn=&i_wuwn="\
        "&i_well_use=HIDDEN&i_well_use=&i_watershed=HIDDEN&i_watershed=&i_labslip=HIDDEN"\
        "&i_labslip=&i_labslip=&i_labslip=&i_labslip=&i_labslip=&i_sample_from="\
        "&i_sample_to=&i_dg_samples=HIDDEN&i_dg_samples=YES&i_pw_samples=HIDDEN&"\
        "i_pw_samples=YES&i_sw_samples=HIDDEN&i_storet_group=&i_storet=HIDDEN&i_storet="\
        "&i_storet=&i_storet=&i_storet=&i_storet=&i_cas=HIDDEN&i_cas=&i_cas=&i_cas=&i_cas=&i_cas="\
        "&i_res_criteria=ALL&i_storet_index=1"
        self.sample_db_url = url
        super(Well, self).save(*args, **kwargs)
Пример #25
0
class Anomaly(models.Model):
    col0 = models.BigIntegerField(null=True)
    mmsi = models.FloatField(null=True)
    datetime = models.FloatField(null=True)
    lat = models.FloatField(null=True)
    lon = models.FloatField(null=True)
    sog = models.FloatField(null=True)
    cog = models.FloatField(null=True)
    heading = models.BigIntegerField(null=True)
    vesselname = models.CharField(max_length=254, null=True)
    imo = models.CharField(max_length=254, null=True)
    callsign = models.CharField(max_length=254, null=True)
    vesseltype = models.FloatField(null=True)
    status = models.FloatField(null=True)
    length = models.FloatField(null=True)
    width = models.FloatField(null=True)
    draft = models.FloatField(null=True)
    cargo = models.FloatField(null=True)
    transcieve = models.CharField(max_length=254, null=True)
    geom = models.MultiPointField(srid=4326, null=True)
Пример #26
0
class CountyByMonth(models.Model):
    """
    The unemployment data in county in a particular month.
    """
    # The time and place
    county = models.ForeignKey(County)
    year = models.IntegerField()
    month = models.IntegerField()

    # The goodies
    labor_force = models.IntegerField()
    employment = models.IntegerField()
    unemployment = models.IntegerField()
    unemployment_rate = models.FloatField()

    # The boring stuff
    is_seasonally_adjusted = models.BooleanField('seasonally adjusted')
    is_preliminary = models.BooleanField('preliminary')
    benchmark = models.CharField(max_length=150)

    # Managers
    objects = models.GeoManager()
    adjusted = SeasonallyAdjustedManager()
    unadjusted = UnadjustedManager()

    class Meta:
        ordering = (
            'county',
            'year',
            'month',
        )
        verbose_name = 'County by Month'
        verbose_name_plural = 'Counties by Month'

    def __unicode__(self):
        return u'%s %s-%s' % (self.county, self.year, self.month)

    def get_month_display(self):
        """
        Return the month in AP style.
        """
        from django.utils.dateformat import format
        return format(datetime.date(2010, self.month, 01), 'N')

    def get_month_obj(self):
        """
        Return the month as a datetime object.
        """
        return datetime.datetime(self.year, self.month, 1)

    def get_next_month(self):
        """
        Return the month after this one.
        """
        from dateutil.relativedelta import relativedelta
        return self.get_month_obj() + relativedelta(months=+1)

    def get_previous_month(self):
        """
        Return the month before this one.
        """
        from dateutil.relativedelta import relativedelta
        return self.get_month_obj() + relativedelta(months=-1)
Пример #27
0
class Locality(UpdateMixin, ChangesetMixin):
    """
    A Locality is uniquely defined by an *uuid* attribute. Attribute *geom*
    stores geometry as a point object. *upstream_id* is used to preserve link
    to the originating dataset which is used to find and update a Locality on
    any reoccurring data imports.

    A Locality is in a *Domain* and data values for Attributes, to be exact,
    their Specifications, are defined through *Value*
    """
    DEFINED_DAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

    domain = models.ForeignKey('Domain')
    uuid = models.TextField(unique=True)
    upstream_id = models.TextField(null=True, unique=True)
    geom = models.PointField(srid=4326)
    specifications = models.ManyToManyField('Specification', through='Value')
    name = models.TextField()
    source = models.TextField(default='healthsites.io')
    migrated = models.BooleanField(default=False)

    # completeness is a big calculation
    # so it has to be an field
    completeness = models.FloatField(null=True, default=0.0)
    is_master = models.BooleanField(default=True)

    objects = PassThroughGeoManager.for_queryset_class(LocalitiesQuerySet)()
    tracker = FieldTracker()

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

    def _get_attr_map(self):
        return (self.domain.specification_set.order_by('id').values(
            'id', 'attribute__key'))

    def set_geom(self, lon, lat):
        """
        Helper method to set Locality geometry
        """

        self.geom.set_x(lon)
        self.geom.set_y(lat)

    def set_values(self, changed_data, social_user, changeset=None):
        """
        Set values for a Locality which are defined by Specifications

        Once all of values are set, 'SIG_locality_values_updated' signal will
        be triggered to update FullTextSearch index for this Locality
        """
        special_key = [
            'scope_of_service', 'ancillary_services', 'activities',
            'inpatient_service', 'staff'
        ]
        attrs = self._get_attr_map()

        tmp_changeset = changeset

        changed_values = []
        for key, data in changed_data.iteritems():
            if key in special_key:
                data = data.replace(',', '|')
                data = data.replace('| ', '|')
            # try to match key from changed items with a key from attr_map
            attr_list = [
                attr for attr in attrs if attr['attribute__key'] == key
            ]

            if attr_list:
                # get specification id for specific key
                spec_id = attr_list[0]['id']

                # update or create new values
                try:
                    obj = self.value_set.get(specification_id=spec_id)
                    _created = False
                except Value.DoesNotExist:
                    # in case there is no value for the specification, create
                    obj = Value()
                    obj.locality = self
                    obj.specification_id = spec_id
                    _created = True

                # set data
                obj.data = data

                # check if Value.data actually changed, and save if it did
                if obj.tracker.changed():
                    if not (tmp_changeset):
                        tmp_changeset = Changeset.objects.create(
                            social_user=social_user)
                    obj.changeset = tmp_changeset
                    obj.save()
                    changed_values.append((obj, _created))
                else:
                    # nothing changed, don't save the value
                    pass
            else:
                # attr_id was not found (maybe a bad attribute)
                LOG.warning('Locality %s has no attribute key %s', self.pk,
                            key)

        # send values_updated signal
        signals.SIG_locality_values_updated.send(sender=self.__class__,
                                                 instance=self)

        # calculate completeness
        if changed_values:
            self.completeness = self.calculate_completeness()
            self.save()

        return changed_values

    def repr_dict(self, clean=False, in_array=False):
        """
        Basic locality representation, as a dictionary
        """

        dict = {
            u'uuid': self.uuid,
            u'upstream': self.upstream_id,
            u'source': self.source,
            u'name': self.name,
            u'geom': (self.geom.x, self.geom.y),
            u'version': self.version,
            u'date_modified': self.changeset.created,
            u'completeness': '%s%%' % format(self.completeness, '.2f'),
        }

        dict['values'] = {}

        data_query = (self.value_set.select_related().exclude(
            data__isnull=True).exclude(data__exact=''))

        for val in data_query:
            if in_array:
                dict['values'][val.specification.attribute.key] = [
                    data for data in val.data.split('|') if data
                ]

                clean_data = dict['values'][val.specification.attribute.key]
                if len(clean_data) == 0:
                    dict['values'][val.specification.attribute.key] = '-'
                elif len(clean_data) == 1:
                    dict['values'][
                        val.specification.attribute.key] = clean_data[0]
                continue
            if clean:
                # clean if empty
                temp = val.data.replace('|', '')
                if len(temp) == 0:
                    val.data = ''
                # clean data
                val.data = val.data.replace('|', ',')
                val.specification.attribute.key = (
                    val.specification.attribute.key.replace('_', '-'))
                cleaned_data = val.data.replace(',', '')
                if len(cleaned_data) > 0:
                    dict['values'][val.specification.attribute.key] = val.data
            else:
                dict['values'][val.specification.attribute.key] = val.data

        try:
            site = Site.objects.get(name=dict[u'source'])
            dict[u'source_url'] = site.domain
        except Site.DoesNotExist:
            pass

        # exclusive for open street map
        if self.upstream_id is not None and 'openstreetmap' in self.upstream_id.lower(
        ):
            osm_whole_id = self.upstream_id.split(u'¶')
            if len(osm_whole_id) > 0:
                osm_whole_id = osm_whole_id[1]
                identifier = osm_whole_id[0]
                osm_id = osm_whole_id[1:]
                if identifier == 'n':
                    dict['osm_type'] = 'node'
                    url = 'http://www.openstreetmap.org/node/' + osm_id
                elif identifier == 'r':
                    dict['osm_type'] = 'relation'
                    url = 'http://www.openstreetmap.org/relation/' + osm_id
                elif identifier == 'w':
                    dict['osm_type'] = 'way'
                    url = 'http://www.openstreetmap.org/way/' + osm_id

                if url:
                    dict['osm_id'] = osm_id
                    dict['source_url'] = url
        return dict

    def is_type(self, value):
        if value != '':
            try:
                self.value_set.filter(
                    specification__attribute__key='type').get(data=value)
                return True
            except Exception:
                return False
        return True

    def calculate_completeness(self):
        DEFAULT_VALUE = 4  # GUID & GEOM & NAME & DATA SOURCE
        global_attr = attributes_availables['global']
        specific_attr = attributes_availables['hospital']
        for key in attributes_availables.keys():
            try:
                self.value_set.filter(
                    specification__attribute__key='type').get(
                        data__icontains=key)
                specific_attr = attributes_availables[key]
            except Value.DoesNotExist:
                continue

        values = self.repr_dict()['values']
        counted_value = DEFAULT_VALUE
        max_value = len(global_attr) + len(specific_attr) + DEFAULT_VALUE

        for attr in global_attr + specific_attr:
            if attr in values:
                data = values[attr]
                if len(data.replace('-', '').replace('|', '').strip()) != 0:
                    counted_value += 1

        return (counted_value + 0.0) / (max_value + 0.0) * 100

    def prepare_for_fts(self):
        """
        Retrieve and group *Value* objects, for this Locality, based on their
        FTS ordering (defined by *Specification*)
        """

        data_values = itertools.groupby(
            self.value_set.order_by('specification__fts_rank').values_list(
                'specification__fts_rank', 'data'), lambda x: x[0])

        return {k: ' '.join([x[1] for x in v]) for k, v in data_values}

    def update_what3words(self, user, changeset):
        from utils import get_what_3_words
        what3words = get_what_3_words(self.geom)
        if what3words != '':
            self.set_values({'what3words': what3words}, user, changeset)

    def get_synonyms(self):
        synonyms = SynonymLocalities.objects.get(locality=self)
        return synonyms

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

    def validate_data_by_defined_list(self,
                                      data,
                                      key,
                                      options,
                                      required=False):
        """ Check value data by key if it is string and it is in options.

        :param data: Data to be inserted
        :param key: Key data that is checked
        :param options: Options to be checked
        :return:
        """
        try:
            value = data[key]
            if isinstance(value, list):
                raise ValueError('nature_of_facility should be string')
            if value not in options:
                raise ValueError('%s is not recognized, options : %s' %
                                 (key, options))

        except KeyError as e:
            if required:
                raise ValueError('%s is required' % e)
            pass

    def validate_data(self, data):
        """ Validate data based on fields

        :param data: Data that will be inserted
        :type data: dict
        """
        try:
            data['lng'] = float(data['lng'])
        except ValueError:
            raise ValueError('lng is not in float')
        try:
            data['lat'] = float(data['lat'])
        except ValueError:
            raise ValueError('lat is not in float')

        if not data['name']:
            raise ValueError('name is empty')

        domain = Domain.objects.get(name='Health')
        attributes = Specification.objects.filter(domain=domain).filter(
            required=True)
        for attribute in attributes:
            if not data[attribute.attribute.key]:
                raise ValueError('%s is empty' % attribute.attribute.key)

        # inpatient_service
        try:
            inpatient_service = data['inpatient_service']
            try:
                full_time_beds = inpatient_service['full_time_beds']
            except KeyError:
                raise ValueError(
                    'full_time_beds needs to be in inpatient_service')
            try:
                part_time_beds = inpatient_service['part_time_beds']
            except KeyError:
                raise ValueError(
                    'part_time_beds needs to be in inpatient_service')
            data['inpatient_service'] = '%s|%s' % (full_time_beds,
                                                   part_time_beds)
        except KeyError:
            pass

        # staff
        try:
            staff = data['staff']
            try:
                doctors = staff['doctors']
            except KeyError:
                raise ValueError('doctors needs to be in staff')
            try:
                nurses = staff['nurses']
            except KeyError:
                raise ValueError('nurses needs to be in staff')
            data['staff'] = '%s|%s' % (doctors, nurses)
        except KeyError:
            pass

        # nature of facility
        options = [
            'clinic without beds', 'clinic with beds',
            'first referral hospital',
            'second referral hospital or General hospital',
            'tertiary level including University hospital'
        ]
        self.validate_data_by_defined_list(data, 'nature_of_facility', options)

        # nature of facility
        options = ['public', 'private not for profit', 'private commercial']
        self.validate_data_by_defined_list(data, 'ownership', options)

        # defined_hours
        try:
            defined_hours = []
            for index, day in enumerate(Locality.DEFINED_DAYS):
                try:
                    hours = data['defining_hours'][day]
                    if isinstance(hours, str) or isinstance(hours, unicode):
                        if hours == '':
                            hours = []
                        else:
                            try:
                                hours = json.loads(hours)
                            except ValueError:
                                pass
                    if not isinstance(hours, list):
                        raise ValueError('%s is need to be in list' % day)
                    if len(hours) == 1:
                        hours.append('-')
                    elif len(hours) > 2:
                        raise ValueError('maximum lenght of %s is 2' % day)
                    hours = '-'.join(hours)
                    if not hours:
                        hours = '-'
                    defined_hours.append(hours)
                except KeyError as e:
                    raise ValueError('%s is required on defined_hours' % e)
            data['defining_hours'] = defined_hours
        except KeyError:
            pass
        except TypeError:
            raise TypeError('defining_hours needs to be in dictionary')

        return True

    def update_data(self, data, user):
        """ Update locality data with new data.

        :param data: Data that will be inserted
        :type data: dict
        """
        import uuid
        from django.contrib.gis.geos import Point
        from localities.tasks import regenerate_cache, regenerate_cache_cluster

        self.validate_data(data)
        old_geom = None
        try:
            old_geom = [self.geom.x, self.geom.y]
            self.set_geom(data['lng'], data['lat'])
        except AttributeError:
            self.geom = Point(data['lng'], data['lat'])

        self.name = data['name']

        # there are some changes so create a new changeset
        changeset = Changeset.objects.create(social_user=user)
        self.changeset = changeset

        del data['lng']
        del data['lat']

        created = False
        if not self.pk:
            created = True
            self.domain = Domain.objects.get(name='Health')
            self.changeset = changeset
            self.uuid = uuid.uuid4().hex
            self.upstream_id = u'web¶{}'.format(self.uuid)
            self.save()

        self.set_specifications(data, changeset)
        if not created and self.tracker.changed():
            self.changeset = changeset
            self.save()

        # generate some attributes if location changed/created
        new_geom = [self.geom.x, self.geom.y]
        if new_geom != old_geom or created:
            try:
                self.update_what3words(user, changeset)
            except AttributeError:
                pass
            regenerate_cache_cluster.delay()
        regenerate_cache.delay(changeset.pk, self.pk)
        return True

    def set_specifications(self,
                           data,
                           changeset,
                           autocreate_specification=True):
        """
        Set values for a Locality which are defined by Specifications

        Once all of values are set, 'SIG_locality_values_updated' signal will
        be triggered to update FullTextSearch index for this Locality

        :param data: Data to be inserted as specification
        :type data: dict
        """
        fields = self._meta.get_all_field_names()
        domain = Domain.objects.get(name='Health')

        changed_values = []
        for key, value in data.iteritems():
            if key in fields:
                continue

            if isinstance(value, list):
                value = '|'.join(value)
            else:
                value = '%s' % value

            value = value.replace(',', '|')
            value = value.replace('| ', '|')

            try:
                specification = Specification.objects.get(domain=domain,
                                                          attribute__key=key)
            except Specification.DoesNotExist:
                if autocreate_specification:
                    try:
                        attribute = Attribute.objects.get(key=key)
                    except Attribute.DoesNotExist:
                        attribute = Attribute.objects.create(
                            key=key, changeset=changeset)
                    specification = Specification.objects.create(
                        domain=domain,
                        attribute=attribute,
                        changeset=changeset)
                else:
                    continue

            try:
                obj = self.value_set.get(specification=specification)
            except Value.DoesNotExist:
                # in case there is no value for the specification, create
                obj = Value()
                obj.locality = self
                obj.specification = specification

            obj.data = value

            # check if Value.data actually changed, and save if it did
            if obj.tracker.changed():
                obj.changeset = changeset
                obj.save()
                changed_values.append(obj)
            else:
                # nothing changed, don't save the value
                pass

        # send values_updated signal
        signals.SIG_locality_values_updated.send(sender=self.__class__,
                                                 instance=self)

        # calculate completeness
        if changed_values:
            self.completeness = self.calculate_completeness()
            self.save()

        return changed_values
Пример #28
0
class Transformer_C2(models.Model):
    fid_1 = models.IntegerField(null=True, blank=True)
    objectid = models.BigIntegerField(null=True, blank=True)
    tag = models.CharField(null=True, blank=True, max_length=15)
    subtypecod = models.BigIntegerField(null=True, blank=True)
    op_volt = models.CharField(null=True, blank=True, max_length=2)
    facilityid = models.CharField(null=True, blank=True, max_length=13)
    phasedesig = models.BigIntegerField(null=True, blank=True)
    ratekva = models.FloatField(null=True, blank=True)
    circuitcou = models.IntegerField(null=True, blank=True)
    configurat = models.CharField(null=True, blank=True, max_length=2)
    owner = models.CharField(null=True, blank=True, max_length=1)
    presenttap = models.CharField(null=True, blank=True, max_length=1)
    customerty = models.CharField(null=True, blank=True, max_length=1)
    loadstatus = models.IntegerField(null=True, blank=True)
    phasea_kva = models.FloatField(null=True, blank=True)
    phaseb_kva = models.FloatField(null=True, blank=True)
    phasec_kva = models.FloatField(null=True, blank=True)
    capnum = models.IntegerField(null=True, blank=True)
    totalkvar = models.IntegerField(null=True, blank=True)
    lanum = models.IntegerField(null=True, blank=True)
    constructi = models.CharField(null=True, blank=True, max_length=1)
    location = models.CharField(null=True, blank=True, max_length=50)
    angle = models.FloatField(null=True, blank=True)
    labeltext = models.CharField(null=True, blank=True, max_length=60)
    transforme = models.IntegerField(null=True, blank=True)
    installati = models.IntegerField(null=True, blank=True)
    creationus = models.CharField(null=True, blank=True, max_length=50)
    datecreate = models.DateField(null=True, blank=True)
    lastuser = models.CharField(null=True, blank=True, max_length=50)
    datemodifi = models.DateField(null=True, blank=True)
    feederid = models.CharField(null=True, blank=True, max_length=7)
    feederid2 = models.CharField(null=True, blank=True, max_length=7)
    feederinfo = models.BigIntegerField(null=True, blank=True)
    electrictr = models.BigIntegerField(null=True, blank=True)
    enabled = models.IntegerField(null=True, blank=True)
    wbs = models.CharField(null=True, blank=True, max_length=55)
    existingkw = models.FloatField(null=True, blank=True)
    existingkv = models.FloatField(null=True, blank=True)
    existing_1 = models.FloatField(null=True, blank=True)
    workreques = models.CharField(null=True, blank=True, max_length=20)
    designid = models.CharField(null=True, blank=True, max_length=20)
    worklocati = models.CharField(null=True, blank=True, max_length=20)
    workflowst = models.BigIntegerField(null=True, blank=True)
    workfuncti = models.BigIntegerField(null=True, blank=True)
    designtext = models.CharField(null=True, blank=True, max_length=100)
    graphicdes = models.CharField(null=True, blank=True, max_length=10)
    numberofus = models.BigIntegerField(null=True, blank=True)
    attachment = models.CharField(null=True, blank=True, max_length=254)
    matrefno = models.CharField(null=True, blank=True, max_length=30)
    globalid = models.CharField(null=True, blank=True, max_length=38)
    opvoltint = models.BigIntegerField(null=True, blank=True)
    objectid_1 = models.IntegerField(null=True, blank=True)
    name = models.CharField(null=True, blank=True, max_length=45)
    code = models.CharField(null=True, blank=True, max_length=14)
    creation_1 = models.CharField(null=True, blank=True, max_length=50)
    datecrea_1 = models.DateField(null=True, blank=True)
    lastuser_1 = models.CharField(null=True, blank=True, max_length=50)
    datemodi_1 = models.DateField(null=True, blank=True)
    workrequ_1 = models.CharField(null=True, blank=True, max_length=20)
    designid_1 = models.CharField(null=True, blank=True, max_length=20)
    workloca_1 = models.CharField(null=True, blank=True, max_length=20)
    workflow_1 = models.IntegerField(null=True, blank=True)
    workfunc_1 = models.IntegerField(null=True, blank=True)
    area_code = models.CharField(null=True, blank=True, max_length=2)
    shape_leng = models.FloatField(null=True, blank=True)
    shape_area = models.FloatField(null=True, blank=True)
    lat = models.FloatField(null=True, blank=True)
    long = models.FloatField(null=True, blank=True)

    loadProfile_base = models.CharField(null=True, blank=True, max_length=800)
    loadProfile_ev = models.CharField(null=True, blank=True, max_length=800)
    impact = models.CharField(null=True, blank=True, max_length=800)
    flag = models.BooleanField(default=False)

    geom = models.MultiPointField(srid=4326)

    def __str__(self):
        return self.facilityid
Пример #29
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
class CompetitionResult(models.Model):
    """Výsledek soutěže"""
    class Meta:
        verbose_name = _("Výsledek soutěže")
        verbose_name_plural = _("Výsledky soutěží")
        unique_together = (("user_attendance", "competition"), ("team",
                                                                "competition"))

    user_attendance = models.ForeignKey(
        UserAttendance,
        related_name="competitions_results",
        null=True,
        blank=True,
        default=None,
        on_delete=models.CASCADE,
    )
    team = models.ForeignKey(
        Team,
        related_name="competitions_results",
        null=True,
        blank=True,
        default=None,
        on_delete=models.CASCADE,
    )
    company = models.ForeignKey(
        Company,
        related_name="company_results",
        null=True,
        blank=True,
        default=None,
        on_delete=models.CASCADE,
    )
    competition = models.ForeignKey(
        "Competition",
        related_name="results",
        null=False,
        blank=False,
        on_delete=models.CASCADE,
    )
    result = models.DecimalField(
        verbose_name=_("Výsledek"),
        max_digits=10,
        decimal_places=6,
        null=True,
        blank=True,
        default=None,
        db_index=True,
    )
    result_divident = models.FloatField(
        verbose_name=_("Dělenec"),
        null=True,
        blank=True,
        default=None,
    )
    result_divisor = models.FloatField(
        verbose_name=_("Dělitel"),
        null=True,
        blank=True,
        default=None,
    )
    created = models.DateTimeField(
        verbose_name=_("Datum vytvoření"),
        auto_now_add=True,
        null=True,
    )
    updated = models.DateTimeField(
        verbose_name=_("Datum poslední změny"),
        auto_now=True,
        null=True,
    )
    frequency = models.FloatField(
        verbose_name=_("Pravidelnost"),
        null=True,
        blank=True,
        default=0,
    )
    distance = models.FloatField(
        verbose_name=_("Vzdalenost"),
        null=True,
        blank=True,
        default=0,
    )

    def get_sequence_range(self):
        """
        Return range of places of this result.
        Means, that the competitor is placed on one or more places.
        """
        lower_range = (CompetitionResult.objects.filter(
            competition=self.competition,
            result__gt=self.result,
        ).count() + 1)
        upper_range = CompetitionResult.objects.filter(
            competition=self.competition,
            result__gte=self.result,
        ).count()
        return lower_range, upper_range

    def get_occupation(self):
        if self.user_attendance:
            return getattr(self.user_attendance.userprofile.occupation, "name",
                           "-")

    def get_sex(self):
        if self.user_attendance:
            return self.user_attendance.userprofile.get_sex_display()

    def get_team(self):
        if self.competition.competitor_type in ["liberos", "single_user"]:
            return self.user_attendance.team
        if self.competition.competitor_type == "team":
            return self.team

    def get_team_name(self):
        return self.get_team().name or ""

    def get_company(self):
        if self.competition.competitor_type == "company":
            return self.company
        team = self.get_team()
        if team:
            return team.subsidiary.company

    def get_subsidiary(self):
        return "%s / %s" % (self.get_street(), self.get_company())

    def get_street(self):
        team = self.get_team()
        if team:
            return team.subsidiary.address_street

    def get_city(self):
        team = self.get_team()
        if team:
            return team.subsidiary.city
        if self.company:
            return self.company.city

    def get_result(self):
        """Get result in kilometers rounded to reasonable number of decimal places."""
        return round(self.result, 1)

    def get_result_divisor(self):
        if self.competition.competition_type == "frequency":
            return int(round(self.result_divisor))
        else:
            return round(self.result_divisor, 1)

    def get_result_divident(self):
        if self.competition.competition_type == "frequency":
            return int(round(self.result_divident))
        else:
            return round(self.result_divident, 1)

    def get_result_percentage(self):
        """
        Get result as percentage of all rides.
        @return percentage in rounded integer
        """
        if self.result:
            return round(self.result * 100, 1)
        else:
            return 0

    def get_emissions(self):
        from ..util import get_emissions

        return get_emissions(self.distance)

    def competitor_attr(self,
                        team_getter,
                        company_getter,
                        user_attendance_getter,
                        default=""):
        if self.competition.competitor_type == "team":
            if self.team:
                return team_getter(self.team)
        elif self.competition.competitor_type == "company":
            if self.company:
                return company_getter(self.company)
        else:
            if self.user_attendance:
                return user_attendance_getter(self.user_attendance)
        return default

    def get_icon_url(self):
        return self.competitor_attr(
            lambda team: "%s" % team.icon_url(),
            lambda company: "%s" % company.icon_url(),
            lambda user_attendance: "%s" % user_attendance.avatar_url(),
        )

    def __str__(self):
        return self.competitor_attr(
            lambda team: "%s" % team.name,
            lambda company: "%s" % company.name,
            lambda user_attendance: "%s" % user_attendance.userprofile.name(),
        )

    def user_attendances(self):
        competition = self.competition
        if (competition.competitor_type == "single_user"
                or competition.competitor_type == "libero"):
            return [self.user_attendance]
        elif competition.competitor_type == "team":
            return self.team.members
        elif competition.competitor_type == "company":
            return UserAttendance.objects.filter(
                team__subsidiary__company=self.company)