class Feature(models.Model): """ Model to represent features created in the application. """ STATUS_VALUES = [ 'Unassigned', 'In work', 'Awaiting review', 'In review', 'Completed' ] #'Assigned' STATUS_CHOICES = [(choice, choice) for choice in STATUS_VALUES] aoi = models.ForeignKey(AOI, related_name='features', editable=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) objects = models.GeoManager() analyst = models.ForeignKey(User, editable=False) template = models.ForeignKey("FeatureType", on_delete=models.PROTECT) status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='In work') # Allow the user to save their own properties properties = JSONField(load_kwargs={}, blank=True, null=True) # These help the user identify features when data is exposed outside of the application (Geoserver). job = models.ForeignKey(Job, editable=False) project = models.ForeignKey(Project, editable=False) #Try this vs having individual models the_geom = models.GeometryField(blank=True, null=True) def geoJSON(self, as_json=True, using_style_template=True): """ Returns geoJSON of the feature. Try to conform to https://github.com/mapbox/simplestyle-spec/tree/master/1.0.0 """ properties_main = self.properties or {} properties_built = dict( id=self.id, status=self.status, analyst=self.analyst.username, created_at=datetime.strftime(self.created_at, '%Y-%m-%dT%H:%M:%S%Z'), updated_at=datetime.strftime(self.updated_at, '%Y-%m-%dT%H:%M:%S%Z'), ) properties_template = self.template.properties or {} # properties_template can return a list from it's backing model, make sure we get the Dict if type(properties_template) == types.ListType: properties_template = properties_template[0] # srj: if using_style_template set, we're styling object from its feature id, else we'll # just use the style properties (which should already be included if defined for feature) # (we may want to set some defaults later on to make sure) if using_style_template: properties_built['template'] = self.template.id if hasattr( self.template, "id") else None properties = dict(properties_built.items() + properties_main.items() + properties_template.items()) feature_type = FeatureType.objects.get(id=self.template.id) geojson = SortedDict() geojson["type"] = "Feature" geojson["properties"] = properties geojson["geometry"] = json.loads(self.the_geom.json) if feature_type and using_style_template: geojson["style"] = feature_type.style_to_geojson() else: geojson["style"] = feature_type.style if (as_json): return clean_dumps(geojson) else: for key in properties: if isinstance(properties[key], str) or isinstance( properties[key], unicode): properties[key] = properties[key].replace( '<', '<l').replace('>', '>').replace( "javascript:", "j_script-") return geojson def json_item(self, show_detailed_properties=False): properties_main = self.properties or {} #Pull the County data if it exists, otherwise find it and add it back to the object if properties_main.has_key('county'): county = properties_main['county'] else: county_list = Counties.objects.filter( poly__contains=self.the_geom.centroid.wkt) if len(county_list): county = str(county_list[0].name) else: county = "Unknown" self.properties = properties_main if not show_detailed_properties: if 'linked_items' in properties_main: properties_main['linked_items'] = True else: properties_main['linked_items'] = False properties_built = dict( id=self.id, feature_type=str(self.template.name) if hasattr( self.template, "name") else self.template.id, analyst=str(self.analyst.username), workcell_id=self.aoi.id, status=str(self.status), county=county # created_at=datetime.strftime(self.created_at, '%Y-%m-%dT%H:%M:%S%Z'), # updated_at=datetime.strftime(self.updated_at, '%Y-%m-%dT%H:%M:%S%Z'), ) properties_feature = dict(self.template.properties or {}) properties = dict(properties_main.items() + properties_built.items() + properties_feature.items()) return properties def __unicode__(self): return "Feature created for {0}".format(self.aoi.name) def clean(self): obj_geom_type = self.the_geom.geom_type.lower() template_geom_type = self.template.type.lower() if obj_geom_type != template_geom_type: error_text = "Feature type {0} does not match the template's feature type {1}." raise ValidationError( error_text.format(obj_geom_type, template_geom_type)) class Meta: ordering = ( '-updated_at', 'aoi', )
class AggregationBase(models.Model): slug = models.CharField(max_length=50, primary_key=True) centroid = models.GeometryField(blank=True, null=True) sum_schools = models.BigIntegerField(null=True, blank=True) sum_govt_schools = models.BigIntegerField(null=True, blank=True) sum_rural_schools = models.BigIntegerField(null=True, blank=True) avg_distance_brc = models.FloatField(null=True, blank=True) avg_distance_crc = models.FloatField(null=True, blank=True) sum_pre_primary_schools = models.BigIntegerField(null=True, blank=True) sum_residential_schools = models.BigIntegerField(null=True, blank=True) sum_pre_primary_students = models.BigIntegerField(null=True, blank=True) avg_pre_primary_students = models.FloatField(null=True, blank=True) sum_shift_schools = models.BigIntegerField(null=True, blank=True) sum_no_of_working_days = models.BigIntegerField(null=True, blank=True) avg_no_of_working_days = models.FloatField(null=True, blank=True) sum_no_of_acad_inspection = models.BigIntegerField(null=True, blank=True) avg_no_of_acad_inspection = models.FloatField(null=True, blank=True) sum_visits_by_brc = models.BigIntegerField(null=True, blank=True) avg_visits_by_brc = models.FloatField(null=True, blank=True) sum_visits_by_crc = models.BigIntegerField(null=True, blank=True) avg_visits_by_crc = models.FloatField(null=True, blank=True) sum_school_dev_grant_recd = models.FloatField(null=True, blank=True) avg_school_dev_grant_recd = models.FloatField(null=True, blank=True) sum_school_dev_grant_expnd = models.FloatField(null=True, blank=True) avg_school_dev_grant_expnd = models.FloatField(null=True, blank=True) sum_tlm_grant_recd = models.FloatField(null=True, blank=True) avg_tlm_grant_recd = models.FloatField(null=True, blank=True) sum_tlm_grant_expnd = models.FloatField(null=True, blank=True) avg_tlm_grant_expnd = models.FloatField(null=True, blank=True) sum_funds_from_students_recd = models.FloatField(null=True, blank=True) avg_funds_from_students_recd = models.FloatField(null=True, blank=True) sum_funds_from_students_expnd = models.FloatField(null=True, blank=True) avg_funds_from_students_expnd = models.FloatField(null=True, blank=True) sum_tot_clrooms = models.BigIntegerField(null=True, blank=True) avg_tot_clrooms = models.FloatField(null=True, blank=True) sum_classrooms_in_good_condition = models.BigIntegerField(null=True, blank=True) avg_classrooms_in_good_condition = models.FloatField(null=True, blank=True) sum_has_classrooms_in_good_condition = models.BigIntegerField(null=True, blank=True) sum_classrooms_require_major_repair = models.BigIntegerField(null=True, blank=True) avg_classrooms_require_major_repair = models.FloatField(null=True, blank=True) sum_classrooms_require_minor_repair = models.BigIntegerField(null=True, blank=True) avg_classrooms_require_minor_repair = models.FloatField(null=True, blank=True) sum_other_rooms_in_good_cond = models.BigIntegerField(null=True, blank=True) avg_other_rooms_in_good_cond = models.FloatField(null=True, blank=True) sum_other_rooms_need_major_rep = models.BigIntegerField(null=True, blank=True) avg_other_rooms_need_major_rep = models.FloatField(null=True, blank=True) sum_other_rooms_need_minor_rep = models.BigIntegerField(null=True, blank=True) avg_other_rooms_need_minor_rep = models.FloatField(null=True, blank=True) sum_toilet_common = models.BigIntegerField(null=True, blank=True) avg_toilet_common = models.FloatField(null=True, blank=True) sum_toilet_boys = models.BigIntegerField(null=True, blank=True) avg_toilet_boys = models.FloatField(null=True, blank=True) sum_toilet_girls = models.BigIntegerField(null=True, blank=True) avg_toilet_girls = models.FloatField(null=True, blank=True) sum_kitchen_devices_grant = models.BigIntegerField(null=True, blank=True) avg_kitchen_devices_grant = models.FloatField(null=True, blank=True) sum_has_mdm = models.BigIntegerField(null=True, blank=True) sum_has_cal_lab = models.BigIntegerField(null=True, blank=True) sum_has_separate_room_for_headmaster = models.BigIntegerField(null=True, blank=True) sum_has_electricity = models.BigIntegerField(null=True, blank=True) sum_has_boundary_wall = models.BigIntegerField(null=True, blank=True) sum_has_library = models.BigIntegerField(null=True, blank=True) sum_books_in_library = models.BigIntegerField(null=True, blank=True) avg_books_in_library = models.FloatField(null=True, blank=True) sum_has_playground = models.BigIntegerField(null=True, blank=True) sum_has_blackboard = models.BigIntegerField(null=True, blank=True) sum_has_drinking_water = models.BigIntegerField(null=True, blank=True) sum_has_medical_checkup = models.BigIntegerField(null=True, blank=True) sum_has_ramps = models.BigIntegerField(null=True, blank=True) sum_has_computer = models.BigIntegerField(null=True, blank=True) sum_has_toilet = models.BigIntegerField(null=True, blank=True) sum_has_girls_toilet = models.BigIntegerField(null=True, blank=True) sum_no_of_computers = models.BigIntegerField(null=True, blank=True) avg_no_of_computers = models.FloatField(null=True, blank=True) sum_male_tch = models.BigIntegerField(null=True, blank=True) avg_male_tch = models.FloatField(null=True, blank=True) sum_female_tch = models.BigIntegerField(null=True, blank=True) avg_female_tch = models.FloatField(null=True, blank=True) sum_noresp_tch = models.BigIntegerField(null=True, blank=True) avg_noresp_tch = models.FloatField(null=True, blank=True) sum_head_teacher = models.BigIntegerField(null=True, blank=True) avg_head_teacher = models.FloatField(null=True, blank=True) sum_graduate_teachers = models.BigIntegerField(null=True, blank=True) avg_graduate_teachers = models.FloatField(null=True, blank=True) sum_tch_with_professional_qualification = models.BigIntegerField(null=True, blank=True) avg_tch_with_professional_qualification = models.FloatField(null=True, blank=True) sum_days_involved_in_non_tch_assgn = models.BigIntegerField(null=True, blank=True) avg_days_involved_in_non_tch_assgn = models.FloatField(null=True, blank=True) sum_teachers_involved_in_non_tch_assgn = models.BigIntegerField(null=True, blank=True) avg_teachers_involved_in_non_tch_assgn = models.FloatField(null=True, blank=True) sum_boys = models.BigIntegerField(blank=True, null=True) avg_boys = models.FloatField(blank=True, null=True) sum_girls = models.BigIntegerField(blank=True, null=True) avg_girls = models.FloatField(blank=True, null=True) objects = models.GeoManager() class Meta: abstract = True @property def session(self): """Finds session of the current object from table name """ # extracts the 4 digit session from table name session = filter(str.isdigit, str(self._meta.db_table)) listified_session = list(session) listified_session.insert(2, '-') session = ''.join(listified_session) return session
class Station(models.Model): id = models.IntegerField(primary_key=True) data_id = models.IntegerField(db_index=True) code = models.CharField(max_length=16, db_index=True) name = models.CharField(max_length=255) zone = models.CharField(max_length=16) state = models.CharField(max_length=128) address = models.CharField(max_length=512, blank=True) point = models.PointField(blank=True, null=True) objects = models.GeoManager() def __unicode__(self): return "%s: %s" % ( self.code, self.name, ) @classmethod def import_from_csv(kls, path_to_csv): stations = csv.DictReader(open(path_to_csv)) for s in stations: station = Station(**s) station.save() print station.id @classmethod def import_locations(kls, path_to_json): geojson = json.load(open(path_to_json)) features = geojson['features'] for f in features: station_code = f['properties']['code'].upper() station = Station.objects.get(code=station_code) lon = f['geometry']['coordinates'][0] lat = f['geometry']['coordinates'][1] if lon == 0 or lon == '': continue try: pt = Point(lon, lat) except: print json.dumps(f) raise Error('bad lat-long') station.point = pt station.save() print station_code def get_geojson(self): return { 'type': 'Feature', 'geometry': json.loads(self.point.geojson) if self.point else None, 'properties': { 'code': self.code, 'name': self.name, 'state': self.state, 'address': self.address } } def get_destinations(self): geojson = self.get_geojson() geojson['properties']['destinations'] = [] for s in self.schedule_set.filter( minor_stop_number=0).select_related('train__to_station'): last_stop = s.train.to_station last_stop_geojson = last_stop.get_geojson() last_stop_geojson['properties']['train_number'] = s.train.number last_stop_geojson['properties']['train_name'] = s.train.name geojson['properties']['destinations'].append(last_stop_geojson) return geojson @classmethod def get_all_destinations(kls): return [s.get_destinations() for s in Station.objects.all()] @classmethod def import_osm_geojson(kls, path_to_file): osm_data = json.load(open(path_to_file)) count = 0 for feature in osm_data['features']: if 'ref' in feature['properties']: count += 1 code = feature['properties']['ref'] try: station = Station.objects.get(code=code) except: continue station.point = Point(feature['geometry']['coordinates'][0], feature['geometry']['coordinates'][1]) station.save() print station.name print count @classmethod def match_osm_names(kls, path_to_file): osm_data = json.load(open(path_to_file)) for feature in osm_data['features']: if 'name' in feature['properties']: name = feature['properties']['name'] first_name = name.split(' ')[0] stations = Station.objects.filter(point=None).filter( name__iexact=first_name) if stations.count() == 1: station = stations[0] station.point = Point( feature['geometry']['coordinates'][0], feature['geometry']['coordinates'][1]) station.save() print station.name
class Boundary(MyModel): poly = models.PolygonField("Boundary", blank=True) isconfirmed = models.BooleanField("Confirmed?", ) boundary_type = models.ForeignKey(BoundaryType) owner = CurrentUserField(blank=True, related_name="nam_owner", default=1) modifier = CurrentUserField(blank=True, related_name="nam_modifier", default=1) related = models.ManyToManyField("self", symmetrical=False, null=True, blank=True, through='boundaries.BoundariesRelated', related_name='related_boundary') name = models.CharField("Name", max_length=128, blank=True) number = models.PositiveIntegerField("Number", null=True, blank=True) geo_name_id = models.PositiveIntegerField("GEO Name ID", null=True, blank=True) previousnumber = models.CharField("Previous Number", max_length=32, blank=True) code = models.CharField("Code", max_length=32, blank=True) previouscode = models.CharField("Previous Code", max_length=32, blank=True) postalcode = models.CharField("Zip Code", max_length=32, blank=True) #area_kml = models.DecimalField("Area Kilometers", max_digits=11, decimal_places=7, null=True, blank=True) #population = models.PositiveIntegerField("Population", null=True, blank=True) #population_target_language = models.PositiveIntegerField("English Population", null=True, blank=True) notes = models.TextField("Notes", blank=True) objects = models.GeoManager() #helper functions #b = Boundary.objects.all()[0] #pt = b.pt_from_long_lat(-84.1453933304581, 9.97895563839969) #b.contains(pt) def pt_from_long_lat(self, long, lat): from django.contrib.gis.geos import fromstr return fromstr("POINT(%s %s)" % (long, lat)) def contains(self, pt): return self.poly.contains(pt) # http://nemo.seaports2100.org/doku.php/tutorials/sebastian/geomysql # input - KML Polygon (well-formatted) def kml2poly(self, kml_str): # Begin MySQL Polygon output output = 'POLYGON(' # Import XML parser from xml.dom.minidom import parseString # Parse KML kml_str i = parseString(kml_str) # Get outer rings coordinates outercoords = i.getElementsByTagName( "outerBoundaryIs")[0].getElementsByTagName( "coordinates")[0].firstChild.nodeValue.strip() # Start outer ring output output += '(' # For each point in coordinates, add to output for pt in outercoords.split(' '): lon, lat, elev = pt.split(',') output += lon + " " + lat + "," # Strip last comma from output and close outer ring output = output[:-1] + ")" # Get number of inner rings irings = len(i.getElementsByTagName("innerBoundaryIs")) # For each inner ring, add to output for n in range(irings): # Get rind coordinates innercoords = i.getElementsByTagName( "innerBoundaryIs")[n].getElementsByTagName( "coordinates")[0].firstChild.nodeValue.strip() # Start output output += ",(" # For each point in coordinates, add to output for pt in outercoords.split(' '): lon, lat, elev = pt.split(',') output += lon + " " + lat + "," # Strip last comma from output and close ring output = output[:-1] + ")" # End Polygon output output += ')' # Return formatted MySQL Polygon return output #Load poly from kml string: #'<Polygon><outerBoundaryIs><LinearRing><coordinates>-84.1453933305,9.9789556384,0 -84.1436421837,9.97173599811,0 -84.1367912059,9.96863308888,0 -84.1352551122,9.97121372626,0 -84.135777384,9.97176671998,0 -84.1358081059,9.97228899183,0 -84.1338111841,9.97342570116,0 -84.1351015028,9.97708160411,0 -84.1324901436,9.98294948196,0 -84.1326437529,9.98301092571,0 -84.134087681,9.98172060702,0 -84.1369448152,9.98150555391,0 -84.1379586371,9.98110616955,0 -84.138450187,9.98273442885,0 -84.1406007182,9.98341031007,0 -84.1416759838,9.98193566014,0 -84.1453933305,9.9789556384,0</coordinates></LinearRing></outerBoundaryIs></Polygon>' def set_poly_from_kml_str(self, kml_str): self.poly = self.kml2poly(kml_str) # a start for creating links to where this boundary may reside/be contained within def geo_tag(self): center_pt = self.center_pt bscontains = Boundary.objects.exclude(boundary_type__id=5).filter( poly__contains=center_pt) for b in bscontains: print b @property def coords(self): return self.poly.coords if self.poly else None @property def boundary(self): return self.poly.boundary if self.poly else None @property def kml(self): return self.poly.kml if self.poly else None @property def center_pt(self): return self.poly.centroid if self.poly else None @property def full_name(self): ret = u'' if self.boundary_type: ret = self.boundary_type.title ret += u'-' if ret else u'' if self.name: ret += self.name return ret @property def number_path(self): related_title = u'' related_title = str(self.number) if self.number else u'' return related_title class Meta: #app_label = u'boundaries' db_table = u'flt_boundaries' # db_table = u'flt_boundaries_test' #unique_together = ("boundary_type", "name", "number", "code"), verbose_name_plural = "boundaries" permissions = (('access_boundaries', 'Access to Boundaries'), ) #def get_absolute_url(self): #return "/boundary/%i/" % self.id def type(self): return u'boundary' def __unicode__(self): return self.full_name + ' | ' + self.number_path + ' : ' + str(self.id)
class Job(UIDMixin, TimeStampedModelMixin): """ Model for a Job. """ def __init__(self, *args, **kwargs): kwargs['the_geom'] = convert_polygon(kwargs.get('the_geom')) or '' kwargs['the_geom_webmercator'] = convert_polygon(kwargs.get('the_geom_webmercator')) or '' kwargs['the_geog'] = convert_polygon(kwargs.get('the_geog')) or '' super(Job, self).__init__(*args, **kwargs) user = models.ForeignKey(User, related_name='owner') name = models.CharField(max_length=100, db_index=True) description = models.CharField(max_length=1000, db_index=True) event = models.CharField(max_length=100, db_index=True, default='', blank=True) region = models.ForeignKey(Region, null=True, blank=True, on_delete=models.SET_NULL) provider_tasks = models.ManyToManyField(DataProviderTask, related_name='provider_tasks') preset = models.ForeignKey(DatamodelPreset, null=True, blank=True) published = models.BooleanField(default=False, db_index=True) # publish export featured = models.BooleanField(default=False, db_index=True) # datapack is featured the_geom = models.MultiPolygonField(verbose_name='Extent for export', srid=4326, default='') the_geom_webmercator = models.MultiPolygonField(verbose_name='Mercator extent for export', srid=3857, default='') the_geog = models.MultiPolygonField(verbose_name='Geographic extent for export', geography=True, default='') original_selection = models.GeometryCollectionField(verbose_name='The original map selection', srid=4326, default=GeometryCollection(), null=True, blank=True) objects = models.GeoManager() include_zipfile = models.BooleanField(default=False) json_tags = JSONField(default=dict) class Meta: # pragma: no cover managed = True db_table = 'jobs' def save(self, *args, **kwargs): self.the_geom = convert_polygon(self.the_geom) self.the_geog = GEOSGeometry(self.the_geom) self.the_geom_webmercator = self.the_geom.transform(ct=3857, clone=True) super(Job, self).save(*args, **kwargs) def __str__(self): return '{0}'.format(self.name) @property def overpass_extents(self,): """ Return the export extents in order required by Overpass API. """ extents = GEOSGeometry(self.the_geom).extent # (w,s,e,n) # overpass needs extents in order (s,w,n,e) overpass_extents = '{0},{1},{2},{3}'.format(str(extents[1]), str(extents[0]), str(extents[3]), str(extents[2])) return overpass_extents @property def extents(self,): return GEOSGeometry(self.the_geom).extent # (w,s,e,n) @property def filters(self,): """ Return key=value pairs for each tag in this export. Used in utils.overpass.filter to filter the export. """ # Command-line key=value filters for osmfilter filters = [] for tag in self.json_tags: kv = '{0}={1}'.format(tag['key'], tag['value']) filters.append(kv) return filters @property def categorised_tags(self,): """ Return tags mapped according to their geometry types. """ points = set() lines = set() polygons = set() for tag in self.json_tags: if 'point' in tag['geom']: points.add(tag['key']) if 'line' in tag['geom']: lines.add(tag['key']) if 'polygon' in tag['geom']: polygons.add(tag['key']) return {'points': sorted(list(points)), 'lines': sorted(list(lines)), 'polygons': sorted(list(polygons))} @property def bounds_geojson(self,): return serialize('geojson', [self], geometry_field='the_geom', fields=('name', 'the_geom'))
class Lieu(models.Model): name = models.CharField(max_length=512, help_text=_("nom du lieu"), verbose_name=_("lieu de la reprรฉsentation")) # allowed_users = models.ManyToManyField(CustomUser, # null = True, # blank = True, # verbose_name = _('utilisateur authorisรฉ')) phoneNumber = models.CharField( max_length=512, null=True, blank=True, verbose_name=_("numรฉro de tรฉlรฉphone du lieu")) city = models.CharField(max_length=512, verbose_name=_("ville")) zipCode = models.CharField(max_length=64, null=True, blank=True, verbose_name=_("code postal")) adress = models.CharField(max_length=512, verbose_name=_("adresse")) adress2 = models.CharField(max_length=512, null=True, blank=True, verbose_name=_("suite de l'adresse")) website = models.URLField(null=True, blank=True, verbose_name=_("site web")) region = models.ForeignKey(RegionChild2, blank=True, null=True, verbose_name=_("commune")) status = models.SmallIntegerField( verbose_name=_("status"), null=True, blank=True, help_text=_( "0 = en crรฉation, 1 = en validation, 3 = public, 4 = exportรฉ vers le cahier " "spรฉcial")) latitude = models.FloatField(null=True, blank=True, verbose_name=_("latitude")) longitude = models.FloatField(verbose_name=_("longitude"), null=True, blank=True) slug = models.SlugField(null=True, blank=True, help_text=_("nom formatรฉ pour les URLs")) old_id = models.IntegerField(null=True, blank=True) ## geodjango magic in_geom = models.PointField( 'shp', srid=4326, help_text=_("Cliquez sur la carte"), null=True, blank=True, ) objects = models.GeoManager() def as_a_link(self): return '<a href="' + self.get_absolute_url( ) + '" class="venue">' + self.name + '</a>' def get_absolute_url(self): from django.core.urlresolvers import reverse return reverse('place', args=[self.slug]) class Meta: verbose_name = _('lieu') verbose_name_plural = _('lieux') def save(self, **kwargs): if self.slug is not None: from regionfestival.snippets import unique_slugify unique_slugify(self, self.name) if self.in_geom is not None: self.longitude = self.in_geom.x self.latitude = self.in_geom.y try: self.region = RegionChild2.objects.get( boundaries__contains=self.in_geom) except: pass elif self.longitude is not None and self.latitude is not None: self.in_geom = 'POINT (' + str(self.latitude) + ' ' + str( self.longitude) + ' )' super(Lieu, self).save(**kwargs) def __str__(self): return self.name
class FireStation(USGSStructureData): """ Fire Stations. """ service_id = 7 fdid = models.CharField(max_length=10, null=True, blank=True) department = models.ForeignKey(FireDepartment, null=True, blank=True, on_delete=models.SET_NULL) station_number = models.IntegerField(null=True, blank=True) station_address = models.ForeignKey(Address, null=True, blank=True) district = models.MultiPolygonField(null=True, blank=True) objects = models.GeoManager() @classmethod def populate_address(cls): us, _ = Country.objects.get_or_create(iso_code='US') for obj in cls.objects.filter(station_address__isnull=True, address__isnull=False, zipcode__isnull=False): try: addr, _ = Address.objects.get_or_create(address_line1=obj.address, city=obj.city, state_province=obj.state, postal_code=obj.zipcode, country=us, defaults=dict(geom=obj.geom)) except Address.MultipleObjectsReturned: objs = Address.objects.filter(address_line1=obj.address, city=obj.city, state_province=obj.state, postal_code=obj.zipcode, country=us) import ipdb; ipdb.set_trace() obj.station_address = addr obj.save() @property def origin_uri(self): """ This object's URI (from the national map). """ return 'http://services.nationalmap.gov/arcgis/rest/services/structures/MapServer/7/{0}?f=json' \ .format(self.objectid) @classmethod def load_data(cls): objects = requests.get('http://services.nationalmap.gov/arcgis/rest/services/structures/MapServer/7/query?' 'where=1%3D1&text=&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&' 'spatialRel=esriSpatialRelIntersects&relationParam=&outFields=&returnGeometry=true&' 'maxAllowableOffset=&geometryPrecision=&outSR=&returnIdsOnly=true&returnCountOnly=false&' 'orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&' 'gdbVersion=&returnDistinctValues=false&f=json') current_ids = set(FireStation.objects.all().values_list('objectid', flat=True)) object_ids = set(json.loads(objects.content)['objectIds']) - current_ids url = 'http://services.nationalmap.gov/arcgis/rest/services/structures/MapServer/7/{0}?f=json' us, _ = Country.objects.get_or_create(iso_code='US') for object in object_ids: try: if FireStation.objects.filter(objectid=object): continue obj = requests.get(url.format(object)) obj = json.loads(obj.content) data = dict((k.lower(), v) for k, v in obj['feature']['attributes'].iteritems()) if obj['feature'].get('geometry'): data['geom'] = Point(obj['feature']['geometry']['x'], obj['feature']['geometry']['y']) data['loaddate'] = datetime.datetime.fromtimestamp(data['loaddate']/1000.0) feat = cls.objects.create(**data) feat.save() print 'Saved object: {0}'.format(data.get('name')) print '{0} Firestations loaded.'.format(FireStation.objects.all().count()) except KeyError: print '{0} failed.'.format(object) print url.format(object) except IntegrityError: print '{0} failed.'.format(object) print url.format(object) print sys.exc_info() try: rollback() except: pass except: print '{0} failed.'.format(object) print url.format(object) print sys.exc_info() @property def district_area(self): """ Project the district's geometry into north america lambert conformal conic Returns km2 """ if self.district: try: return self.district.transform(102009, clone=True).area / 1000000 except: return def get_absolute_url(self): return reverse('firestation_detail', kwargs=dict(pk=self.id)) class Meta: verbose_name = 'Fire Station'
class Map(NamedModel): """ A single thematical map. """ ANONYMOUS = 1 EDITORS = 2 OWNER = 3 PUBLIC = 1 OPEN = 2 PRIVATE = 3 EDIT_STATUS = ( (ANONYMOUS, _('Everyone can edit')), (EDITORS, _('Only editors can edit')), (OWNER, _('Only owner can edit')), ) SHARE_STATUS = ( (PUBLIC, _('everyone (public)')), (OPEN, _('anyone with link')), (PRIVATE, _('editors only')), ) slug = models.SlugField(db_index=True) description = models.TextField(blank=True, null=True, verbose_name=_("description")) center = models.PointField(geography=True, verbose_name=_("center")) zoom = models.IntegerField(default=7, verbose_name=_("zoom")) locate = models.BooleanField(default=False, verbose_name=_("locate"), help_text=_("Locate user on load?")) licence = models.ForeignKey( Licence, help_text=_("Choose the map licence."), verbose_name=_('licence'), on_delete=models.SET_DEFAULT, default=get_default_licence ) modified_at = models.DateTimeField(auto_now=True) tilelayer = models.ForeignKey(TileLayer, blank=True, null=True, related_name="maps", verbose_name=_("background")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="owned_maps", verbose_name=_("owner")) editors = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, verbose_name=_("editors")) edit_status = models.SmallIntegerField(choices=EDIT_STATUS, default=OWNER, verbose_name=_("edit status")) share_status = models.SmallIntegerField(choices=SHARE_STATUS, default=PUBLIC, verbose_name=_("share status")) settings = DictField(blank=True, null=True, verbose_name=_("settings")) objects = models.GeoManager() public = PublicManager() def get_absolute_url(self): return reverse("map", kwargs={'slug': self.slug or "map", 'pk': self.pk}) def get_anonymous_edit_url(self): signer = Signer() signature = signer.sign(self.pk) return reverse('map_anonymous_edit_url', kwargs={'signature': signature}) def is_anonymous_owner(self, request): if self.owner: # edit cookies are only valid while map hasn't owner return False key, value = self.signed_cookie_elements try: has_anonymous_cookie = int(request.get_signed_cookie(key, False)) == value except ValueError: has_anonymous_cookie = False return has_anonymous_cookie def can_edit(self, user=None, request=None): """ Define if a user can edit or not the instance, according to his account or the request. """ can = False if request and not self.owner: if (getattr(settings, "LEAFLET_STORAGE_ALLOW_ANONYMOUS", False) and self.is_anonymous_owner(request)): can = True if user and user.is_authenticated(): # if user is authenticated, attach as owner self.owner = user self.save() msg = _("Your anonymous map has been attached to your account %s" % user) messages.info(request, msg) if self.edit_status == self.ANONYMOUS: can = True elif not user.is_authenticated(): pass elif user == self.owner: can = True elif self.edit_status == self.EDITORS and user in self.editors.all(): can = True return can def can_view(self, request): if self.owner is None: can = True elif self.share_status in [self.PUBLIC, self.OPEN]: can = True elif request.user == self.owner: can = True else: can = not (self.share_status == self.PRIVATE and request.user not in self.editors.all()) return can @property def signed_cookie_elements(self): return ('anonymous_owner|%s' % self.pk, self.pk) def get_tilelayer(self): return self.tilelayer or TileLayer.get_default() def clone(self, **kwargs): new = self.__class__.objects.get(pk=self.pk) new.pk = None new.name = u"%s %s" % (_("Clone of"), self.name) if "owner" in kwargs: #ย can be None in case of anonymous cloning new.owner = kwargs["owner"] new.save() for editor in self.editors.all(): new.editors.add(editor) for datalayer in self.datalayer_set.all(): datalayer.clone(map_inst=new) return new
class Checkin(models.Model): time = models.DateTimeField() user = models.ForeignKey(User) place = models.ForeignKey(Place) note = models.TextField() objects = gismodels.GeoManager()
class Commune(models.Model, GEOFLAManager): GEOFLA_DBF_FIELDS = [ 'ID_GEOFLA', 'CODE_COMM', 'INSEE_COM', 'NOM_COMM', 'STATUT', 'X_CHF_LIEU', 'Y_CHF_LIEU', 'X_CENTROID', 'Y_CENTROID', 'Z_MOYEN', 'SUPERFICIE', 'POPULATION', 'CODE_CANT', 'CODE_ARR', 'CODE_DEPT', 'NOM_DEPT', 'CODE_REG', 'NOM_REGION' ] GEOFLAFIELDS = [ GFFM('ID_GEOFLA', 'id_geofla', int), GFFM('CODE_COMM', 'code_comm', 'to_unicode'), GFFM('INSEE_COM', 'insee_com', 'to_unicode'), GFFM('NOM_COMM', 'nom_comm', 'to_unicode'), GFFM('STATUT', 'statut', 'to_choice', choices=STATUT_COMMUNE), GFFM(('X_CHF_LIEU', 'Y_CHF_LIEU'), 'chf_lieu', 'to_point'), GFFM(('X_CENTROID', 'Y_CENTROID'), 'centroid', 'to_point'), GFFM('Z_MOYEN', 'z_moyen', int), GFFM('SUPERFICIE', 'superficie', int), GFFM('POPULATION', 'population', float), ] #GFFM(('CODE_CANT', 'CODE_ARR', 'CODE_DEPT', 'NOM_DEPT'), 'canton', # 'get_instance', instance_class=Canton),] id_geofla = models.IntegerField(primary_key=True) code_comm = models.CharField(verbose_name=u"Code commune", null=True, blank=True, max_length=3) insee_com = models.CharField(verbose_name=u"Code INSEE", null=True, blank=True, max_length=5) nom_comm = models.CharField(verbose_name=u"Nom", null=True, blank=True, max_length=50) statut = models.CharField(verbose_name=u"Statut", null=True, blank=True, max_length=2, choices=STATUT_COMMUNE) chf_lieu = models.PointField(verbose_name=u"Chef lieu", null=True, blank=True, srid=settings.EPSG) centroid = models.PointField(verbose_name=u"Centroรฏde", null=True, blank=True, srid=settings.EPSG) z_moyen = models.IntegerField(verbose_name=u"Altitude moyenne (m)", null=True, blank=True) superficie = models.IntegerField(verbose_name=u"Superficie (ha)", null=True, blank=True) population = models.FloatField(verbose_name=u"Population (en milliers)", null=True, blank=True) limite = models.MultiPolygonField(verbose_name=u"Limite", null=True, blank=True, srid=settings.EPSG) #canton = models.ForeignKey("Canton", null=True, blank=True) objects = models.GeoManager() def __unicode__(self): return self.nom_comm
class Geo(models.Model): STATE_TYPE, COUNTY_TYPE, TRACT_TYPE, METRO_TYPE, MICRO_TYPE = range(1, 6) METDIV_TYPE, = range(6, 7) TYPES = [(STATE_TYPE, 'State'), (COUNTY_TYPE, 'County'), (TRACT_TYPE, 'Census Tract'), (METRO_TYPE, 'Metropolitan'), (MICRO_TYPE, 'Micropolitan'), (METDIV_TYPE, 'Metropolitan Division')] geoid = models.CharField(max_length=20, primary_key=True) geo_type = models.PositiveIntegerField(choices=TYPES, db_index=True) name = models.CharField(max_length=50) state = models.CharField(max_length=2, null=True) county = models.CharField(max_length=3, null=True) tract = models.CharField(max_length=6, null=True) csa = models.CharField(max_length=3, null=True, help_text='Combined Statistical Area') cbsa = models.CharField(max_length=5, null=True, help_text='Core Based Statistical Area') metdiv = models.CharField(max_length=5, null=True, help_text='Metro Division') geom = models.MultiPolygonField(srid=4269) minlat = models.FloatField() maxlat = models.FloatField() minlon = models.FloatField() maxlon = models.FloatField() centlat = models.FloatField() centlon = models.FloatField() objects = models.GeoManager() class Meta: index_together = [("geo_type", "minlat", "minlon"), ("geo_type", "minlat", "maxlon"), ("geo_type", "maxlat", "minlon"), ("geo_type", "maxlat", "maxlon"), ("geo_type", "centlat", "centlon"), ("geo_type", "cbsa")] def as_geojson(self): """Convert this model into a geojson string""" geojson = { 'type': 'Feature', 'geometry': '$_$', # placeholder 'properties': { 'geoid': self.geoid, 'geoType': self.geo_type, 'state': self.state, 'county': self.county, 'cbsa': self.cbsa, 'centlat': self.centlat, 'centlon': self.centlon } } geojson = json.dumps(geojson) return geojson.replace( '"$_$"', self.geom.simplify(preserve_topology=True).geojson)
def create_postal_codes(): @property def parent(self): """Returns region if available, otherwise country""" return self.region if self.region else self.country @property def hierarchy(self): """Get hierarchy, root first""" list = self.parent.hierarchy list.append(self) return list @property def names(self): """Get a hierarchy of non-null names, root first""" return [ e for e in [ force_unicode(self.country), force_unicode(self.region_0_name), force_unicode(self.region_1_name), force_unicode(self.region_2_name), force_unicode(self.name), ] if e ] @property def name_full(self): """Get full name including hierarchy""" return u', '.join(reversed(self.names)) postal_codes = {} for country in settings.postal_codes: name_format = "{}" + country name = name_format.format('PostalCode') postal_codes[country] = create_model( name=name, fields={ 'country': models.ForeignKey(Country, related_name='postal_codes_' + country), 'code': models.CharField(max_length=20, db_index=True), 'name': models.CharField(max_length=200, db_index=True), 'region_0_name': models.CharField(max_length=100, db_index=True, verbose_name="region 0 name (state)"), 'region_1_name': models.CharField(max_length=100, db_index=True, verbose_name="region 1 name (county)"), 'region_2_name': models.CharField(max_length=100, db_index=True, verbose_name="region 2 name (community)"), 'region': models.ForeignKey(Region, null=True, blank=True, related_name='postal_codes_' + country), 'location': models.PointField(), 'objects': models.GeoManager(), 'parent': parent, 'hierarchy': hierarchy, 'names': names, 'name_full': name_full, '__unicode__': lambda self: force_unicode(self.code), }, app_label='cities', module='cities.models', options={ 'db_table': 'cities_' + un_camel(name), 'verbose_name': un_camel(name).replace('_', ' '), 'verbose_name_plural': un_camel(name_format.format('PostalCodes')).replace('_', ' '), }, ) return postal_codes
class InformationDesk(models.Model): name = models.CharField(verbose_name=_(u"Title"), max_length=256, db_column='nom') type = models.ForeignKey(InformationDeskType, verbose_name=_(u"Type"), related_name='desks', db_column='type') description = models.TextField(verbose_name=_(u"Description"), blank=True, db_column='description', help_text=_(u"Brief description")) phone = models.CharField(verbose_name=_(u"Phone"), max_length=32, blank=True, null=True, db_column='telephone') 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) photo = models.FileField(verbose_name=_(u"Photo"), upload_to=settings.UPLOAD_DIR, db_column='photo', max_length=512, blank=True, null=True) street = models.CharField(verbose_name=_(u"Street"), max_length=256, blank=True, null=True, db_column='rue') postal_code = models.CharField(verbose_name=_(u"Postal code"), max_length=8, blank=True, null=True, db_column='code') municipality = models.CharField(verbose_name=_(u"Municipality"), blank=True, null=True, max_length=256, db_column='commune') geom = models.PointField(verbose_name=_(u"Emplacement"), db_column='geom', blank=True, null=True, srid=settings.SRID, spatial_index=False) objects = models.GeoManager() class Meta: db_table = 't_b_renseignement' verbose_name = _(u"Information desk") verbose_name_plural = _(u"Information desks") ordering = ['name'] def __unicode__(self): return self.name @property def description_strip(self): """Used in trek public template. """ nobr = re.compile(r'(\s*<br.*?>)+\s*', re.I) newlines = nobr.sub("\n", self.description) return smart_plain_text(newlines) @property def serializable_type(self): return { 'id': self.type.id, 'label': self.type.label, 'pictogram': self.type.pictogram.url, } @property def latitude(self): if self.geom: api_geom = self.geom.transform(settings.API_SRID, clone=True) return api_geom.y return None @property def longitude(self): if self.geom: api_geom = self.geom.transform(settings.API_SRID, clone=True) return api_geom.x return None @property def thumbnail(self): if not self.photo: return None thumbnailer = get_thumbnailer(self.photo) try: return thumbnailer.get_thumbnail(aliases.get('thumbnail')) except InvalidImageFormatError: logger.warning( _("Image %s invalid or missing from disk.") % self.photo) return None @property def photo_url(self): thumbnail = self.thumbnail if not thumbnail: return None return os.path.join(settings.MEDIA_URL, thumbnail.name)
class Place(models.Model): #BUG - why id is NULL? #name&position - ัะฝะธะบะฐะปัะฝัะน ะธะฝะดะธัะธะบะฐัะพั name = models.CharField(max_length=128, verbose_name=u"ะฝะฐะทะฒะฐะฝะธะต") position = models.PointField(verbose_name=u"ะบะพะพัะดะธะฝะฐัั") objects = models.GeoManager() is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this place should be treated as ' 'active. Unselect this instead of place has no owner too long' ' (by engine initiate).')) is_in_engine = models.BooleanField( _('create in engine'), default=False, help_text=_('After creation place in db, place is created in engine.' 'If it be done successfully - tis field will be true')) date = models.DateTimeField(default=timezone.now, verbose_name=u"ะดะฐัะฐ ัะพะทะดะฐะฝะธั") date_is_active = models.DateTimeField(default=timezone.now, verbose_name=u"ะดะฐัะฐ ะฐะบัะธะฒะฐัะธะธ") address = models.CharField( max_length=128, null=True, blank=True, verbose_name=u"ะฐะดัะตั", ) crossStreet = models.CharField( max_length=128, null=True, blank=True, verbose_name=u"ะฟะตัะตัะตัะตะฝะธะต ัะปะธั", ) contact = models.CharField( max_length=512, null=True, blank=True, verbose_name=u"ะบะพะฝัะฐะบัั", ) city_id = models.IntegerField( db_index=True, null=False, blank=False, verbose_name=u"ะธะดะตะฝัะธัะธะบะฐัะพั ะฒ GeoNames", ) fsq_id = models.CharField( max_length=24, null=True, blank=True, verbose_name=u"ะธะดะตะฝัะธัะธะบะฐัะพั ะฒ Foursquare", ) foursquare_icon_prefix = models.CharField( max_length=128, null=True, blank=True, verbose_name=u"ะฟัะตัะธะบั ะฟะธะบัะพะณัะฐะผะผั ะบะฐัะตะณะพัะธะธ ะฒ Foursquare") foursquare_icon_suffix = models.CharField( max_length=16, null=True, blank=True, verbose_name=u"ััััะธะบั (ัะฐััะธัะตะฝะธะต) ะฟะธะบัะพะณัะฐะผะผั ะบะฐัะตะณะพัะธะธ ะฒ Foursquare" ) def longitude(self): return self.position.x def latitude(self): return self.position.y def foursquare_details_url(self): return "https://foursquare.com/v/%s" % self.fsq_id def get_string_date(self): return get_string_date(self.date_is_active) def create_in_engine(self): self.is_in_engine = True self.save() def __unicode__(self): return u"%s" % self.name + (self.address and (u", %s" % self.address) or u"") class Meta: unique_together = ( 'position', 'name', ) verbose_name = _('place') verbose_name_plural = _('places') ordering = ("name", )
class City(models.Model): name = models.CharField(max_length=30) point = models.PointField() objects = models.GeoManager() def __str__(self): return self.name
class GADM(models.Model): id_0 = models.IntegerField() iso = models.CharField(max_length=3) name_engli = models.CharField(max_length=50) name_iso = models.CharField(max_length=54) name_fao = models.CharField(max_length=50) name_local = models.CharField(max_length=54) name_obsol = models.CharField(max_length=150) name_varia = models.CharField(max_length=160) name_nonla = models.CharField(max_length=50) name_frenc = models.CharField(max_length=50) name_spani = models.CharField(max_length=50) name_russi = models.CharField(max_length=50) name_arabi = models.CharField(max_length=50) name_chine = models.CharField(max_length=50) waspartof = models.CharField(max_length=100) contains = models.CharField(max_length=50) sovereign = models.CharField(max_length=40) iso2 = models.CharField(max_length=4) www = models.CharField(max_length=2) fips = models.CharField(max_length=6) ison = models.FloatField() validfr = models.CharField(max_length=12) validto = models.CharField(max_length=10) pop2000 = models.FloatField() sqkm = models.FloatField() popsqkm = models.FloatField() unregion1 = models.CharField(max_length=254) unregion2 = models.CharField(max_length=254) developing = models.FloatField() cis = models.FloatField() transition = models.FloatField() oecd = models.FloatField() wbregion = models.CharField(max_length=254) wbincome = models.CharField(max_length=254) wbdebt = models.CharField(max_length=254) wbother = models.CharField(max_length=254) ceeac = models.FloatField() cemac = models.FloatField() ceplg = models.FloatField() comesa = models.FloatField() eac = models.FloatField() ecowas = models.FloatField() igad = models.FloatField() ioc = models.FloatField() mru = models.FloatField() sacu = models.FloatField() uemoa = models.FloatField() uma = models.FloatField() palop = models.FloatField() parta = models.FloatField() cacm = models.FloatField() eurasec = models.FloatField() agadir = models.FloatField() saarc = models.FloatField() asean = models.FloatField() nafta = models.FloatField() gcc = models.FloatField() csn = models.FloatField() caricom = models.FloatField() eu = models.FloatField() can = models.FloatField() acp = models.FloatField() landlocked = models.FloatField() aosis = models.FloatField() sids = models.FloatField() islands = models.FloatField() ldc = models.FloatField() geom = models.MultiPolygonField(srid=4326, null=True) objects = models.GeoManager() class Meta: verbose_name = 'Country' verbose_name_plural = 'Countries' @staticmethod def is_valid_point(country_name, point, margin_km=50): """ Checks if the point is within county's borders with margin of 'margin_km' kilometers from its borders. Parameters ---------- country_name : str point : tuple margin_km : int Returns ------- status : bool """ pnt = Point(*point, srid=4326) country = GADM.objects.filter(name_engli__iexact=country_name) if not country: return False if country.distance(pnt).get( name_engli__iexact=country_name).distance.km < margin_km: return True return False
class Location(models.Model): """Model for school locations in Chicago """ EMPTY = '' NONE = 'None' LICENSED = 'Licensed' BRONZE = 'Bronze' SILVER = 'Silver' GOLD = 'Gold' Q_RATING_CHOICES = ( (EMPTY, ugettext_lazy('Select a rating')), (NONE, ugettext_lazy('None')), (LICENSED, ugettext_lazy('Licensed')), (BRONZE, ugettext_lazy('Bronze')), (SILVER, ugettext_lazy('Silver')), (GOLD, ugettext_lazy('Gold')), ) LOCATION_TYPE_CHOICES = ( (0, 'Normal Location'), (1, 'Application Site'), ) HIGH = 'High' MEDIUM = 'Medium' LOW = 'Low' AVAILABILITY_CHOICES = ( (HIGH, ugettext_lazy('High')), (MEDIUM, ugettext_lazy('Medium')), (LOW, ugettext_lazy('Low')), ) ecm_key = models.IntegerField('ECM Key', default=0, blank=True) site_name = models.CharField('Site Name', max_length=100) site_type = models.IntegerField('Site Type', default=0, choices=LOCATION_TYPE_CHOICES) address = models.CharField('Address', max_length=75) city = models.CharField('City', max_length=75) state = models.CharField('State', max_length=2) zip = models.CharField('Zip Code', max_length=10) neighborhood = models.ForeignKey('Neighborhood', null=True) phone = models.CharField(ugettext_lazy('Phone Number'), max_length=20, blank=True) q_rating = models.CharField(ugettext_lazy('Quality Rating'), choices=Q_RATING_CHOICES, max_length=10, blank=True) url = models.CharField(ugettext_lazy('Website'), max_length=256, blank=True) q_stmt = models.TextField(ugettext_lazy('Description'), blank=True) enrollment = models.TextField(ugettext_lazy('Enrollment Process'), blank=True) accred = models.CharField(ugettext_lazy('Accreditation'), max_length=100, blank=True) prg_hours = models.CharField(ugettext_lazy('Program Hours'), max_length=50, blank=True) is_age_lt_3 = models.NullBooleanField(ugettext_lazy('Ages 0 - 3')) is_age_gt_3 = models.NullBooleanField(ugettext_lazy('Ages 3 - 5')) is_full_day = models.NullBooleanField(ugettext_lazy('Full Day')) is_part_day = models.NullBooleanField(ugettext_lazy('Part Day')) is_school_year = models.NullBooleanField(ugettext_lazy('School Year')) is_full_year = models.NullBooleanField(ugettext_lazy('Full Year')) ages = models.CharField(ugettext_lazy('Ages Served'), max_length=50, blank=True) is_full_week = models.NullBooleanField(ugettext_lazy('Full Week')) is_part_week = models.NullBooleanField(ugettext_lazy('Part Week')) language_1 = models.CharField('Language 1 (other than English)', max_length=50, blank=True) language_2 = models.CharField('Language 2 (other than English)', max_length=50, blank=True) language_3 = models.CharField('Language 3 (other than English)', max_length=50, blank=True) is_community_based = models.NullBooleanField( ugettext_lazy('Community Based')) is_cps_based = models.NullBooleanField(ugettext_lazy('CPS Based')) is_home_visiting = models.NullBooleanField( ugettext_lazy('Offers Home Visiting')) accept_ccap = models.NullBooleanField(ugettext_lazy('Accepts CCAP')) is_hs = models.NullBooleanField(ugettext_lazy('Head Start')) is_ehs = models.NullBooleanField(ugettext_lazy('Early Head Start')) open_house = models.TextField(ugettext_lazy('Open House'), blank=True) curriculum = models.TextField(ugettext_lazy('Curriculum'), blank=True) email = models.EmailField(blank=True) # Keeps track of whether or not new locations have been approved by the admin accepted = models.BooleanField(ugettext_lazy('Approved'), default=False) # ECM alottment status, classroom availability availability = models.CharField(ugettext_lazy('Availability'), choices=AVAILABILITY_CHOICES, max_length=10, blank=True) # To get these placeholder fields to show up in the UI, replace # 'Placeholder 1' and 'Placeholder 2' in the lines below with # real labels, and add 'placeholder_1' and 'placeholder_2' to the # 'display_include' list. Also, in admin.py, browse to the # LocationAdmin class and add the appropriate entries to the # fieldsets list. placeholder_1 = models.TextField('Placeholder 1', blank=True) placeholder_2 = models.TextField('Placeholder 2', blank=True) geom = models.PointField('Geometry', srid=4326, null=True) objects = models.GeoManager() # List of simple/boolean fields that should be displayed by Location renderers/views display_include = { 'ages', 'accred', 'accept_ccap', 'is_home_visiting', 'is_hs', 'is_ehs', 'is_community_based', 'is_cps_based', 'open_house', 'curriculum', } # List of fields that should be hidden when left blank hide_if_none = { 'open_house', 'curriculum', } display_order = dict((k, v) for v, k in enumerate([ 'open_house', 'accred', 'ages', 'description', 'enrollment', 'duration_hours', 'weekday_availability', 'languages', 'program_info', 'curriculum', 'quality_rating' ])) q_rating_translations = [ ugettext_lazy('None'), ugettext_lazy('Licensed'), ugettext_lazy('Bronze'), ugettext_lazy('Silver'), ugettext_lazy('Gold') ] def __unicode__(self): return unicode(self.site_name) def verbose_name(self, field): """ Given the name of field, returns the verbose_name property for it """ return unicode(self._meta.get_field_by_name(field)[0].verbose_name) @property def is_enrollment(self): if self.site_type == 1: return True else: return False def combine_languages(self): lang_list = [ lang for lang in self.language_1, self.language_2, self.language_3 if lang ] languages = ", ".join(lang_list) return languages def combine_other_features(self): other_features = '' return other_features @staticmethod def get_filter_fields(): """ Returns all boolean fields that should be used for filtering Location objects This method does not use a static list of names, but rather inspects the meta class attached to the model to introspect on the field types. This also has the benefit of providing the verbose name of the field. """ # TODO: This relies on fields being ordered in the fields object in the # same order they're defined above. This is probably a sketchy assumption. exclude = ['is_montessori', 'is_special_ed'] fields = [] for field in Location._meta.fields: if (field.get_internal_type() == 'NullBooleanField' and not field.get_attname() in exclude): fields.append(( field.get_attname(), _(field.verbose_name), )) return fields def get_boolean_fieldnames(self): """ Extracts list of boolean field names from model """ fields = self._meta.fields return [ field.name for field in fields if field.get_internal_type() == 'NullBooleanField' ] def is_true_bool_field(self, field): """ Returns true if field is a boolean field and self.field is True """ fname = field.get_attname() return (field.get_internal_type() == 'NullBooleanField' and getattr(self, fname)) def is_simple_field(self, field): """ Returns true if field is of type CharField or TextField """ ftype = field.get_internal_type() return ((ftype == 'CharField' or ftype == 'TextField')) def get_context_dict(self, short=False): """Gets a context dictionary for rendering this object in templates Performs a bunch of cleanup and filtering logic to format fields appropriately and remove useless info :param short: If true, a shorter version of the dict will be returned """ # Fix some ugly data if self.site_name.isupper(): self.site_name = title(self.site_name) if self.address.isupper(): self.address = title(self.address) if self.city.isupper(): self.city = title(self.city) item = { 'address': self.address, 'city': self.city, 'site_name': self.site_name, 'zip': self.zip, 'url': self.url, 'state': self.state, 'key': self.pk, 'email': self.email, 'type': self.site_type, 'full_day': self.is_full_day, 'part_day': self.is_part_day, 'age_lt_3': self.is_age_lt_3, 'age_gt_3': self.is_age_gt_3, 'site_type': self.site_type, 'is_enrollment': self.is_enrollment, 'duration_hours': self.prg_hours, } # simple fields to present -- these are the attributes that have text content sfields = [] # boolean fields to present -- these are the attributes that are set to True bfields = [] # Fields to include in Affiliation aggregate field affiliation_fields = [ self._meta.get_field_by_name(name)[0] for name in [ 'is_home_visiting', 'is_community_based', 'is_cps_based', 'is_hs', 'is_ehs' ] ] program_fields = [ self._meta.get_field_by_name(name)[0] for name in ['is_full_year', 'is_school_year'] ] week_fields = [ self._meta.get_field_by_name(name)[0] for name in ['is_full_week', 'is_part_week', 'is_full_day', 'is_part_day'] ] aff_field_names = {f.get_attname() for f in affiliation_fields} for field in self._meta.fields: fname = field.get_attname() if not fname in self.display_include or fname in aff_field_names: continue if self.is_true_bool_field(field): bfields.append(field.verbose_name) elif self.is_simple_field(field): value = field.value_from_object(self) hide_field = fname in self.hide_if_none and not value if not hide_field: kv = { 'key': fname, 'fieldname': _(field.verbose_name), 'value': value if value else _('None') } sfields.append(kv) affiliation_values = [ self.verbose_name(aff.get_attname()) for aff in affiliation_fields if aff.value_from_object(self) ] sfields.append({ 'key': 'program_info', 'fieldname': _('Program Information'), 'value': ', '.join(affiliation_values) if affiliation_values else _('None') }) # Combine Languages lang_list = [ lang for lang in self.language_1, self.language_2, self.language_3 if lang ] languages = ", ".join(lang_list) if languages != '': sfields.append({ 'key': 'languages', 'fieldname': _('Languages'), 'value': languages }) # Program Duration/Hours program_values = [ self.verbose_name(prg.get_attname()) for prg in program_fields if prg.value_from_object(self) ] program_hours = self.prg_hours if self.prg_hours else _( "No Hours Listed") program_values.append(program_hours) sfields.append({ 'key': 'duration_hours', 'fieldname': _('Duration and Hours'), 'value': ', '.join(program_values) if program_values else _('None') }) # Weekday Avaialability week_values = [ self.verbose_name(wk.get_attname()) for wk in week_fields if wk.value_from_object(self) ] sfields.append({ 'key': 'weekday_availability', 'fieldname': _('Weekday Availability'), 'value': ', '.join(week_values) if week_values else _('None') }) # Quality Rating # default empty db entry to coming soon so we don't have to modify code when CEL chooses # to implement this. No q_rating is explicitly set as 'None' in the database and will # be properly displayed in the UI as long as the db field is set to 'None' # key for displayed image, not to be translated item['quality'] = self.q_rating.lower() or 'none' # translatable displayed text q_rating = self.q_rating or 'Coming Soon' sfields.append({ 'key': 'quality_rating', 'fieldname': _('Quality Rating'), 'value': _(q_rating) }) # Phone phone = { 'fieldname': _('Phone Number'), 'number': nicephone(self.phone) } # Position position = {'lng': self.geom[0], 'lat': self.geom[1]} # Quality Statement if self.q_stmt and not short: sfields.append({ 'key': 'description', 'fieldname': _('Description'), 'value': self.q_stmt }) bfields.sort() sfields.sort(key=lambda a: self.display_order[a['key']]) # Translation # Adding a dictionary with strings that need to be translated in the handlebars template # This way we can do this with django and not have to worry about making a separate # handlebars helper trans_dict = { 'more': _('More'), 'website': _('Website'), 'directions': _('Directions'), 'share': _('Share'), 'qrisrating': _('QRIS Rating'), 'contact': _('Compare and Apply'), 'more_info': _('More Info'), 'serves03': _('Serves ages 0 - 3'), 'serves35': _('Serves ages 3 - 5'), 'serves05': _('Serves ages 0 - 3, 3 - 5'), 'full_day': _('Full Day'), 'part_day': _('Part Day') } # More information for tooltip icon accreditation = ['Accredited'] if self.accred != 'None' else [] accreditation.append('School' if self.is_cps_based else 'Center') # Tooltips - necessary for translations in handlebars template tooltip = { 'directions': _('Directions from Google'), 'moreinfo': _('Click to show more information'), 'star': _('Click to save to your list'), 'unstar': _('Click to remove from your list'), 'accreditation': ' '.join(accreditation), 'quality': _(q_rating) } return { 'item': item, 'phone': phone, 'sfields': sfields, 'bfields': { 'fieldname': _('Other Features'), 'values': bfields }, 'position': position, 'translations': trans_dict, 'tooltip': tooltip } def val_or_empty(self, field, f=(lambda x: x)): """ Returns a pretty string representing the value of a field if it's present, otherwise an empty string. The pretty string ends in a newline. field: string with the name of a field on this model f: optional rendering function. It's given the value of the field, modifies it, and returns the result. Default returns its input """ val = self.__dict__[field] return ("%s: %s\n" % (self.verbose_name(field), f(val))) if val else "" def save(self, *args, **kwargs): """ Override for Model.save() Overrides Location.save(). Provides the additional functionality of updating the Neighborhood of the Location before the save. """ if self.geom is not None: neighborhoods = Neighborhood.objects.filter( boundary__intersects=self.geom) if len(neighborhoods): self.neighborhood = neighborhoods[0] super(Location, self).save(*args, **kwargs)
class Instance(models.Model): """ Each "Tree Map" is a single instance """ name = models.CharField(max_length=255, unique=True) url_name = models.CharField( max_length=255, unique=True, validators=[ reserved_name_validator, RegexValidator( r'^%s$' % URL_NAME_PATTERN, trans('Must start with a letter and may only contain ' 'letters, numbers, or dashes ("-")'), trans('Invalid URL name')) ]) """ Basemap type Basemap data ------------ ----------------- Google Google_API_Key Bing Bing_API_Key TMS TMS URL with {x},{y},{z} """ basemap_type = models.CharField(max_length=255, choices=(("google", "Google"), ("bing", "Bing"), ("tms", "Tile Map Service")), default="google") basemap_data = models.CharField(max_length=255, null=True, blank=True) """ The current database revision for the instance This revision is used to determine if tiles should be cached. In particular, the revision has *no* effect on the actual data. Generally we make tile requests like: http://tileserver/tile/{layer}/{rev}/{Z}/{Y}/{X} There is a database trigger that updates the revision whenever an edit to a geometry field is made so you don't have to worry about it. You should *not* edit this field. """ geo_rev = models.IntegerField(default=1) eco_benefits_conversion = models.ForeignKey('BenefitCurrencyConversion', null=True, blank=True) """ Center of the map when loading the instance """ bounds = models.MultiPolygonField(srid=3857) """ Override the center location (which is, by default, the centroid of "bounds" """ center_override = models.PointField(srid=3857, null=True, blank=True) default_role = models.ForeignKey('Role', related_name='default_role') users = models.ManyToManyField('User', through='InstanceUser', null=True, blank=True) boundaries = models.ManyToManyField('Boundary', null=True, blank=True) """ Config contains a bunch of config variables for a given instance these can be accessed via per-config properties such as `advanced_search_fields`. Note that it is a DotDict, and so supports get() with a dotted key and a default, e.g. instance.config.get('fruit.apple.type', 'delicious') as well as creating dotted keys when no keys in the path exist yet, e.g. instance.config = DotDict({}) instance.config.fruit.apple.type = 'macoun' """ config = JSONField(blank=True) is_public = models.BooleanField(default=False) logo = models.ImageField(upload_to='logos', null=True, blank=True) itree_region_default = models.CharField(max_length=20, null=True, blank=True, choices=ITREE_REGION_CHOICES) objects = models.GeoManager() def __unicode__(self): return self.name def _make_config_property(prop, default=None): def get_config(self): return self.config.get(prop, default) def set_config(self, value): self.config[prop] = value return property(get_config, set_config) mobile_search_fields = _make_config_property('mobile_search_fields', DEFAULT_MOBILE_SEARCH_FIELDS) mobile_api_fields = _make_config_property('mobile_api_fields', DEFAULT_MOBILE_API_FIELDS) date_format = _make_config_property('date_format', settings.DATE_FORMAT) short_date_format = _make_config_property('short_date_format', settings.SHORT_DATE_FORMAT) scss_variables = _make_config_property('scss_variables') map_feature_types = _make_config_property('map_feature_types', ['Plot']) @property def advanced_search_fields(self): # TODO pull from the config once users have a way to set search fields from treemap.util import to_object_name # if we come to support more udfc searches, we can add them here. udfc_models = ['Tree', 'Plot'] udfc_names = ['Stewardship', 'Alerts'] # must inflate object so that template can look for keys empty_udfc = { to_object_name(n_k): { to_object_name(m_k): { 'fields': [], 'udfd': None } for m_k in udfc_models } for n_k in udfc_names } if not self.feature_enabled('advanced_search_filters'): return { 'standard': [], 'missing': [], 'display': [], 'udfc': empty_udfc } from treemap.models import MapFeature # prevent circular import fields = { 'standard': [{ 'identifier': 'tree.diameter', 'search_type': 'RANGE' }, { 'identifier': 'tree.date_planted', 'search_type': 'RANGE' }], 'display': [{ 'model': 'Tree', 'label': 'Show trees' }, { 'model': 'EmptyPlot', 'label': 'Show empty planting sites' }], 'missing': [{ 'identifier': 'species.id', 'label': 'Show missing species', 'search_type': 'ISNULL', 'value': 'true' }, { 'identifier': 'tree.diameter', 'label': 'Show missing trunk diameter', 'search_type': 'ISNULL', 'value': 'true' }, { 'identifier': 'mapFeaturePhoto.id', 'label': 'Show missing photos', 'search_type': 'ISNULL', 'value': 'true' }], } def make_display_filter(feature_name): Feature = MapFeature.get_subclass(feature_name) if hasattr(Feature, 'display_name_plural'): plural = Feature.display_name_plural else: plural = Feature.display_name + 's' return {'label': 'Show %s' % plural.lower(), 'model': feature_name} fields['display'] += [ make_display_filter(feature_name) for feature_name in self.map_feature_types if feature_name != 'Plot' ] # It makes styling easier if every field has an identifier num = 0 for filters in fields.itervalues(): for field in filters: field['id'] = "%s_%s" % (field.get('identifier', ''), num) num += 1 # prevent circular import from treemap.udf import UserDefinedFieldDefinition udfds = UserDefinedFieldDefinition.objects.filter( instance=self, name__in=udfc_names, model_type__in=udfc_models) udfc = deepcopy(empty_udfc) for udfd in udfds: udfd_info = { 'udfd': udfd, 'fields': udfd.datatype_dict[0]['choices'] } name_dict = udfc[to_object_name(udfd.name)] name_dict[to_object_name(udfd.model_type)] = udfd_info fields['udfc'] = udfc return fields @property def supports_resources(self): """ Determine whether this instance has multiple map feature types (plots + "resources") or not. """ n = len(self.map_feature_types) return n > 1 @property def extent_as_json(self): boundary = self.bounds.boundary xmin, ymin, xmax, ymax = boundary.extent return json.dumps({ 'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax }) @property def center(self): return self.center_override or self.bounds.centroid @property def geo_rev_hash(self): return hashlib.md5(str(self.geo_rev)).hexdigest() @property def center_lat_lng(self): return self.center.transform(4326, clone=True) @property def factor_conversions(self): """ Returns a dict for use in eco.py Benefits from eco_benefits_conversion """ benefits_conversion = self.eco_benefits_conversion if benefits_conversion: return benefits_conversion.get_factor_conversions_config() else: return None @property def scss_query_string(self): scss_vars = ({k: val for k, val in self.scss_variables.items() if val} if self.scss_variables else {}) return urlencode(scss_vars) @property def static_page_names(self): from treemap.models import StaticPage # prevent circular import built_in_names = StaticPage.built_in_names() custom_names = [ page.name for page in StaticPage.objects.filter( instance=self).exclude(name__in=built_in_names) ] names = built_in_names + custom_names return names def itree_regions(self): from treemap.models import ITreeRegion if self.itree_region_default: regions = [self.itree_region_default] else: regions = ITreeRegion.objects.filter( geometry__intersects=self.bounds) return regions def has_itree_region(self): from treemap.models import ITreeRegion # prevent circular import intersecting_regions = (ITreeRegion.objects.filter( geometry__intersects=self.bounds)) return bool(self.itree_region_default) or intersecting_regions.exists() def is_accessible_by(self, user): try: if self.is_public: return True # Extension point if hasattr(user, 'is_super_admin') and user.is_super_admin(): return True # If a user is not logged in, trying to check # user=user raises a type error so I am checking # pk instead self.instanceuser_set.get(user__pk=user.pk) return True except ObjectDoesNotExist: return False def scope_model(self, model): qs = model.objects.filter(instance=self) return qs def feature_enabled(self, feature): # Delayed import to prevent circular imports from treemap.plugin import feature_enabled return feature_enabled(self, feature) def seed_with_dummy_default_role(self): """ Instances need roles and roles needs instances... crazy stuff we're going to create the needed role below however, we'll temporarily use a 'dummy role'. The dummy role has no instance. """ from treemap.audit import Role dummy_roles = Role.objects.filter(instance__isnull=True) if len(dummy_roles) == 0: dummy_role = Role.objects.create(name='empty', rep_thresh=0) else: dummy_role = dummy_roles[0] self.default_role = dummy_role def save(self, *args, **kwargs): self.full_clean() self.url_name = self.url_name.lower() super(Instance, self).save(*args, **kwargs)
class USGSStructureData(models.Model): """ Models structure data from the USGS National Map. Schema from: http://services.nationalmap.gov/arcgis/rest/services/structures/MapServer/1?f=json """ DATA_SECURITY_CHOICES = [(0, 'Unknown'), (1, 'Top Secret'), (2, 'Secret'), (3, 'Confidential'), (4, 'Restricted'), (5, 'Unclassified'), (6, 'Sensitive')] DISTRIBUTION_POLICY_CHOICES = [('A1', 'Emergency Service Provider - Internal Use Only'), ('A2', 'Emergency Service Provider - Bitmap Display Via Web'), ('A3', 'Emergency Service Provider - Free Distribution to Third Parties'), ('A4', 'Emergency Service Provider - Free Distribution to Third Parties Via' ' Internet'), ('B1', 'Government Agencies or Their Delegated Agents - Internal Use Only'), ('B2', 'Government Agencies or Their Delegated Agents - Bitmap Display Via Web'), ('B3', 'Government Agencies or Their Delegated Agents - Free Distribution to Third' ' Parties'), ('B4', 'Government Agencies or Their Delegated Agents - Free Distribution to Third' ' Parties Via Internet'), ('C1', 'Other Public or Educational Institutions - Internal Use Only'), ('C2', 'Other Public or Educational Institutions - Bitmap Display Via Web'), ('C3', 'Other Public or Educational Institutions - Free Distribution to Third' ' Parties'), ('C4', 'Other Public or Educational Institutions - Free Distribution to Third' ' Parties Via Internet'), ('D1', 'Data Contributors - Internal Use Only'), ('D2', 'Data Contributors - ' 'Bitmap Display Via Web'), ('D3', 'Data Contributors - Free Distribution to Third Parties'), ('D4', 'Data Contributors - Free Distribution to Third Parties Via Internet'), ('E1', 'Public Domain - Internal Use Only'), ('E2', 'Public Domain - Bitmap' ' Display Via Web'), ('E3', 'Public Domain - Free Distribution to Third Parties'), ('E4', 'Public Domain - Free Distribution to Third Parties Via Internet')] FCODE_CHOICES = [(81000, 'Transportation Facility'), (81006, 'Airport Terminal'), (81008, 'Air Support / Maintenance Facility'), (81010, 'Air Traffic Control Center / Command Center'), (81011, 'Boat Ramp / Dock'), (81012, 'Bridge'), (81014, 'Bridge: Light Rail / Subway'), (81016, 'Bridge: Railroad'), (81018, 'Bridge: Road'), (81020, 'Border Crossing / Port of Entry'), (81022, 'Bus Station / Dispatch Facility'), (81024, 'Ferry Terminal / Dispatch Facility'), (81025, 'Harbor / Marina'), (81026, 'Helipad / Heliport / Helispot'), (81028, 'Launch Facility'), (81030, 'Launch Pad'), (81032, 'Light Rail Power Substation'), (81034, 'Light Rail Station'), (81036, 'Park and Ride / Commuter Lot'), (81038, 'Parking Lot Structure / Garage'), (81040, 'Pier / Wharf / Quay / Mole'), (81042, 'Port Facility'), (81044, 'Port Facility: Commercial Port'), (81046, 'Port Facility: Crane'), (81048, 'Port Facility: Maintenance and Fuel Facility'), (81050, 'Port Facility: Modal Transfer Facility'), (81052, 'Port Facility: Passenger Terminal'), (81054, 'Port Facility: Warehouse Storage / Container Yard'), (81056, 'Railroad Facility'), (81058, 'Railroad Command / Control Facility'), (81060, 'Railroad Freight Loading Facility'), (81062, 'Railroad Maintenance / Fuel Facility'), (81064, 'Railroad Roundhouse / Turntable'), (81066, 'Railroad Station'), (81068, 'Railroad Yard'), (81070, 'Rest Stop / Roadside Park'), (81072, 'Seaplane Anchorage / Base'), (81073, 'Snowshed'), (81074, 'Subway Station'), (81076, 'Toll Booth / Plaza'), (81078, 'Truck Stop'), (81080, 'Tunnel'), (81082, 'Tunnel: Light Rail / Subway'), (81084, 'Tunnel: Road'), (81086, 'Tunnel: Railroad'), (81088, 'Weigh Station / Inspection Station')] ISLANDMARK_CHOICES = [(1, 'Yes'), (2, 'No'), (0, 'Unknown')] POINTLOCATIONTYPE_CHOICES = [(0, 'Unknown'), (1, 'Centroid'), (2, 'Egress or Entrance'), (3, 'Turn-off location'), (4, 'Approximate')] ADMINTYPE_CHOICES = [(0, 'Unknown'), (1, 'Federal'), (2, 'Tribal'), (3, 'State'), (4, 'Regional'), (5, 'County'), (6, 'Municipal'), (7, 'Private')] created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) objectid = models.IntegerField(unique=True, null=True, blank=True) permanent_identifier = models.CharField(max_length=40, null=True, blank=True) source_featureid = models.CharField(max_length=40, null=True, blank=True) source_datasetid = models.CharField(max_length=40, null=True, blank=True) source_datadesc = models.CharField(max_length=100, null=True, blank=True) source_originator = models.CharField(max_length=130, null=True, blank=True) data_security = models.IntegerField(blank=True, null=True, choices=DATA_SECURITY_CHOICES) distribution_policy = models.CharField(max_length=4, choices=DISTRIBUTION_POLICY_CHOICES, null=True, blank=True) loaddate = models.DateTimeField(null=True, blank=True) ftype = models.CharField(blank=True, null=True, max_length=50) fcode = models.IntegerField(blank=True, null=True, choices=FCODE_CHOICES) name = models.CharField(max_length=100, null=True, blank=True) islandmark = models.IntegerField(null=True, blank=True, choices=ISLANDMARK_CHOICES, verbose_name='Landmark') pointlocationtype = models.IntegerField(null=True, blank=True, choices=POINTLOCATIONTYPE_CHOICES, verbose_name='Point Type') admintype = models.IntegerField(null=True, blank=True, choices=ADMINTYPE_CHOICES) addressbuildingname = models.CharField(max_length=60, null=True, blank=True, verbose_name='Building Name') address = models.CharField(max_length=75, null=True, blank=True) city = models.CharField(max_length=40, null=True, blank=True) state = models.CharField(max_length=2, null=True, blank=True) zipcode = models.CharField(max_length=10, null=True, blank=True) gnis_id = models.CharField(max_length=10, null=True, blank=True) foot_id = models.CharField(max_length=40, null=True, blank=True) complex_id = models.CharField(max_length=40, null=True, blank=True) globalid = models.CharField(max_length=38, null=True, blank=True) geom = models.PointField() objects = models.GeoManager() def __unicode__(self): return u'{state}, {city}, {name}'.format(name=self.name, state=self.state, city=self.city) def full_address(self): return u'{address}, {city}, {state}, {zipcode}'.format(address=self.address, city=self.city, state=self.state, zipcode=self.zipcode) class Meta: ordering = ('state', 'city', 'name') @classmethod def count_differential(cls): """ Reports the count differential between the upstream service and this table. """ url = 'http://services.nationalmap.gov/arcgis/rest/services/govunits/MapServer/{0}/query?' \ 'where=1%3D1&text=&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&' \ 'spatialRel=esriSpatialRelIntersects&relationParam=&outFields=&returnGeometry=true' \ '&maxAllowableOffset=&geometryPrecision=&outSR=&returnIdsOnly=false&returnCountOnly=true&orderByFields=' \ '&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&gdbVersion=&' \ 'returnDistinctValues=false&f=pjson' response = requests.get(url.format(cls.service_id)) if response.ok: response_js = json.loads(response.content) upstream_count = response_js.get('count') if upstream_count: local_count = cls.objects.all().count() print 'The upstream service has: {0} features.'.format(upstream_count) print 'The local model {1} has: {0} features.'.format(local_count, cls.__name__) return local_count - upstream_count
class Poi(models.Model): """Model representing Point of interest (POI).""" name = models.CharField(_(u'name'), max_length=50, help_text=_(u'Name of the POI.')) area = models.ForeignKey(Area, help_text=_(u'Area, which POI is situated in.'), verbose_name=_(u'area')) type = models.IntegerField(_(u'type'), choices=settings.SNP_POI_TYPES, help_text=_(u'Type of the POI.')) active = models.BooleanField( _(u'active'), default=True, help_text=_(u'Boolean of controlling displaying POI in the map.')) priority = models.IntegerField( _(u'priority'), default=5, help_text=_(u'Displaying priority of the POI in the map.')) note = models.TextField(_(u'note'), blank=True, help_text=_(u'Note about the POI.')) photo = models.ManyToManyField(Photo, blank=True, null=True, verbose_name=_(u'list of photos'), help_text=_(u'Photo of the POI.')) jos_article_id = models.ManyToManyField( Jos_article_id, blank=True, null=True, verbose_name=_(u'list of articles'), help_text=_( u'Many-to-many relation with article ids (from Joomla DB).')) jos_photo_id = models.ManyToManyField( Jos_photo_id, blank=True, null=True, verbose_name=_(u'list of joomla photos'), help_text=_(u'Many-to-many relation with photo ids (from Joomla DB).')) created_by = models.CharField( _(u'author'), max_length=50, blank=True, help_text=_(u'Name of the creator of the POI.')) created_at = models.DateTimeField( _(u'creation time'), default=datetime.now(), help_text=_(u'Date-time stamp of creation of the POI.')) the_geom = models.PointField( _(u'the geom'), help_text=_(u'Spatial representation of the POI in the WGS84.')) objects = models.GeoManager() @property def has_photo(self): if len(self.photo.all()) == 0 and len(self.jos_photo_id.all()) == 0: return False else: return True #has_photo.boolean = True @property def has_article(self): if len(self.jos_article_id.all()) == 0: return False else: return True #has_article.boolean = True class Meta: get_latest_by = 'created_at' verbose_name = _(u'Point of interest') verbose_name_plural = _(u'Points of interest') def __unicode__(self): return self.name
class TrapLocation(models.Model): @classmethod def create_from_obj(self, transect_obj, point_obj, the_expedition): t = TrapLocation() t.expedition = the_expedition t.transect_bearing = transect_obj['heading'] t.team_letter = transect_obj['team_letter'] t.set_actual_lat_long(point_obj['point']) t.set_suggested_lat_long(point_obj['point']) t.transect_distance = point_obj['distance'] t.team_number = point_obj['point_id'] t.save() return t def recreate_point_obj(self): result = {} result['distance'] = self.transect_distance result['point_id'] = self.team_number result['point'] = [self.suggested_lat(), self.suggested_lon()] return result """ A location you might decide to set a trap.""" expedition = models.ForeignKey(Expedition, null=True, blank=True) suggested_point = models.PointField(null=True, blank=True) actual_point = models.PointField(null=True, blank=True) objects = models.GeoManager() # instead we're linking directly to the type of trap. trap_type = models.ForeignKey( TrapType, null=True, blank=True, help_text="Which type of trap, if any, was left at this location.") understory = models.TextField(blank=True, null=True, default='', help_text="Understory") notes_about_location = models.TextField( blank=True, help_text="Notes about the location") # this is wrt true north. for wrt mag. north, see method below transect_bearing = models.FloatField(blank=True, null=True, help_text="Heading of this bearing") transect_distance = models.FloatField( blank=True, null=True, help_text="Distance along this bearing") # Team info: team_letter = models.CharField( blank=True, null=True, help_text="Name of team responsible for this location.", max_length=256) team_number = models.IntegerField( blank=True, null=True, help_text="Differentiates the traps each team is in charge of.") order = models.IntegerField(blank=True, null=True, help_text="Order in which to show this trap.") habitat = models.ForeignKey( Habitat, null=True, blank=True, help_text="What habitat best describes this location?", on_delete=models.SET_NULL) # info about the outcome: whether_a_trap_was_set_here = models.BooleanField( default=False, help_text='''We typically won't use all the locations suggested by the randomization recipe; this denotes that a trap was actually placed at or near this point.''') bait = models.ForeignKey(Bait, null=True, blank=True, help_text="Any bait used", on_delete=models.SET_NULL) animal = models.ForeignKey(Animal, null=True, blank=True, help_text="Any animals caught", on_delete=models.SET_NULL) bait_still_there = models.BooleanField( default=False, help_text='''Was the bait you left in the trap still there when you came back?''') notes_about_outcome = models.TextField( blank=True, help_text="Any miscellaneous notes about the outcome") student_names = models.TextField( blank=True, null=True, help_text='''Names of the students responsible for this location (this would be filled in, if at all, by the instructor after the students have left the forest.''', max_length=256) def date(self): if self.expedition and self.expedition.end_date_of_expedition: return self.expedition.end_date_of_expedition.strftime("%m/%d/%y") else: return None def date_for_solr(self): if self.expedition: return self.expedition.end_date_of_expedition else: return None def trap_nickname(self): return "%s%d" % (self.team_letter, self.team_number) def transect_endpoints(self): trig_radians_angle = positive_radians( degrees_to_radians(self.transect_bearing)) side_of_square = 250.0 # meters. #TODO move this to settings. transect_length = length_of_transect(trig_radians_angle, side_of_square) square_center = self.expedition.grid_square.center center_point = [square_center.lat(), square_center.lon()] result = {} result['center'] = [square_center.lat(), square_center.lon()] result['edge'] = list( walk_transect(center_point, transect_length, trig_radians_angle)) return result def set_transect_bearing_wrt_magnetic_north(self, mnb): result = mnb + 13.0 if result < 0: result = result + 360.0 if result > 360.0: result = result - 360.0 self.transect_bearing = result def set_suggested_lat_lon_from_mag_north(self, heading_degrees_from_mag_north, distance): self.set_transect_bearing_wrt_magnetic_north( heading_degrees_from_mag_north) trig_radians_angle = positive_radians( degrees_to_radians(self.transect_bearing)) square_center = self.expedition.grid_square.center center_point = [square_center.lat(), square_center.lon()] suggested_location = list( walk_transect(center_point, distance, trig_radians_angle)) self.set_suggested_lat_long(suggested_location) def transect_bearing_wrt_magnetic_north(self): result = self.transect_bearing - 13.0 if result < 0: result = result + 360.0 return result def set_suggested_lat_long(self, coords): # see # https://code.djangoproject.com/attachment/ticket/ # 16778/postgis-adapter-2.patch # if this breaks again. self.suggested_point = "POINT(%s %s)" % (coords[0], coords[1]) def set_actual_lat_long(self, coords): # see # https://code.djangoproject.com/attachment/ticket/ # 16778/postgis-adapter-2.patch # if this breaks again. self.actual_point = "POINT(%s %s)" % (coords[0], coords[1]) def __unicode__(self): return self.gps_coords() def suggested_gps_coords(self): return "%s, %s" % (self.suggested_NSlat(), self.suggested_EWlon()) def actual_gps_coords(self): return "%s, %s" % (self.actual_NSlat(), self.actual_EWlon()) def suggested_NSlat(self): lat = self.suggested_lat() if lat: if lat > 0: return '%0.5F N' % abs(lat) return '%0.5F S' % abs(lat) return None def suggested_EWlon(self): lon = self.suggested_lon() if lon: if lon < 0: return '%0.5F W' % abs(lon) return '%0.5F E' % abs(lon) return None def actual_NSlat(self): lat = self.actual_lat() if lat: if lat > 0: return '%0.5F N' % abs(lat) return '%0.5F S' % abs(lat) return None def actual_EWlon(self): lon = self.actual_lon() if lon: if lon < 0: return '%0.5F W' % abs(lon) return '%0.5F E' % abs(lon) return None def suggested_lat(self): if self.suggested_point: return self.suggested_point.coords[0] return None def suggested_lon(self): if self.suggested_point: return self.suggested_point.coords[1] return None def actual_lat(self): if self.actual_point: return self.actual_point.coords[0] return None def actual_lon(self): if self.actual_point: return self.actual_point.coords[1] return None def species_if_any(self): if self.animal: return self.animal.species.common_name else: return None def habitat_if_any(self): if self.habitat: return self.habitat.label else: return None def habitat_id_if_any(self): if self.habitat: return self.habitat.id else: return None def school_if_any(self): if self.expedition.school: return self.expedition.school.name else: return None def search_map_repr(self): result = {} info_string = \ "Animal: %s</br>Habitat: %s</br>School: %s</br>Date: %s" % ( self.species_if_any(), self.habitat_if_any(), self.school_if_any(), self.date()) result['name'] = info_string result['where'] = [self.actual_lat(), self.actual_lon()] result['species'] = self.species_if_any() result['habitat_id'] = self.habitat_id_if_any() result['habitat'] = self.habitat_if_any() result['school'] = self.school_if_any() result['date'] = self.date() return result def dir(self): return dir(self) def gps_coords(self): return "%s, %s" % (self.actual_NSlat(), self.actual_EWlon())
class Project(models.Model): pjid = models.AutoField(primary_key=True) Locatie = models.CharField(max_length=255, blank=False) Hoofdtype = models.ForeignKey(HoofdType, related_name='hoofd_type_project', on_delete=models.CASCADE, blank=True, null=True) Aard = models.ManyToManyField(ProjectType, related_name='project_type_project') Intakedatum = models.DateField(blank=False, default=datetime.now) startdatum = models.DateField(blank=False, default=datetime.now) einddatum = models.DateField(blank=False, default=datetime.now) Plangebied = models.PolygonField(srid=4326, null=True) Organisatie_opdrachtgever = models.ForeignKey( Organisatie, blank=True, related_name='organisatie_project', on_delete=models.CASCADE, null=True) Bestuurlijk_opdrachtgever = models.ForeignKey( Employee, related_name='administrativeclient_project', on_delete=models.CASCADE, blank=True, null=True) Ambtelijk_opdrachtgever = models.ForeignKey( Employee, blank=True, related_name='officialclient_project', on_delete=models.CASCADE, null=True) Opdracht_verantwoordelijke = models.ForeignKey( Employee, blank=False, related_name='maincontractor_project', on_delete=models.CASCADE, null=True) Deel_projectleider = models.ForeignKey( Employee, blank=True, related_name='subcontractor_project', on_delete=models.CASCADE, null=True) Account_houder = models.ForeignKey(Employee, blank=True, related_name='accountant_project', on_delete=models.CASCADE, null=True) Timetellnummer = models.CharField(max_length=18, blank=True, null=True) # Convert manytomany list into a string @property def Type(self): return '{}'.format(self.Hoofdtype) @property def AardList(self): return ', '.join([a.Soort for a in self.Aard.all()]) @property def Jaar(self): return '{}'.format(self.startdatum.year) def __str__(self): return '{} - {} - {} - {}'.format(self.pjid, self.Type, self.AardList, self.Locatie, self.Jaar) objects = models.GeoManager() Indicatiebedrag = models.DecimalField(max_digits=9, decimal_places=2, blank=True, default=0.00) Maximumbedrag = models.DecimalField(max_digits=9, decimal_places=2, blank=True, default=0.00) Vervolgafspraken = models.TextField(max_length=None, blank=True, null=True) class Meta: db_table = 'project'
class Instance(models.Model): json = JSONField(default={}, null=False) xml = models.TextField() user = models.ForeignKey(User, related_name='instances', null=True) xform = models.ForeignKey(XForm, null=True, related_name='instances') survey_type = models.ForeignKey(SurveyType) # shows when we first received this instance date_created = models.DateTimeField(auto_now_add=True) # this will end up representing "date last parsed" date_modified = models.DateTimeField(auto_now=True) # this will end up representing "date instance was deleted" deleted_at = models.DateTimeField(null=True, default=None) # ODK keeps track of three statuses for an instance: # incomplete, submitted, complete # we add a fourth status: submitted_via_web status = models.CharField(max_length=20, default=u'submitted_via_web') uuid = models.CharField(max_length=249, default=u'') version = models.CharField(max_length=XFORM_TITLE_LENGTH, null=True) # store an geographic objects associated with this instance geom = models.GeometryCollectionField(null=True) objects = models.GeoManager() tags = TaggableManager() class Meta: app_label = 'logger' @classmethod def set_deleted_at(cls, instance_id, deleted_at=timezone.now()): try: instance = cls.objects.get(id=instance_id) except cls.DoesNotExist: pass else: instance.set_deleted(deleted_at) def _check_active(self, force): """Check that form is active and raise exception if not. :param force: Ignore restrictions on saving. """ if not force and self.xform and not self.xform.downloadable: raise FormInactiveError() def _set_geom(self): xform = self.xform data_dictionary = xform.data_dictionary() geo_xpaths = data_dictionary.geopoint_xpaths() doc = self.get_dict() points = [] if len(geo_xpaths): for xpath in geo_xpaths: geometry = [float(s) for s in doc.get(xpath, u'').split()] if len(geometry): lat, lng = geometry[0:2] points.append(Point(lng, lat)) if not xform.instances_with_geopoints and len(points): xform.instances_with_geopoints = True xform.save() self.geom = GeometryCollection(points) def _set_json(self): doc = self.get_dict() if not self.date_created: now = submission_time() self.date_created = now point = self.point if point: doc[GEOLOCATION] = [point.y, point.x] doc[SUBMISSION_TIME] = self.date_created.strftime(MONGO_STRFTIME) doc[XFORM_ID_STRING] = self._parser.get_xform_id_string() doc[SUBMITTED_BY] = self.user.username\ if self.user is not None else None self.json = doc def _set_parser(self): if not hasattr(self, "_parser"): self._parser = XFormInstanceParser( self.xml, self.xform.data_dictionary()) def _set_survey_type(self): self.survey_type, created = \ SurveyType.objects.get_or_create(slug=self.get_root_node_name()) def _set_uuid(self): if self.xml and not self.uuid: uuid = get_uuid_from_xml(self.xml) if uuid is not None: self.uuid = uuid set_uuid(self) def get(self, abbreviated_xpath): self._set_parser() return self._parser.get(abbreviated_xpath) def get_dict(self, force_new=False, flat=True): """Return a python object representation of this instance's XML.""" self._set_parser() return self._parser.get_flat_dict_with_attributes() if flat else\ self._parser.to_dict() def get_full_dict(self): # TODO should we store all of these in the JSON no matter what? d = self.json data = { UUID: self.uuid, ID: self.id, BAMBOO_DATASET_ID: self.xform.bamboo_dataset, self.USERFORM_ID: u'%s_%s' % ( self.user.username, self.xform.id_string), ATTACHMENTS: [a.media_file.name for a in self.attachments.all()], self.STATUS: self.status, TAGS: list(self.tags.names()), NOTES: self.get_notes(), VERSION: self.version } if isinstance(self.instance.deleted_at, datetime): data[DELETEDAT] = self.deleted_at.strftime(MONGO_STRFTIME) d.update(data) return d def get_notes(self): return [note['note'] for note in self.notes.values('note')] def get_root_node(self): self._set_parser() return self._parser.get_root_node() def get_root_node_name(self): self._set_parser() return self._parser.get_root_node_name() @property def point(self): gc = self.geom if gc and len(gc): return gc[0] def save(self, *args, **kwargs): force = kwargs.get('force') if force: del kwargs['force'] self._check_active(force) self._set_geom() self._set_json() self._set_survey_type() self._set_uuid() self.version = self.xform.version super(Instance, self).save(*args, **kwargs) def set_deleted(self, deleted_at=timezone.now()): self.deleted_at = deleted_at self.save() # force submission count re-calculation self.xform.submission_count(force_update=True) self.parsed_instance.save()
class StarModel(models.Model): """ Additional data and simulated info about stars. Data needs to be generated using 'build_model' before being accessed """ star = models.OneToOneField(Star, db_index=True, help_text="The star with real data", default=1) star_type = models.ForeignKey(StarType, help_text="Stellar Classification", blank=True, null=True) luminosity_class = models.ForeignKey(StarLuminosityType, help_text="Luminosity Class (0-VII)", blank=True, null=True) luminosity_mod = models.CharField( max_length=5, help_text="Luminosity sub class (a, ab, b, a-0", blank=True, null=True) base_color = models.CharField(max_length=8, help_text="Basic RBG Color", default="#ffddbe", blank=True, null=True) rand_seed = models.FloatField( help_text="Random Seed from 0-1 used to build notional system", blank=True, null=True, default=0) guessed_temp = models.FloatField(help_text="Guessed at Temperature", blank=True, null=True, default=0) guessed_mass = models.FloatField(help_text="Guessed at Mass", blank=True, null=True, default=0) guessed_radius = models.FloatField(help_text="Guessed at Radius", blank=True, null=True, default=0) guessed_age = models.FloatField(help_text="Guessed at Age", blank=True, null=True, default=0) json_of_closest_stars = models.TextField( help_text= "List of Stars, will be filled in automatically on first calculation", blank=True, null=True) ids_of_companion_stars = models.CharField( max_length=30, help_text="Comma-separated IDs of any stars within .3 LY", blank=True, null=True) location = models.PointField(db_index=True, dim=3, blank=True, null=True, srid=900913) objects = models.GeoManager() def build_model(self, star_id=None, star_prime=None, forced=False): np.random.seed() self.add_rand_seed(forced) if not star_prime and not star_id: star_prime = self.star if star_prime: self.star = star_prime else: self.star = Star.objects.get(id=star_id) if self.star: star_a, star_b, star_c, star_d = get_star_type(self.star.spectrum) self.add_type(star_a) self.add_color(star_a, star_b, star_c) self.add_luminosity(star_c) self.luminosity_mod = star_d self.add_rand_variables(forced) self.save() def add_rand_seed(self, forced=False): add_it = True if not forced and self.rand_seed: add_it = False if add_it: self.rand_seed = np.random.random() #rand_range(0, 1) self.save() def add_rand_variables(self, forced=False): add_it = True if not forced and self.guessed_temp: add_it = False if add_it: options = { 'rand_seed': self.rand_seed, 'star_type': self.star_type, 'temp': 0, 'mass': 0, 'age': 0, 'radius': 0, 'luminosity_class': self.luminosity_class, 'luminosity_mod': self.luminosity_mod } settings = star_variables(options) self.guessed_temp = settings.get('temp', 0) self.guessed_mass = settings.get('mass', 0) self.guessed_radius = settings.get('radius', 0) self.guessed_age = settings.get('age', 0) self.save() def add_luminosity(self, star_c): result = "ok" try: star_type = StarLuminosityType.objects.get(symbol=star_c) self.luminosity_class = star_type except StarLuminosityType.DoesNotExist: result = "unknown" return result def add_type(self, star_a): result = "ok" try: star_type = StarType.objects.get(symbol=star_a) self.star_type = star_type except StarType.DoesNotExist: result = "unknown" return result def add_color(self, star_a="K", star_b="", star_c=""): star = self found_color = "" if star_a or star_b or star_c: found_color = color_of_star(star_a, star_b, star_c) if not found_color and star.star and star.star.spectrum: star_a, star_b, star_c = get_star_type(star.star.spectrum) found_color = color_of_star(star_a, star_b, star_c) if not found_color: if star.star_type and star.star_type.base_color: found_color = star.star_type.base_color star.base_color = found_color star.save() class Meta: verbose_name_plural = 'Stars (Simulated)' ordering = ['star'] def nearby_stars(self, force_regenerate=False): if self.json_of_closest_stars and not force_regenerate: star_list = json.loads(self.json_of_closest_stars) else: star_list = closest_stars(self, StarModel) self.json_of_closest_stars = json.dumps(star_list) self.save() return star_list def nearby_stars_json(self): self.nearby_stars() return self.json_of_closest_stars def nearby_stars_json_force_recalc(self): self.nearby_stars(force_regenerate=True) return self.json_of_closest_stars additional_methods = [ 'nearby_stars', ] def get_params(self, requested_methods=None, only_variables=None): """ Converts parameters to object. Options: requested_methods = ['__unicode__', ] (to also call these functions and return results) only_variables = ['name', 'title', ] (to only return values of these model variables) """ additional_methods = self.additional_methods if requested_methods: additional_methods = requested_methods + additional_methods dumps = dict() if not only_variables: model_fields = [field.name for field in self._meta.fields] else: model_fields = only_variables for field in model_fields: val = self.__getattribute__(field) if type(val) == Point: point = dict() point['x'] = val.x point['y'] = val.y point['z'] = val.z dumps[str(field)] = point else: dumps[str(field)] = str(val) for func in additional_methods: dumps[func] = getattr(self, func)() return dumps
class Person(UserenaBaseProfile): # define the fields for your item here like: name = models.CharField(max_length=100, null=True, blank=True) mid = models.CharField(max_length=100, null=True, blank=True) page_url = models.URLField(null=True, blank=True) preferred_email = models.EmailField(null=True, blank=True) company_name = models.CharField(max_length=100, null=True, blank=True) city = models.CharField(max_length=100, null=True, blank=True) state = models.CharField(max_length=100, null=True, blank=True) country = models.CharField(max_length=100, null=True, blank=True) #wesleyan education wesleyan_degree_school_1 = models.CharField(max_length=100, null=True, blank=True) wesleyan_degree_year_1 = models.CharField(max_length=100, null=True, blank=True) wesleyan_degree_1 = models.CharField(max_length=100, null=True, blank=True) wesleyan_degree_1_major_1 = models.CharField(max_length=100, null=True, blank=True) wesleyan_degree_1_major_2 = models.CharField(max_length=100, null=True, blank=True) wesleyan_degree_1_major_3 = models.CharField(max_length=100, null=True) # member information first_name = models.CharField(max_length=100, null=True, blank=True) last_name = models.CharField(max_length=100, null=True, blank=True) nickname = models.CharField(max_length=100, null=True, blank=True) last_name_at_grad = models.CharField(max_length=100, null=True, blank=True) preferred_class_year = models.CharField(max_length=100, null=True, blank=True) preferred_email = models.CharField(max_length=100, null=True, blank=True) #primary employment company_name = models.CharField(max_length=100, null=True, blank=True) position_title = models.CharField(max_length=100, null=True, blank=True) position_status = models.CharField(max_length=100, null=True, blank=True) business_address_1 = models.CharField(max_length=100, null=True, blank=True) business_address_2 = models.CharField(max_length=100, null=True, blank=True) business_address_city = models.CharField(max_length=100, null=True, blank=True) business_address_state = models.CharField(max_length=100, null=True, blank=True) business_address_zip = models.CharField(max_length=100, null=True, blank=True) business_address_country = models.CharField(max_length=100, null=True, blank=True) occupation = models.CharField(max_length=100, null=True, blank=True) industry = models.CharField(max_length=100, null=True, blank=True) #geolocation location = models.PointField(null=True, blank=True) # Override the default manager with GeoManager instance objects = models.GeoManager() people = models.Manager() geolocated = PersonLocationManager() names = PersonNameManager() user = models.OneToOneField(User, null=True, blank=True, unique=True, verbose_name=_('user')) #sites = models.ManyToManyField(Site) def makeName(self): n = self.name.split(',') self.first_name = n[1] self.last_name = n[0] def __unicode__(self): if self.first_name and self.last_name: return self.last_name + ", " + self.first_name elif self.name: self.makeName() return self.last_name + ', ' + self.first_name else: return u"Person object pk=%s" % self.pk
class InstanceHistory(models.Model, InstanceBaseClass): class Meta: app_label = 'logger' xform_instance = models.ForeignKey( Instance, related_name='submission_history') user = models.ForeignKey(User, null=True) xml = models.TextField() # old instance id uuid = models.CharField(max_length=249, default=u'') date_created = models.DateTimeField(auto_now_add=True) date_modified = models.DateTimeField(auto_now=True) submission_date = models.DateTimeField(null=True, default=None) geom = models.GeometryCollectionField(null=True) objects = models.GeoManager() @property def xform(self): return self.xform_instance.xform @property def attachments(self): return self.xform_instance.attachments.all() @property def json(self): return self.get_full_dict(load_existing=False) @property def status(self): return self.xform_instance.status @property def tags(self): return self.xform_instance.tags @property def notes(self): return self.xform_instance.notes.all() @property def version(self): return self.xform_instance.version @property def osm_data(self): return self.xform_instance.osm_data @property def deleted_at(self): return None def _set_parser(self): if not hasattr(self, "_parser"): self._parser = XFormInstanceParser( self.xml, self.xform_instance.xform ) @classmethod def set_deleted_at(cls, instance_id, deleted_at=timezone.now()): return None
class BasicData(models.Model): school_code = models.BigIntegerField(primary_key=True) centroid = models.GeometryField(blank=True, null=True) district = models.CharField(max_length=50, blank=True) school_name = models.CharField(max_length=200, blank=True) block_name = models.CharField(max_length=50, blank=True) cluster_name = models.CharField(max_length=50, blank=True) village_name = models.CharField(max_length=50, blank=True) assembly_name = models.CharField(max_length=35, blank=True) parliament_name = models.CharField(max_length=35, blank=True) pincode = models.IntegerField(null=True, blank=True) new_pincode = models.IntegerField(null=True, blank=True) rural_urban = models.IntegerField(choices=AREA, null=True, blank=True) medium_of_instruction = models.IntegerField(choices=MEDIUM, null=True, blank=True) distance_brc = models.FloatField(null=True, blank=True) distance_crc = models.FloatField(null=True, blank=True) yeur_estd = models.IntegerField(null=True, blank=True) pre_pry_yn = models.IntegerField(null=True, blank=True) residential_sch_yn = models.IntegerField(null=True, blank=True) sch_management = models.IntegerField(choices=SCHOOL_MANAGEMENT, null=True, blank=True) lowest_class = models.IntegerField(null=True, blank=True) highest_class = models.IntegerField(null=True, blank=True) sch_category = models.IntegerField(choices=SCHOOL_CATEGORY, null=True, blank=True) pre_pry_students = models.IntegerField(null=True, blank=True) school_type = models.IntegerField(choices=SCHOOL_TYPES, null=True, blank=True) shift_school_yn = models.IntegerField(null=True, blank=True) no_of_working_days = models.IntegerField(null=True, blank=True) no_of_acad_inspection = models.IntegerField(null=True, blank=True) residential_sch_type = models.IntegerField(null=True, blank=True) pre_pry_teachers = models.IntegerField(null=True, blank=True) visits_by_brc = models.IntegerField(null=True, blank=True) visits_by_crc = models.IntegerField(null=True, blank=True) school_dev_grant_recd = models.FloatField(null=True, blank=True) school_dev_grant_expnd = models.FloatField(null=True, blank=True) tlm_grant_recd = models.FloatField(null=True, blank=True) tlm_grant_expnd = models.FloatField(null=True, blank=True) funds_from_students_recd = models.FloatField(null=True, blank=True) funds_from_students_expnd = models.FloatField(null=True, blank=True) building_status = models.IntegerField(choices=BUILDING_STATUS, null=True, blank=True) tot_clrooms = models.IntegerField(null=True, blank=True) classrooms_in_good_condition = models.IntegerField(null=True, blank=True) classrooms_require_major_repair = models.IntegerField(choices=YESNO, null=True, blank=True) classrooms_require_minor_repair = models.IntegerField(choices=YESNO, null=True, blank=True) other_rooms_in_good_cond = models.IntegerField(null=True, blank=True) other_rooms_need_major_rep = models.IntegerField(null=True, blank=True) other_rooms_need_minor_rep = models.IntegerField(null=True, blank=True) toilet_common = models.IntegerField(null=True, blank=True) toilet_boys = models.IntegerField(null=True, blank=True) toilet_girls = models.IntegerField(null=True, blank=True) kitchen_devices_grant = models.IntegerField(null=True, blank=True) status_of_mdm = models.IntegerField(choices=MDM_STATUS, null=True, blank=True) computer_aided_learnin_lab = models.IntegerField(choices=YESNO, null=True, blank=True) separate_room_for_headmaster = models.IntegerField(choices=YESNO, null=True, blank=True) electricity = models.IntegerField(choices=YESNO, null=True, blank=True) boundary_wall = models.IntegerField(choices=BOUNDARY_WALL, null=True, blank=True) library_yn = models.IntegerField(choices=YESNO, null=True, blank=True) playground = models.IntegerField(choices=YESNO, null=True, blank=True) blackboard = models.IntegerField(null=True, blank=True) books_in_library = models.IntegerField(null=True, blank=True) drinking_water = models.IntegerField(choices=DRINKING_WATER, null=True, blank=True) medical_checkup = models.IntegerField(choices=YESNO, null=True, blank=True) ramps = models.IntegerField(choices=YESNO, null=True, blank=True) no_of_computers = models.IntegerField(null=True, blank=True) male_tch = models.IntegerField(null=True, blank=True) female_tch = models.IntegerField(null=True, blank=True) noresp_tch = models.IntegerField(null=True, blank=True) head_teacher = models.IntegerField(null=True, blank=True) graduate_teachers = models.IntegerField(null=True, blank=True) tch_with_professional_qualification = models.IntegerField(null=True, blank=True) days_involved_in_non_tch_assgn = models.IntegerField(null=True, blank=True) teachers_involved_in_non_tch_assgn = models.IntegerField(null=True, blank=True) class1_total_enr_boys = models.IntegerField(blank=True, null=True) class2_total_enr_boys = models.IntegerField(blank=True, null=True) class3_total_enr_boys = models.IntegerField(blank=True, null=True) class4_total_enr_boys = models.IntegerField(blank=True, null=True) class5_total_enr_boys = models.IntegerField(blank=True, null=True) class6_total_enr_boys = models.IntegerField(blank=True, null=True) class7_total_enr_boys = models.IntegerField(blank=True, null=True) class8_total_enr_boys = models.IntegerField(blank=True, null=True) class1_total_enr_girls = models.IntegerField(blank=True, null=True) class2_total_enr_girls = models.IntegerField(blank=True, null=True) class3_total_enr_girls = models.IntegerField(blank=True, null=True) class4_total_enr_girls = models.IntegerField(blank=True, null=True) class5_total_enr_girls = models.IntegerField(blank=True, null=True) class6_total_enr_girls = models.IntegerField(blank=True, null=True) class7_total_enr_girls = models.IntegerField(blank=True, null=True) class8_total_enr_girls = models.IntegerField(blank=True, null=True) total_boys = models.IntegerField(blank=True, null=True) total_girls = models.IntegerField(blank=True, null=True) objects = models.GeoManager() class Meta: abstract = True def __unicode__(self): return self.school_name @property def popup_content(self): return self.school_name
class Instance(models.Model): """ Each "Tree Map" is a single instance """ name = models.CharField(max_length=255, unique=True) url_name = models.CharField( max_length=255, unique=True, validators=[ reserved_name_validator, RegexValidator( r'^%s$' % URL_NAME_PATTERN, trans('Must start with a letter and may only contain ' 'letters, numbers, or dashes ("-")'), trans('Invalid URL name')) ]) """ Basemap type Basemap data ------------ ----------------- Google Google_API_Key Bing Bing_API_Key TMS TMS URL with {x},{y},{z} """ basemap_type = models.CharField(max_length=255, choices=(("google", "Google"), ("bing", "Bing"), ("tms", "Tile Map Service")), default="google") basemap_data = models.CharField(max_length=255, null=True, blank=True) """ The current database revision for the instance This revision is used to determine if tiles should be cached. In particular, the revision has *no* effect on the actual data. Generally we make tile requests like: http://tileserver/tile/{layer}/{rev}/{Z}/{Y}/{X} There is a database trigger that updates the revision whenever an edit to a geometry field is made so you don't have to worry about it. You should *not* edit this field. """ geo_rev = models.IntegerField(default=1) eco_benefits_conversion = models.ForeignKey('BenefitCurrencyConversion', null=True, blank=True) """ Center of the map when loading the instance """ bounds = models.MultiPolygonField(srid=3857) """ Override the center location (which is, by default, the centroid of "bounds" """ center_override = models.PointField(srid=3857, null=True, blank=True) default_role = models.ForeignKey('Role', related_name='default_role') users = models.ManyToManyField('User', through='InstanceUser', null=True, blank=True) boundaries = models.ManyToManyField('Boundary', null=True, blank=True) """ Config contains a bunch of config variables for a given instance these can be accessed via per-config properties such as `advanced_search_fields`. Note that it is a DotDict, and so supports get() with a dotted key and a default, e.g. instance.config.get('fruit.apple.type', 'delicious') as well as creating dotted keys when no keys in the path exist yet, e.g. instance.config = DotDict({}) instance.config.fruit.apple.type = 'macoun' """ config = JSONField(blank=True) is_public = models.BooleanField(default=False) logo = models.ImageField(upload_to='logos', null=True, blank=True) itree_region_default = models.CharField(max_length=20, null=True, blank=True, choices=ITREE_REGION_CHOICES) # Monotonically increasing number used to invalidate my InstanceAdjuncts adjuncts_timestamp = models.BigIntegerField(default=0) objects = models.GeoManager() def __unicode__(self): return self.name def _make_config_property(prop, default=None): def get_config(self): return self.config.get(prop, default) def set_config(self, value): self.config[prop] = value return property(get_config, set_config) date_format = _make_config_property('date_format', settings.DATE_FORMAT) short_date_format = _make_config_property('short_date_format', settings.SHORT_DATE_FORMAT) scss_variables = _make_config_property('scss_variables') map_feature_types = _make_config_property('map_feature_types', ['Plot']) mobile_search_fields = _make_config_property('mobile_search_fields', DEFAULT_MOBILE_SEARCH_FIELDS) mobile_api_fields = _make_config_property('mobile_api_fields', DEFAULT_MOBILE_API_FIELDS) non_admins_can_export = models.BooleanField(default=True) @property def advanced_search_fields(self): # TODO pull from the config once users have a way to set search fields if not self.feature_enabled('advanced_search_filters'): return { 'standard': [], 'missing': [], 'display': [], 'udfc': self._get_udfc_search_fields() } from treemap.models import MapFeature # prevent circular import fields = { 'standard': [{ 'identifier': 'tree.diameter', 'search_type': 'RANGE' }, { 'identifier': 'tree.date_planted', 'search_type': 'RANGE' }, { 'identifier': 'mapFeature.updated_at', 'search_type': 'RANGE' }], 'display': [{ 'model': 'Tree', 'label': 'Show trees' }, { 'model': 'EmptyPlot', 'label': 'Show empty planting sites' }], 'missing': [{ 'identifier': 'species.id', 'label': 'Show missing species', 'search_type': 'ISNULL', 'value': 'true' }, { 'identifier': 'tree.diameter', 'label': 'Show missing trunk diameter', 'search_type': 'ISNULL', 'value': 'true' }, { 'identifier': 'mapFeaturePhoto.id', 'label': 'Show missing photos', 'search_type': 'ISNULL', 'value': 'true' }], } def make_display_filter(feature_name): Feature = MapFeature.get_subclass(feature_name) if hasattr(Feature, 'display_name_plural'): plural = Feature.display_name_plural else: plural = Feature.display_name + 's' return {'label': 'Show %s' % plural.lower(), 'model': feature_name} fields['display'] += [ make_display_filter(feature_name) for feature_name in self.map_feature_types if feature_name != 'Plot' ] # It makes styling easier if every field has an identifier num = 0 for filters in fields.itervalues(): for field in filters: field['id'] = "%s_%s" % (field.get('identifier', ''), num) num += 1 fields['udfc'] = self._get_udfc_search_fields() return fields def _get_udfc_search_fields(self): from treemap.util import to_object_name empty_udfc = { to_object_name(n_k): { to_object_name(m_k): { 'fields': [], 'udfd': None } for m_k in UDFC_MODELS } for n_k in UDFC_NAMES } udfds = [] for model_name in UDFC_MODELS: for udfd in udf_defs(self, model_name): if udfd.name in UDFC_NAMES: udfds.append(udfd) udfc = deepcopy(empty_udfc) for udfd in udfds: udfd_info = { 'udfd': udfd, 'fields': udfd.datatype_dict[0]['choices'] } name_dict = udfc[to_object_name(udfd.name)] name_dict[to_object_name(udfd.model_type)] = udfd_info return udfc @property def supports_resources(self): """ Determine whether this instance has multiple map feature types (plots + "resources") or not. """ n = len(self.map_feature_types) return n > 1 @property def extent_as_json(self): boundary = self.bounds.boundary xmin, ymin, xmax, ymax = boundary.extent return json.dumps({ 'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax }) @property def bounds_as_geojson(self): boundary = self.bounds boundary.transform(4326) return boundary.json @property def center(self): return self.center_override or self.bounds.centroid @property def geo_rev_hash(self): return hashlib.md5(str(self.geo_rev)).hexdigest() @property def center_lat_lng(self): return self.center.transform(4326, clone=True) @property def factor_conversions(self): """ Returns a dict for use in eco.py Benefits from eco_benefits_conversion """ benefits_conversion = self.eco_benefits_conversion if benefits_conversion: return benefits_conversion.get_factor_conversions_config() else: return None @property def scss_query_string(self): scss_vars = ({k: val for k, val in self.scss_variables.items() if val} if self.scss_variables else {}) return urlencode(scss_vars) @property def static_page_names(self): from treemap.models import StaticPage # prevent circular import built_in_names = StaticPage.built_in_names() custom_names = [ page.name for page in StaticPage.objects.filter( instance=self).exclude(name__in=built_in_names) ] names = built_in_names + custom_names return names def update_geo_rev(self): qs = Instance.objects.filter(pk=self.id) # Use SQL increment in case self.geo_rev is stale qs.update(geo_rev=F('geo_rev') + 1) # Fetch updated value so callers will have it self.geo_rev = qs[0].geo_rev def itree_region_codes(self): from treemap.models import ITreeRegion if self.itree_region_default: region_codes = [self.itree_region_default] else: region_codes = ITreeRegion.objects \ .filter(geometry__intersects=self.bounds) \ .values_list('code', flat=True) return region_codes def itree_regions(self): from treemap.models import ITreeRegion # prevent circular import if self.itree_region_default: codes = [self.itree_region_default] else: codes = (ITreeRegion.objects.filter( geometry__intersects=self.bounds).values_list('code', flat=True)) return [(code, ITREE_REGIONS.get(code, {}).get('name')) for code in codes] def has_itree_region(self): return bool(self.itree_regions()) def is_accessible_by(self, user): try: if self.is_public: return True # Extension point if hasattr(user, 'is_super_admin') and user.is_super_admin(): return True # If a user is not logged in, trying to check # user=user raises a type error so I am checking # pk instead self.instanceuser_set.get(user__pk=user.pk) return True except ObjectDoesNotExist: return False def scope_model(self, model): qs = model.objects.filter(instance=self) return qs def feature_enabled(self, feature): # Delayed import to prevent circular imports from treemap.plugin import feature_enabled return feature_enabled(self, feature) def seed_with_dummy_default_role(self): """ Instances need roles and roles needs instances... crazy stuff we're going to create the needed role below however, we'll temporarily use a 'dummy role'. The dummy role has no instance. """ from treemap.audit import Role dummy_roles = Role.objects.filter(instance__isnull=True) if len(dummy_roles) == 0: dummy_role = Role.objects.create(name='empty', rep_thresh=0) else: dummy_role = dummy_roles[0] self.default_role = dummy_role def clean(self): # We need to work around a bit of a chicken/egg problem here # The default API fields reference Stewardship, but the Stewardship # UDFs won't exist when the instance is first created. # To work around this, we only validate when there is something in the # 'config' object, which ignores the default api fields if 'mobile_api_fields' in self.config: self._validate_mobile_api_fields() def _validate_mobile_api_fields(self): # Validate that: # 1) overall structure is correct # 2) each individual group has a header and collection or normal fields # 3) Collection UDF groups only contain collection UDFs # 4) Collection UDF groups have a 'sort_key', which is present on all # fields for that group # 5) no field is referenced more than once # 6) all fields referenced exist # delayed import to avoid circular references from treemap.models import Plot, Tree def _truthy_of_type(item, types): return item and isinstance(item, types) field_groups = self.mobile_api_fields errors = set() scalar_udfs = { udef.full_name: udef for udef in udf_defs(self) if not udef.iscollection } collection_udfs = { udef.full_name: udef for udef in udf_defs(self) if udef.iscollection } if not _truthy_of_type(field_groups, (list, tuple)): raise ValidationError( {'mobile_api_fields': [API_FIELD_ERRORS['no_field_groups']]}) for group in field_groups: if not _truthy_of_type(group.get('header'), basestring): errors.add(API_FIELD_ERRORS['group_has_no_header']) if ((not _truthy_of_type(group.get('collection_udf_keys'), list) and not _truthy_of_type(group.get('field_keys'), list))): errors.add(API_FIELD_ERRORS['group_has_no_keys']) elif 'collection_udf_keys' in group and 'field_keys' in group: errors.add(API_FIELD_ERRORS['group_has_both_keys']) if 'collection_udf_keys' in group: sort_key = group.get('sort_key') if not sort_key: errors.add(API_FIELD_ERRORS['group_has_no_sort_key']) for key in group['collection_udf_keys']: udef = collection_udfs.get(key) if udef is None: errors.add(API_FIELD_ERRORS['group_has_missing_cudf']) elif sort_key not in udef.datatype_by_field: errors.add( API_FIELD_ERRORS['group_has_invalid_sort_key']) scalar_fields = [ key for group in field_groups for key in group.get('field_keys', []) ] collection_fields = [ key for group in field_groups for key in group.get('collection_udf_keys', []) ] all_fields = scalar_fields + collection_fields if len(all_fields) != len(set(all_fields)): errors.add(API_FIELD_ERRORS['duplicate_fields']) for field in scalar_fields: if not re.match(r'(?:plot|tree)[.].*', field): errors.add(API_FIELD_ERRORS['invalid_field'] % {'field': field}) continue model_name, name = field.split('.', 1) # maxsplit of 1 Model = Plot if model_name == 'plot' else Tree standard_fields = Model._meta.get_all_field_names() if ((name not in standard_fields and field not in scalar_udfs)): errors.add(API_FIELD_ERRORS['missing_field']) if errors: raise ValidationError({'mobile_api_fields': errors}) def save(self, *args, **kwargs): self.full_clean() self.url_name = self.url_name.lower() super(Instance, self).save(*args, **kwargs)
class Locazione(ConMarcaTemporale, models.Model): class Meta: verbose_name = "Locazione Geografica" verbose_name_plural = "Locazioni Geografiche" permissions = ( ("view_locazione", "Can view locazione"), ) indirizzo = models.CharField("Indirizzo", max_length=255, db_index=True) objects = models.GeoManager() geo = models.PointField(blank=True, default='POINT(0.0 0.0)', db_index=True, spatial_index=True, srid=4326, geography=True) via = models.CharField("Via", max_length=64, blank=True) civico = models.CharField("Civico", max_length=16, blank=True) comune = models.CharField("Comune", max_length=64, blank=True, db_index=True) provincia = models.CharField("Provincia", max_length=64, blank=True, db_index=True) provincia_breve = models.CharField("Provincia (breve)", max_length=64, blank=True, db_index=True) regione = models.CharField("Regione", max_length=64, blank=True, db_index=True) cap = models.CharField("CAP", max_length=32, blank=True, db_index=True) stato = CountryField("Stato", default="IT") def __str__(self): return self.indirizzo @classmethod def scomponi_indirizzo(cls, oggetto): INDIRIZZO_PARTI = ( ('civico', ('street_number', 'long_name')), ('via', ('route', 'long_name')), ('comune', ('locality', 'long_name')), ('provincia', ('administrative_area_level_2', 'long_name')), ('provincia_breve', ('administrative_area_level_2', 'short_name')), ('regione', ('administrative_area_level_1', 'long_name')), ('stato', ('country', 'short_name')), ('cap', ('postal_code', 'long_name')) ) parti = {a[0]: None for a in INDIRIZZO_PARTI} for (parte, nomenclatura) in INDIRIZZO_PARTI: (a, b) = nomenclatura for p in oggetto['address_components']: if not a in p['types']: continue parti[parte] = p[b].replace('Provincia di ', '').replace('Province of ', '')\ .replace('Provincia della ', 'La ').replace('Provincia dell\'', 'L\'') return parti @classmethod def controlla_posizione(cls, coordinate): """ Valida le coordinate. L'unico controllo possibile รจ che le coordinate non devono essere entrambe zero :param coordinate: vettore lat / lng ritornato da google geocoding :return: coordinate inalterate o '0' """ try: if coordinate['lat'] and coordinate['lng']: return coordinate except (KeyError, ValueError, TypeError): return '0' return '0' @classmethod def cerca(cls, indirizzo): """ Usa le API di Google (Geocode) per cercare l'indirizzo, ritorna una stringa (indirizzo formattato) per ogni risultato. :param indirizzo: Indirizzo da cercare :return: Lista di risultati. """ try: gmaps = googlemaps.Client(key=GOOGLE_KEY) except ValueError: # API key not configured logger.warning("Chiave API Google non configurata. Le ricerche geografiche non ritorneranno " "alcun risultato.") return [] risultati = gmaps.geocode(indirizzo, region="it", language="it") return [ (x['formatted_address'], cls.controlla_posizione(x['geometry']['location']), cls.scomponi_indirizzo(x)) for x in risultati ] @classmethod def oggetto(self, indirizzo): """ Cerca un oggetto per indirizzo. Se esistente, ritorna la referenza. Altrimenti, interroga Google, scompone l'indirizzo e ritorna una nuova istanza di Locazione (salvata). :param indirizzo: Una stringa da ricercare. :return: Oggetto Locazione o None se non trovato. """ if not indirizzo: return None j = Locazione.objects.filter(indirizzo=indirizzo).first() if j: return j risultati = Locazione.cerca(indirizzo) if not len(risultati): return None risultato = risultati[0] j = Locazione.objects.filter(indirizzo=risultato[0]).first() if j: return j l = Locazione( indirizzo=risultato[0], geo=Point(risultato[1]['lng'], risultato[1]['lat']), **{k: risultato[2][k] if risultato[2][k] else '' for k in risultato[2]} ) l.save() return l def cerca_e_aggiorna(self): """ Cerca indirizzo in 'indirizzo' e aggiorna indirizzo e coordinate. """ risultati = Locazione.cerca(self.indirizzo) if not len(risultati): return False risultato = risultati[0] self.indirizzo = risultato[0] self.geo = Point(risultato[1]['lng'], risultato[1]['lat']) valori = {k: risultato[2][k] if risultato[2][k] else '' for k in risultato[2]} for k in valori: setattr(self, k, valori[k]) return self.save() @property def formattato(self): return self.indirizzo.replace("Italy", "Italia")
class Layer(models.Model): """ A layer object that can be added to any map. """ name = models.CharField( max_length=200, help_text='Name that will be displayed within GeoQ') type = models.CharField(choices=SERVICE_TYPES, max_length=75) url = models.CharField( help_text= 'URL of service. If WMS or ESRI, can be any valid URL. Otherwise, the URL will require a local proxy', max_length=500) layer = models.CharField( max_length=800, null=True, blank=True, help_text= 'Layer names can sometimes be comma-separated, and are not needed for data layers (KML, GeoRSS, GeoJSON...)' ) image_format = models.CharField( null=True, blank=True, choices=IMAGE_FORMATS, max_length=75, help_text= 'The MIME type of the image format to use for tiles on WMS layers (image/png, image/jpeg image/gif...). Double check that the server exposes this exactly - some servers push png instead of image/png.' ) styles = models.CharField( null=True, blank=True, max_length=200, help_text= 'The name of a style to use for this layer (only useful for WMS layers if the server exposes it.)' ) transparent = models.BooleanField( default=True, help_text= 'If WMS or overlay, should the tiles be transparent where possible?') refreshrate = models.PositiveIntegerField( blank=True, null=True, verbose_name="Layer Refresh Rate", help_text= 'Layer refresh rate in seconds for vector/data layers (will not refresh WMS layers)' ) description = models.TextField( max_length=800, null=True, blank=True, help_text= 'Text to show in layer chooser, please be descriptive - this will soon be searchable' ) attribution = models.CharField( max_length=200, null=True, blank=True, help_text= "Attribution from layers to the map display (will show in bottom of map when layer is visible)." ) token = models.CharField( max_length=400, null=True, blank=True, help_text= 'Authentication token, if required (usually only for secure layer servers)' ) ## Advanced layer options objects = models.GeoManager() extent = models.PolygonField(null=True, blank=True, help_text='Extent of the layer.') layer_parsing_function = models.CharField( max_length=100, blank=True, null=True, help_text= 'Advanced - The javascript function used to parse a data service (GeoJSON, GeoRSS, KML), needs to be an internally known parser. Contact an admin if you need data parsed in a new way.' ) enable_identify = models.BooleanField( default=False, help_text= 'Advanced - Allow user to click map to query layer for details. The map server must support queries for this layer.' ) info_format = models.CharField( max_length=75, null=True, blank=True, choices=INFO_FORMATS, help_text='Advanced - what format the server returns for an WMS-I query' ) root_field = models.CharField( max_length=100, null=True, blank=True, help_text= 'Advanced - For WMS-I (queryable) layers, the root field returned by server. Leave blank for default (will usually be "FIELDS" in returned XML).' ) fields_to_show = models.CharField( max_length=200, null=True, blank=True, help_text= 'Fields to show when someone uses the identify tool to click on the layer. Leave blank for all.' ) downloadableLink = models.URLField( max_length=400, null=True, blank=True, help_text= 'URL of link to supporting tool (such as a KML document that will be shown as a download button)' ) layer_params = JSONField( null=True, blank=True, help_text= 'JSON key/value pairs to be sent to the web service. ex: {"crs":"urn:ogc:def:crs:EPSG::4326"}' ) dynamic_params = JSONField( null=True, blank=True, help_text= 'URL Variables that may be modified by the analyst. ex: "date"') spatial_reference = models.CharField( max_length=32, blank=True, null=True, default="EPSG:4326", help_text= 'The spatial reference of the service. Should be in ESPG:XXXX format.' ) constraints = models.TextField( null=True, blank=True, help_text='Constrain layer data displayed to certain feature types') disabled = models.BooleanField( default=False, blank=True, help_text="If unchecked, Don't show this layer when listing all layers" ) layer_info_link = models.URLField( null=True, blank=True, help_text='URL of info about the service, or a help doc or something', max_length=500) created_at = models.DateTimeField(auto_now_add=True, null=True) updated_at = models.DateTimeField(auto_now_add=True, null=True) ## Primarily for http://trac.osgeo.org/openlayers/wiki/OpenLayersOptimization additional_domains = models.TextField( null=True, blank=True, help_text= 'Semicolon seperated list of additional domains for the layer. Only used if you want to cycle through domains for load-balancing' ) def __unicode__(self): return '{0}'.format(self.name) def get_layer_urls(self): """ Returns a list of urls for the layer. """ urls = [] if getattr(self, 'additional_domains'): map(urls.append, (domain for domain in self.additional_domains.split(";") if domain)) return urls def get_absolute_url(self): return reverse('layer-update', args=[self.id]) def get_layer_params(self): """ Returns the layer_params attribute, which should be json """ return self.layer_params def layer_json(self): return { "id": self.id, "name": self.name, "format": self.image_format, "type": self.type, "url": self.url, "subdomains": self.get_layer_urls(), "layer": self.layer, "transparent": self.transparent, "layerParams": self.layer_params, "dynamicParams": self.dynamic_params, "refreshrate": self.refreshrate, "token": self.token, "attribution": self.attribution, "spatialReference": self.spatial_reference, "layerParsingFunction": self.layer_parsing_function, "enableIdentify": self.enable_identify, "rootField": self.root_field, "infoFormat": self.info_format, "fieldsToShow": self.fields_to_show, "description": self.description, "downloadableLink": self.downloadableLink, "layer_info_link": self.layer_info_link, "styles": self.styles, } class Meta: ordering = ["name"]