示例#1
0
 def reload(self):
     if self.pk:
         fromdb = self.__class__.objects.get(pk=self.pk)
         self.area = fromdb.area
         AltimetryMixin.reload(self, fromdb)
         TimeStampedModelMixin.reload(self, fromdb)
         NoDeleteMixin.reload(self, fromdb)
         if self.topology:
             self.topology.reload()
     return self
示例#2
0
 def reload(self):
     if self.pk:
         fromdb = self.__class__.objects.get(pk=self.pk)
         self.area = fromdb.area
         AltimetryMixin.reload(self, fromdb)
         TimeStampedModelMixin.reload(self, fromdb)
         NoDeleteMixin.reload(self, fromdb)
         if self.topology:
             self.topology.reload()
     return self
示例#3
0
 def reload(self, fromdb=None):
     """
     Reload into instance all computed attributes in triggers.
     """
     if self.pk:
         # Update computed values
         fromdb = self.__class__.objects.get(pk=self.pk)
         self.geom = fromdb.geom
         # /!\ offset may be set by a trigger OR in
         # the django code, reload() will override
         # any unsaved value
         self.offset = fromdb.offset
         AltimetryMixin.reload(self, fromdb)
         TimeStampedModelMixin.reload(self, fromdb)
         NoDeleteMixin.reload(self, fromdb)
     return self
示例#4
0
class Project(AddPropertyMixin, MapEntityMixin, TimeStampedModelMixin,
              StructureRelated, NoDeleteMixin):

    name = models.CharField(verbose_name=_(u"Name"),
                            max_length=128,
                            db_column='nom')
    begin_year = models.IntegerField(verbose_name=_(u"Begin year"),
                                     db_column='annee_debut')
    end_year = models.IntegerField(verbose_name=_(u"End year"),
                                   db_column='annee_fin')
    constraint = models.TextField(verbose_name=_(u"Constraint"),
                                  blank=True,
                                  db_column='contraintes',
                                  help_text=_(u"Specific conditions, ..."))
    global_cost = models.FloatField(verbose_name=_(u"Global cost"),
                                    default=0,
                                    db_column='cout_global',
                                    help_text=_(u"€"))
    comments = models.TextField(verbose_name=_(u"Comments"),
                                blank=True,
                                db_column='commentaires',
                                help_text=_(u"Remarks and notes"))
    type = models.ForeignKey('ProjectType',
                             null=True,
                             blank=True,
                             verbose_name=_(u"Type"),
                             db_column='type')
    domain = models.ForeignKey('ProjectDomain',
                               null=True,
                               blank=True,
                               verbose_name=_(u"Domain"),
                               db_column='domaine')
    contractors = models.ManyToManyField('Contractor',
                                         related_name="projects",
                                         db_table="m_r_chantier_prestataire",
                                         verbose_name=_(u"Contractors"))
    project_owner = models.ForeignKey(Organism,
                                      related_name='own',
                                      verbose_name=_(u"Project owner"),
                                      db_column='maitre_oeuvre')
    project_manager = models.ForeignKey(Organism,
                                        related_name='manage',
                                        verbose_name=_(u"Project manager"),
                                        db_column='maitre_ouvrage')
    founders = models.ManyToManyField(Organism,
                                      through='Funding',
                                      verbose_name=_(u"Founders"))

    objects = NoDeleteMixin.get_manager_cls(ProjectManager)()

    class Meta:
        db_table = 'm_t_chantier'
        verbose_name = _(u"Project")
        verbose_name_plural = _(u"Projects")
        ordering = ['-begin_year', 'name']

    def __init__(self, *args, **kwargs):
        super(Project, self).__init__(*args, **kwargs)
        self._geom = None

    @property
    def paths(self):
        s = []
        for i in self.interventions.existing():
            s += i.paths
        return Path.objects.filter(pk__in=[p.pk for p in set(s)])

    @property
    def trails(self):
        s = []
        for i in self.interventions.existing():
            for p in i.paths.all():
                for t in p.trails.all():
                    s.append(t.pk)

        return Trail.objects.filter(pk__in=s)

    @property
    def signages(self):
        s = []
        for i in self.interventions.existing():
            s += i.signages
        return list(set(s))

    @property
    def infrastructures(self):
        s = []
        for i in self.interventions.existing():
            s += i.infrastructures
        return list(set(s))

    @classproperty
    def geomfield(cls):
        from django.contrib.gis.geos import LineString
        # Fake field, TODO: still better than overkill code in views, but can do neater.
        c = GeometryCollection([LineString((0, 0), (1, 1))],
                               srid=settings.SRID)
        c.name = 'geom'
        return c

    @property
    def geom(self):
        """ Merge all interventions geometry into a collection
        """
        if self._geom is None:
            interventions = Intervention.objects.existing().filter(
                project=self)
            geoms = [i.geom for i in interventions if i.geom is not None]
            if geoms:
                self._geom = GeometryCollection(*geoms, srid=settings.SRID)
        return self._geom

    @geom.setter
    def geom(self, value):
        self._geom = value

    @property
    def name_display(self):
        return u'<a data-pk="%s" href="%s" title="%s">%s</a>' % (
            self.pk, self.get_detail_url(), self.name, self.name)

    @property
    def name_csv_display(self):
        return unicode(self.name)

    @property
    def interventions_csv_display(self):
        return [unicode(i) for i in self.interventions.existing()]

    @property
    def contractors_display(self):
        return [unicode(c) for c in self.contractors.all()]

    @property
    def founders_display(self):
        return [unicode(f) for f in self.founders.all()]

    @property
    def period(self):
        return "%s - %s" % (self.begin_year, self.end_year)

    @property
    def period_display(self):
        return self.period

    @classproperty
    def period_verbose_name(cls):
        return _("Period")

    @property
    def interventions_total_cost(self):
        total = 0
        qs = self.interventions.existing()
        for i in qs.prefetch_related('manday_set', 'manday_set__job'):
            total += i.total_cost
        return total

    @classproperty
    def interventions_total_cost_verbose_name(cls):
        return _("Interventions total cost")

    def __unicode__(self):
        return u"%s (%s-%s)" % (self.name, self.begin_year, self.end_year)

    @classmethod
    def path_projects(cls, path):
        return cls.objects.existing().filter(
            interventions__in=path.interventions).distinct()

    @classmethod
    def topology_projects(cls, topology):
        return cls.objects.existing().filter(
            interventions__in=topology.interventions).distinct()

    def edges_by_attr(self, interventionattr):
        """ Return related topology objects of project, by aggregating the same attribute
        on its interventions.
        (See geotrek.land.models)
        """
        pks = []
        modelclass = Topology
        for i in self.interventions.all():
            attr_value = getattr(i, interventionattr)
            if isinstance(attr_value, list):
                pks += [o.pk for o in attr_value]
            else:
                modelclass = attr_value.model
                topologies = attr_value.values('ordering', 'id')
                for topology in topologies:
                    pks.append(topology['id'])
        return modelclass.objects.filter(pk__in=pks)

    @classmethod
    def get_create_label(cls):
        return _(u"Add a new project")
示例#5
0
class Intervention(AddPropertyMixin, MapEntityMixin, AltimetryMixin,
                   TimeStampedModelMixin, StructureRelated, NoDeleteMixin):

    name = models.CharField(verbose_name=_(u"Name"),
                            max_length=128,
                            db_column='nom',
                            help_text=_(u"Brief summary"))
    date = models.DateField(default=datetime.now,
                            verbose_name=_(u"Date"),
                            db_column='date',
                            help_text=_(u"When ?"))
    subcontracting = models.BooleanField(verbose_name=_(u"Subcontracting"),
                                         default=False,
                                         db_column='sous_traitance')

    # Technical information
    width = models.FloatField(default=0.0,
                              verbose_name=_(u"Width"),
                              db_column='largeur')
    height = models.FloatField(default=0.0,
                               verbose_name=_(u"Height"),
                               db_column='hauteur')
    area = models.FloatField(editable=False,
                             default=0,
                             verbose_name=_(u"Area"),
                             db_column='surface')

    # Costs
    material_cost = models.FloatField(default=0.0,
                                      verbose_name=_(u"Material cost"),
                                      db_column='cout_materiel')
    heliport_cost = models.FloatField(default=0.0,
                                      verbose_name=_(u"Heliport cost"),
                                      db_column='cout_heliport')
    subcontract_cost = models.FloatField(default=0.0,
                                         verbose_name=_(u"Subcontract cost"),
                                         db_column='cout_soustraitant')
    """ Topology can be of type Infrastructure, Signage or of own type Intervention """
    topology = models.ForeignKey(
        Topology,
        null=True,  # TODO: why null ?
        related_name="interventions_set",
        verbose_name=_(u"Interventions"))
    # AltimetyMixin for denormalized fields from related topology, updated via trigger.
    length = models.FloatField(editable=True,
                               default=0.0,
                               null=True,
                               blank=True,
                               db_column='longueur',
                               verbose_name=_(u"3D Length"))

    stake = models.ForeignKey('core.Stake',
                              null=True,
                              blank=True,
                              related_name='interventions',
                              verbose_name=_("Stake"),
                              db_column='enjeu')

    status = models.ForeignKey('InterventionStatus',
                               verbose_name=_("Status"),
                               db_column='status')

    type = models.ForeignKey('InterventionType',
                             null=True,
                             blank=True,
                             verbose_name=_(u"Type"),
                             db_column='type')

    disorders = models.ManyToManyField('InterventionDisorder',
                                       related_name="interventions",
                                       db_table="m_r_intervention_desordre",
                                       verbose_name=_(u"Disorders"),
                                       blank=True)

    jobs = models.ManyToManyField('InterventionJob',
                                  through='ManDay',
                                  verbose_name=_(u"Jobs"))

    project = models.ForeignKey('Project',
                                null=True,
                                blank=True,
                                related_name="interventions",
                                verbose_name=_(u"Project"),
                                db_column='chantier')
    description = models.TextField(blank=True,
                                   verbose_name=_(u"Description"),
                                   db_column='descriptif',
                                   help_text=_(u"Remarks and notes"))

    objects = NoDeleteMixin.get_manager_cls(InterventionManager)()

    class Meta:
        db_table = 'm_t_intervention'
        verbose_name = _(u"Intervention")
        verbose_name_plural = _(u"Interventions")

    def __init__(self, *args, **kwargs):
        super(Intervention, self).__init__(*args, **kwargs)
        self._geom = None

    def set_topology(self, topology):
        self.topology = topology
        if not self.on_existing_topology:
            raise ValueError("Expecting an infrastructure or signage")

    def default_stake(self):
        stake = None
        if self.topology:
            for path in self.topology.paths.all():
                if path.stake > stake:
                    stake = path.stake
        return stake

    def reload(self):
        if self.pk:
            fromdb = self.__class__.objects.get(pk=self.pk)
            self.area = fromdb.area
            AltimetryMixin.reload(self, fromdb)
            TimeStampedModelMixin.reload(self, fromdb)
            NoDeleteMixin.reload(self, fromdb)
            if self.topology:
                self.topology.reload()
        return self

    def save(self, *args, **kwargs):
        if self.stake is None:
            self.stake = self.default_stake()

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

        # Set kind of Intervention topology
        if self.topology and not self.on_existing_topology:
            topology_kind = self._meta.object_name.upper()
            self.topology.kind = topology_kind
            self.topology.save(update_fields=['kind'])

        # Invalidate project map
        if self.project:
            try:
                os.remove(self.project.get_map_image_path())
            except OSError:
                pass

        self.reload()

    @property
    def on_existing_topology(self):
        return self.is_infrastructure or self.is_signage

    @property
    def infrastructure(self):
        """
        Equivalent of topology attribute, but casted to related type (Infrastructure)
        """
        if self.is_infrastructure:
            return self.infrastructures[0]
        return None

    @property
    def signage(self):
        """
        Equivalent of topology attribute, but casted to related type (Signage)
        """
        if self.is_signage:
            return self.signages[0]
        return None

    @classproperty
    def infrastructure_verbose_name(cls):
        return _("On")

    @classproperty
    def signage_verbose_name(cls):
        return _("On")

    @property
    def infrastructure_display(self):
        icon = 'path'
        title = _('Path')
        if self.on_existing_topology:
            icon = self.topology.kind.lower()
            if self.infrastructure:
                title = u'%s: %s' % (_(
                    self.topology.kind.capitalize()), self.infrastructure)
            elif self.signage:
                title = u'%s: %s' % (_(
                    self.topology.kind.capitalize()), self.signage)
        return u'<img src="%simages/%s-16.png" title="%s">' % (
            settings.STATIC_URL, icon, title)

    @property
    def infrastructure_csv_display(self):
        if self.on_existing_topology:
            if self.infrastructure:
                return u"%s: %s (%s)" % (_(
                    self.topology.kind.capitalize()), self.infrastructure,
                                         self.infrastructure.pk)
            elif self.signage:
                return u"%s: %s (%s)" % (_(self.topology.kind.capitalize()),
                                         self.signage, self.signage.pk)
        return ''

    @property
    def is_infrastructure(self):
        if self.topology:
            return self.topology.kind == Infrastructure.KIND
        return False

    @property
    def is_signage(self):
        if self.topology:
            return self.topology.kind == Signage.KIND
        return False

    @property
    def in_project(self):
        return self.project is not None

    @property
    def paths(self):
        if self.topology:
            return self.topology.paths.all()
        return Path.objects.none()

    @property
    def trails(self):
        s = []
        for p in self.paths.all():
            for t in p.trails.all():
                s.append(t.pk)
        return Trail.objects.filter(pk__in=s)

    @property
    def signages(self):
        if self.is_signage:
            return [Signage.objects.existing().get(pk=self.topology.pk)]
        return []

    @property
    def infrastructures(self):
        if self.is_infrastructure:
            return [Infrastructure.objects.existing().get(pk=self.topology.pk)]
        return []

    @property
    def total_manday(self):
        total = 0.0
        for md in self.manday_set.all():
            total += float(md.nb_days)
        return total

    @classproperty
    def total_manday_verbose_name(cls):
        return _("Mandays")

    @property
    def total_cost_mandays(self):
        total = 0.0
        for md in self.manday_set.all():
            total += md.cost
        return total

    @classproperty
    def total_cost_mandays_verbose_name(cls):
        return _("Mandays cost")

    @property
    def total_cost(self):
        return self.total_cost_mandays + \
            self.material_cost + \
            self.heliport_cost + \
            self.subcontract_cost

    @classproperty
    def total_cost_verbose_name(cls):
        return _("Total cost")

    @classproperty
    def geomfield(cls):
        return Topology._meta.get_field('geom')

    @property
    def geom(self):
        if self._geom is None:
            if self.topology:
                self._geom = self.topology.geom
        return self._geom

    @geom.setter
    def geom(self, value):
        self._geom = value

    @property
    def name_display(self):
        return u'<a data-pk="%s" href="%s" title="%s" >%s</a>' % (
            self.pk, self.get_detail_url(), self.name, self.name)

    @property
    def name_csv_display(self):
        return unicode(self.name)

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

    @classmethod
    def path_interventions(cls, path):
        return cls.objects.existing().filter(topology__aggregations__path=path)

    @classmethod
    def topology_interventions(cls, topology):
        topos = Topology.overlapping(topology).values_list('pk', flat=True)
        return cls.objects.existing().filter(topology__in=topos).distinct('pk')
示例#6
0
class Topology(AddPropertyMixin, AltimetryMixin, TimeStampedModelMixin,
               NoDeleteMixin):
    paths = models.ManyToManyField(Path,
                                   db_column='troncons',
                                   through='PathAggregation',
                                   verbose_name=_("Path"))
    offset = models.FloatField(default=0.0,
                               db_column='decallage',
                               verbose_name=_("Offset"))  # in SRID units
    kind = models.CharField(editable=False,
                            verbose_name=_("Kind"),
                            max_length=32)

    # Override default manager
    objects = NoDeleteMixin.get_manager_cls(models.GeoManager)()

    geom = models.GeometryField(
        editable=(not settings.TREKKING_TOPOLOGY_ENABLED),
        srid=settings.SRID,
        null=True,
        default=None,
        spatial_index=False)
    """ Fake srid attribute, that prevents transform() calls when using Django map widgets. """
    srid = settings.API_SRID

    class Meta:
        db_table = 'e_t_evenement'
        verbose_name = _("Topology")
        verbose_name_plural = _("Topologies")

    def __init__(self, *args, **kwargs):
        super(Topology, self).__init__(*args, **kwargs)
        if not self.pk:
            self.kind = self.__class__.KIND

    @property
    def length_2d(self):
        if self.geom and not self.ispoint():
            return round(self.geom.length, 1)

        else:
            return None

    @classproperty
    def length_2d_verbose_name(cls):
        return _("2D Length")

    @property
    def length_2d_display(self):
        return self.length_2d

    @classproperty
    def KIND(cls):
        return cls._meta.object_name.upper()

    def __str__(self):
        return "%s (%s)" % (_("Topology"), self.pk)

    def ispoint(self):
        if not settings.TREKKING_TOPOLOGY_ENABLED or not self.pk:
            return self.geom and self.geom.geom_type == 'Point'
        return all([
            a.start_position == a.end_position
            for a in self.aggregations.all()
        ])

    def add_path(self, path, start=0.0, end=1.0, order=0, reload=True):
        """
        Shortcut function to add paths into this topology.
        """
        from .factories import PathAggregationFactory
        aggr = PathAggregationFactory.create(topo_object=self,
                                             path=path,
                                             start_position=start,
                                             end_position=end,
                                             order=order)

        if self.deleted:
            self.deleted = False
            self.save(update_fields=['deleted'])

        # Since a trigger modifies geom, we reload the object
        if reload:
            self.reload()
        return aggr

    @classmethod
    def overlapping(cls, topologies):
        """ Return a Topology queryset overlapping specified topologies.
        """
        return TopologyHelper.overlapping(cls, topologies)

    def mutate(self, other, delete=True):
        """
        Take alls attributes of the other topology specified and
        save them into this one. Optionnally deletes the other.
        """
        self.offset = other.offset
        self.save(update_fields=['offset'])
        PathAggregation.objects.filter(topo_object=self).delete()
        # The previous operation has put deleted = True (in triggers)
        # and NULL in geom (see update_geometry_of_evenement:: IF t_count = 0)
        self.deleted = False
        self.geom = other.geom
        self.save(update_fields=['deleted', 'geom'])

        # Now copy all agregations from other to self
        aggrs = other.aggregations.all()
        # A point has only one aggregation, except if it is on an intersection.
        # In this case, the trigger will create them, so ignore them here.
        if other.ispoint():
            aggrs = aggrs[:1]
        for aggr in aggrs:
            self.add_path(aggr.path,
                          aggr.start_position,
                          aggr.end_position,
                          aggr.order,
                          reload=False)
        self.reload()
        if delete:
            other.delete(force=True)  # Really delete it from database
        return self

    def reload(self):
        """
        Reload into instance all computed attributes in triggers.
        """
        if self.pk:
            # Update computed values
            fromdb = self.__class__.objects.get(pk=self.pk)
            self.geom = fromdb.geom
            # /!\ offset may be set by a trigger OR in
            # the django code, reload() will override
            # any unsaved value
            self.offset = fromdb.offset
            AltimetryMixin.reload(self, fromdb)
            TimeStampedModelMixin.reload(self, fromdb)
            NoDeleteMixin.reload(self, fromdb)

        return self

    @debug_pg_notices
    def save(self, *args, **kwargs):
        # HACK: these fields are readonly from the Django point of view
        # but they can be changed at DB level. Since Django write all fields
        # to DB anyway, it is important to update it before writting
        if self.pk and settings.TREKKING_TOPOLOGY_ENABLED:
            existing = self.__class__.objects.get(pk=self.pk)
            self.length = existing.length
            # In the case of points, the geom can be set by Django. Don't override.
            point_geom_not_set = self.ispoint() and self.geom is None
            geom_already_in_db = not self.ispoint(
            ) and existing.geom is not None
            if (point_geom_not_set or geom_already_in_db):
                self.geom = existing.geom
        else:
            if not self.deleted and self.geom is None:
                # We cannot have NULL geometry. So we use an empty one,
                # it will be computed or overwritten by triggers.
                self.geom = fromstr('POINT (0 0)')

        if not self.kind:
            if self.KIND == "TOPOLOGYMIXIN":
                raise Exception("Cannot save abstract topologies")
            self.kind = self.__class__.KIND

        # Static value for Topology offset, if any
        shortmodelname = self._meta.object_name.lower().replace('edge', '')
        self.offset = settings.TOPOLOGY_STATIC_OFFSETS.get(
            shortmodelname, self.offset)

        # Save into db
        super(Topology, self).save(*args, **kwargs)
        self.reload()

    def serialize(self, **kwargs):
        return TopologyHelper.serialize(self, **kwargs)

    @classmethod
    def deserialize(cls, serialized):
        return TopologyHelper.deserialize(serialized)

    def distance(self, to_cls):
        """Distance to associate this topology to another topology class"""
        return None
示例#7
0
class TouristicEvent(AddPropertyMixin, PublishableMixin, MapEntityMixin,
                     StructureRelated, PicturesMixin, TimeStampedModelMixin,
                     NoDeleteMixin):
    """ A touristic event (conference, workshop, etc.) in the park
    """
    description_teaser = models.TextField(
        verbose_name=_(u"Description teaser"),
        blank=True,
        help_text=_(u"A brief summary"),
        db_column='chapeau')
    description = models.TextField(verbose_name=_(u"Description"),
                                   blank=True,
                                   db_column='description',
                                   help_text=_(u"Complete description"))
    themes = models.ManyToManyField(Theme,
                                    related_name="touristic_events",
                                    db_table="t_r_evenement_touristique_theme",
                                    blank=True,
                                    null=True,
                                    verbose_name=_(u"Themes"),
                                    help_text=_(u"Main theme(s)"))
    geom = models.PointField(verbose_name=_(u"Location"), srid=settings.SRID)
    begin_date = models.DateField(blank=True,
                                  null=True,
                                  verbose_name=_(u"Begin date"),
                                  db_column='date_debut')
    end_date = models.DateField(blank=True,
                                null=True,
                                verbose_name=_(u"End date"),
                                db_column='date_fin')
    duration = models.CharField(verbose_name=_(u"Duration"),
                                max_length=64,
                                blank=True,
                                db_column='duree',
                                help_text=_(u"3 days, season, ..."))
    meeting_point = models.CharField(verbose_name=_(u"Meeting point"),
                                     max_length=256,
                                     blank=True,
                                     db_column='point_rdv',
                                     help_text=_(u"Where exactly ?"))
    meeting_time = models.TimeField(verbose_name=_(u"Meeting time"),
                                    blank=True,
                                    null=True,
                                    db_column='heure_rdv',
                                    help_text=_(u"11:00, 23:30"))
    contact = models.TextField(verbose_name=_(u"Contact"),
                               blank=True,
                               db_column='contact')
    email = models.EmailField(verbose_name=_(u"Email"),
                              max_length=256,
                              db_column='email',
                              blank=True,
                              null=True)
    website = models.URLField(verbose_name=_(u"Website"),
                              max_length=256,
                              db_column='website',
                              blank=True,
                              null=True)
    organizer = models.CharField(verbose_name=_(u"Organizer"),
                                 max_length=256,
                                 blank=True,
                                 db_column='organisateur')
    speaker = models.CharField(verbose_name=_(u"Speaker"),
                               max_length=256,
                               blank=True,
                               db_column='intervenant')
    type = models.ForeignKey(TouristicEventType,
                             verbose_name=_(u"Type"),
                             blank=True,
                             null=True,
                             db_column='type')
    accessibility = models.CharField(verbose_name=_(u"Accessibility"),
                                     max_length=256,
                                     blank=True,
                                     db_column='accessibilite')
    participant_number = models.CharField(
        verbose_name=_(u"Number of participants"),
        max_length=256,
        blank=True,
        db_column='nb_places')
    booking = models.TextField(verbose_name=_(u"Booking"),
                               blank=True,
                               db_column='reservation')
    target_audience = models.CharField(verbose_name=_(u"Target audience"),
                                       max_length=128,
                                       blank=True,
                                       null=True,
                                       db_column='public_vise')
    practical_info = models.TextField(
        verbose_name=_(u"Practical info"),
        blank=True,
        db_column='infos_pratiques',
        help_text=_(u"Recommandations / To plan / Advices"))
    source = models.ManyToManyField(
        'common.RecordSource',
        null=True,
        blank=True,
        related_name='touristicevents',
        verbose_name=_("Source"),
        db_table='t_r_evenement_touristique_source')
    eid = models.CharField(verbose_name=_(u"External id"),
                           max_length=128,
                           blank=True,
                           db_column='id_externe')
    approved = models.BooleanField(verbose_name=_(u"Approved"),
                                   default=False,
                                   db_column='labellise')

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

    category_id_prefix = 'E'

    class Meta:
        db_table = 't_t_evenement_touristique'
        verbose_name = _(u"Touristic event")
        verbose_name_plural = _(u"Touristic events")
        ordering = ['-begin_date']

    def __unicode__(self):
        return self.name

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

    @property
    def type1(self):
        return [self.type] if self.type else []

    @property
    def type2(self):
        return []

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

    @property
    def dates_display(self):
        if not self.begin_date and not self.end_date:
            return u""
        elif not self.end_date:
            return _(u"starting from {begin}").format(
                begin=date_format(self.begin_date, 'SHORT_DATE_FORMAT'))
        elif not self.begin_date:
            return _(u"up to {end}").format(
                end=date_format(self.end_date, 'SHORT_DATE_FORMAT'))
        elif self.begin_date == self.end_date:
            return date_format(self.begin_date, 'SHORT_DATE_FORMAT')
        else:
            return _(u"from {begin} to {end}").format(
                begin=date_format(self.begin_date, 'SHORT_DATE_FORMAT'),
                end=date_format(self.end_date, 'SHORT_DATE_FORMAT'))

    @property
    def prefixed_category_id(self):
        return self.category_id_prefix

    def distance(self, to_cls):
        return settings.TOURISM_INTERSECTION_MARGIN
示例#8
0
class TouristicContent(AddPropertyMixin, PublishableMixin, MapEntityMixin,
                       StructureRelated, TimeStampedModelMixin, PicturesMixin,
                       NoDeleteMixin):
    """ A generic touristic content (accomodation, museum, etc.) in the park
    """
    description_teaser = models.TextField(
        verbose_name=_(u"Description teaser"),
        blank=True,
        help_text=_(u"A brief summary"),
        db_column='chapeau')
    description = models.TextField(verbose_name=_(u"Description"),
                                   blank=True,
                                   db_column='description',
                                   help_text=_(u"Complete description"))
    themes = models.ManyToManyField(Theme,
                                    related_name="touristiccontents",
                                    db_table="t_r_contenu_touristique_theme",
                                    blank=True,
                                    null=True,
                                    verbose_name=_(u"Themes"),
                                    help_text=_(u"Main theme(s)"))
    geom = models.GeometryField(verbose_name=_(u"Location"),
                                srid=settings.SRID)
    category = models.ForeignKey(TouristicContentCategory,
                                 related_name='contents',
                                 verbose_name=_(u"Category"),
                                 db_column='categorie')
    contact = models.TextField(verbose_name=_(u"Contact"),
                               blank=True,
                               db_column='contact',
                               help_text=_(u"Address, phone, etc."))
    email = models.EmailField(verbose_name=_(u"Email"),
                              max_length=256,
                              db_column='email',
                              blank=True,
                              null=True)
    website = models.URLField(verbose_name=_(u"Website"),
                              max_length=256,
                              db_column='website',
                              blank=True,
                              null=True)
    practical_info = models.TextField(verbose_name=_(u"Practical info"),
                                      blank=True,
                                      db_column='infos_pratiques',
                                      help_text=_(u"Anything worth to know"))
    type1 = models.ManyToManyField(TouristicContentType,
                                   related_name='contents1',
                                   verbose_name=_(u"Type 1"),
                                   db_table="t_r_contenu_touristique_type1",
                                   blank=True)
    type2 = models.ManyToManyField(TouristicContentType,
                                   related_name='contents2',
                                   verbose_name=_(u"Type 2"),
                                   db_table="t_r_contenu_touristique_type2",
                                   blank=True)
    source = models.ManyToManyField('common.RecordSource',
                                    null=True,
                                    blank=True,
                                    related_name='touristiccontents',
                                    verbose_name=_("Source"),
                                    db_table='t_r_contenu_touristique_source')
    eid = models.CharField(verbose_name=_(u"External id"),
                           max_length=128,
                           blank=True,
                           db_column='id_externe')
    reservation_system = models.ForeignKey(
        ReservationSystem,
        verbose_name=_(u"Reservation system"),
        blank=True,
        null=True)
    reservation_id = models.CharField(verbose_name=_(u"Reservation ID"),
                                      max_length=128,
                                      blank=True,
                                      db_column='id_reservation')
    approved = models.BooleanField(verbose_name=_(u"Approved"),
                                   default=False,
                                   db_column='labellise')

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

    class Meta:
        db_table = 't_t_contenu_touristique'
        verbose_name = _(u"Touristic content")
        verbose_name_plural = _(u"Touristic contents")

    def __unicode__(self):
        return self.name

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

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

    @property
    def type1_label(self):
        return self.category.type1_label

    @property
    def type2_label(self):
        return self.category.type2_label

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

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

    @property
    def prefixed_category_id(self):
        return self.category.prefixed_id

    def distance(self, to_cls):
        return settings.TOURISM_INTERSECTION_MARGIN

    @property
    def type(self):
        """Fake type to simulate POI for mobile app v1"""
        return self.category

    @property
    def min_elevation(self):
        return 0

    @property
    def max_elevation(self):
        return 0
示例#9
0
class Blade(NoDeleteMixin, MapEntityMixin, StructureRelated):
    signage = models.ForeignKey(Signage,
                                db_column='signaletique',
                                verbose_name=_("Signage"),
                                on_delete=models.PROTECT)
    number = models.CharField(verbose_name=_("Number"),
                              max_length=250,
                              db_column='numero')
    direction = models.ForeignKey(Direction,
                                  verbose_name=_("Direction"),
                                  db_column='direction',
                                  on_delete=models.PROTECT)
    type = models.ForeignKey(BladeType,
                             db_column='type',
                             verbose_name=_("Type"))
    color = models.ForeignKey(Color,
                              db_column='couleur',
                              on_delete=models.PROTECT,
                              null=True,
                              blank=True,
                              verbose_name=_("Color"))
    condition = models.ForeignKey(InfrastructureCondition,
                                  db_column='etat',
                                  verbose_name=_("Condition"),
                                  null=True,
                                  blank=True,
                                  on_delete=models.PROTECT)
    topology = models.ForeignKey(Topology,
                                 related_name="blades_set",
                                 verbose_name=_("Blades"))
    objects = NoDeleteMixin.get_manager_cls(BladeManager)()

    class Meta:
        db_table = 's_t_lame'
        verbose_name = _("Blade")
        verbose_name_plural = _("Blades")

    def __str__(self):
        return settings.BLADE_CODE_FORMAT.format(signagecode=self.signage.code,
                                                 bladenumber=self.number)

    def set_topology(self, topology):
        self.topology = topology
        if not self.is_signage:
            raise ValueError("Expecting a signage")

    @property
    def is_signage(self):
        if self.topology:
            return self.topology.kind == Signage.KIND
        return False

    @property
    def geom(self):
        return self.topology.geom

    @geom.setter
    def geom(self, value):
        self._geom = value

    @property
    def signage_display(self):
        return '<img src="%simages/signage-16.png" title="Signage">' % settings.STATIC_URL

    @property
    def order_lines(self):
        return self.lines.order_by('number')

    @property
    def number_display(self):
        s = '<a data-pk="%s" href="%s" title="%s" >%s</a>' % (
            self.pk, self.get_detail_url(), self, self)
        return s
示例#10
0
class SensitiveArea(MapEntityMixin, StructureRelated, TimeStampedModelMixin, NoDeleteMixin,
                    AddPropertyMixin):
    geom = models.GeometryField(srid=settings.SRID)
    species = models.ForeignKey(Species, verbose_name=_(u"Sensitive area"), db_column='espece',
                                on_delete=models.PROTECT)
    published = models.BooleanField(verbose_name=_(u"Published"), default=False,
                                    help_text=_(u"Online"), db_column='public')
    publication_date = models.DateField(verbose_name=_(u"Publication date"),
                                        null=True, blank=True, editable=False,
                                        db_column='date_publication')
    description = models.TextField(verbose_name=_("Description"), blank=True)
    contact = models.TextField(verbose_name=_("Contact"), blank=True)
    eid = models.CharField(verbose_name=_(u"External id"), max_length=128, blank=True, null=True,
                           db_column='id_externe')

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

    class Meta:
        db_table = 's_t_zone_sensible'
        verbose_name = _(u"Sensitive area")
        verbose_name_plural = _(u"Sensitive areas")
        permissions = (
            ("import_sensitivearea", "Can import Sensitive area"),
        )

    def __unicode__(self):
        return self.species.name

    @property
    def radius(self):
        if self.species.radius is None:
            return settings.SENSITIVITY_DEFAULT_RADIUS
        return self.species.radius

    @classproperty
    def radius_verbose_name(cls):
        return _("Radius")

    @property
    def category_display(self):
        return self.species.get_category_display()

    @classproperty
    def category_verbose_name(cls):
        return _("Category")

    def save(self, *args, **kwargs):
        if self.publication_date is None and self.published:
            self.publication_date = datetime.date.today()
        if self.publication_date is not None and not self.published:
            self.publication_date = None
        super(SensitiveArea, self).save(*args, **kwargs)

    @property
    def any_published(self):
        return self.published

    @property
    def published_status(self):
        """Returns the publication status by language.
        """
        status = []
        for l in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']:
            status.append({
                'lang': l[0],
                'language': l[1],
                'status': self.published
            })
        return status

    @property
    def published_langs(self):
        """Returns languages in which the object is published.
        """
        if self.published:
            return [l[0] for l in settings.MAPENTITY_CONFIG['TRANSLATED_LANGUAGES']]
        else:
            return []

    @property
    def species_display(self):
        s = u'<a data-pk="%s" href="%s" title="%s">%s</a>' % (self.pk,
                                                              self.get_detail_url(),
                                                              self.species.name,
                                                              self.species.name)
        if self.published:
            s = u'<span class="badge badge-success" title="%s">&#x2606;</span> ' % _("Published") + s
        return s

    @property
    def extent(self):
        return self.geom.transform(settings.API_SRID, clone=True).extent if self.geom else None

    def kml(self):
        """Exports sensitivearea into KML format"""
        kml = simplekml.Kml()
        geom = self.geom
        if geom.geom_type == 'Point':
            geom = geom.buffer(self.species.radius or settings.SENSITIVITY_DEFAULT_RADIUS, 4)
        geom = geom.transform(4326, clone=True)  # KML uses WGS84
        line = kml.newpolygon(name=self.species.name,
                              description=plain_text(self.description),
                              outerboundaryis=geom.coords[0])
        line.style.linestyle.color = simplekml.Color.red  # Red
        line.style.linestyle.width = 4  # pixels
        return kml.kml()

    def is_public(self):
        return self.published

    @property
    def pretty_period(self):
        return self.species.pretty_period()
    pretty_period_verbose_name = _("Period")

    @property
    def pretty_practices(self):
        return self.species.pretty_practices()
    pretty_practices_verbose_name = _("Practices")
示例#11
0
class TouristicContent(AddPropertyMixin, PublishableMixin, MapEntityMixin,
                       StructureRelated, TimeStampedModelMixin, PicturesMixin,
                       NoDeleteMixin):
    """ A generic touristic content (accomodation, museum, etc.) in the park
    """
    description_teaser = models.TextField(
        verbose_name=_(u"Description teaser"),
        blank=True,
        help_text=_(u"A brief summary"),
        db_column='chapeau')
    description = models.TextField(verbose_name=_(u"Description"),
                                   blank=True,
                                   db_column='description',
                                   help_text=_(u"Complete description"))
    themes = models.ManyToManyField(Theme,
                                    related_name="touristiccontents",
                                    db_table="t_r_contenu_touristique_theme",
                                    blank=True,
                                    verbose_name=_(u"Themes"),
                                    help_text=_(u"Main theme(s)"))
    geom = models.GeometryField(verbose_name=_(u"Location"),
                                srid=settings.SRID)
    category = models.ForeignKey(TouristicContentCategory,
                                 related_name='contents',
                                 verbose_name=_(u"Category"),
                                 db_column='categorie')
    contact = models.TextField(verbose_name=_(u"Contact"),
                               blank=True,
                               db_column='contact',
                               help_text=_(u"Address, phone, etc."))
    email = models.EmailField(verbose_name=_(u"Email"),
                              max_length=256,
                              db_column='email',
                              blank=True,
                              null=True)
    website = models.URLField(verbose_name=_(u"Website"),
                              max_length=256,
                              db_column='website',
                              blank=True,
                              null=True)
    practical_info = models.TextField(verbose_name=_(u"Practical info"),
                                      blank=True,
                                      db_column='infos_pratiques',
                                      help_text=_(u"Anything worth to know"))
    type1 = models.ManyToManyField(TouristicContentType,
                                   related_name='contents1',
                                   verbose_name=_(u"Type 1"),
                                   db_table="t_r_contenu_touristique_type1",
                                   blank=True)
    type2 = models.ManyToManyField(TouristicContentType,
                                   related_name='contents2',
                                   verbose_name=_(u"Type 2"),
                                   db_table="t_r_contenu_touristique_type2",
                                   blank=True)
    source = models.ManyToManyField('common.RecordSource',
                                    blank=True,
                                    related_name='touristiccontents',
                                    verbose_name=_("Source"),
                                    db_table='t_r_contenu_touristique_source')
    portal = models.ManyToManyField('common.TargetPortal',
                                    blank=True,
                                    related_name='touristiccontents',
                                    verbose_name=_("Portal"),
                                    db_table='t_r_contenu_touristique_portal')
    eid = models.CharField(verbose_name=_(u"External id"),
                           max_length=1024,
                           blank=True,
                           null=True,
                           db_column='id_externe')
    reservation_system = models.ForeignKey(
        ReservationSystem,
        verbose_name=_(u"Reservation system"),
        blank=True,
        null=True)
    reservation_id = models.CharField(verbose_name=_(u"Reservation ID"),
                                      max_length=1024,
                                      blank=True,
                                      db_column='id_reservation')
    approved = models.BooleanField(verbose_name=_(u"Approved"),
                                   default=False,
                                   db_column='labellise')

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

    class Meta:
        db_table = 't_t_contenu_touristique'
        verbose_name = _(u"Touristic content")
        verbose_name_plural = _(u"Touristic contents")

    def __unicode__(self):
        return self.name

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

    @property
    def type1_label(self):
        return self.category.type1_label

    @property
    def type2_label(self):
        return self.category.type2_label

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

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

    @property
    def prefixed_category_id(self):
        return self.category.prefixed_id

    def distance(self, to_cls):
        return settings.TOURISM_INTERSECTION_MARGIN

    @property
    def type(self):
        """Fake type to simulate POI for mobile app v1"""
        return self.category

    @property
    def min_elevation(self):
        return 0

    @property
    def max_elevation(self):
        return 0

    @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()])

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

    @property
    def extent(self):
        return self.geom.buffer(10).transform(settings.API_SRID,
                                              clone=True).extent

    @property
    def rando_url(self):
        category_slug = _(u'touristic-content')
        return '{}/{}/'.format(category_slug, self.slug)

    @property
    def meta_description(self):
        return plain_text(self.description_teaser or self.description)[:500]