class Policy(SharedKey, Name, Tags, PolicyLookup): """ A Policy is a loosely defined data structure. That represents a policy of a policy set. Policies may be shared across sets. Their semantic meaning may be determined by their shared key and they may be categorized by their tags. A policy has a range of possible values, anything from True/False to a number range or anything else that can be selected and have meaning. The range is serialized by the values attribute. Classes that have PolicySet attributes, namely ConfigEntity instances, should store the actual selected value of each Policy in a separate data structure ConfigEntity instances store policy settings in ConfigEntity.selections.policy_sets. See that attribute to understand how policy value selections are stored. """ schema = models.CharField(max_length=100, null=True) objects = GeoInheritanceManager() policies = models.ManyToManyField('Policy', default=lambda: []) # Pickle the set of values into a single string field # The allowed values of the policy. This should be anything that can be serialized and represented on the client values = PickledObjectField() def update_or_create_policy(self, policy_config): child_policy = Policy.objects.update_or_create( key=policy_config['key'], schema='%s__%s' % (self.schema, policy_config['key']) if self.schema else policy_config['key'], defaults=dict( name=policy_config['name'], description=policy_config.get('description', None), values=policy_config. get('values', {}) ))[0] if policy_config.get('policies', None) and len(policy_config['policies']) > 0: child_policy.policies.add(*map(lambda child_policy_config: child_policy.update_or_create_policy(child_policy_config), policy_config['policies'])) return child_policy class Meta(object): app_label = 'main'
class PlacetypeComponent(BuiltForm, BuiltFormAggregate): """ PlacetypeComponent represents a mix of PrimaryComponents, such as a "Rural Community College" or a "Boulevard" """ objects = GeoInheritanceManager() primary_components = models.ManyToManyField( PrimaryComponent, through='PrimaryComponentPercent') component_category = models.ForeignKey(PlacetypeComponentCategory) def get_component_field(self): return self.__class__.primary_components class Meta(object): app_label = 'main' def calculate_gross_net_ratio(self): return 1 def get_aggregate_field(self): return self.placetype_set def get_aggregate_built_forms(self): return self.placetype_set.all() def get_percent_set(self): return self.primarycomponentpercent_set
class PrimaryComponentPercent(Percent): """ Many-to-many "through" class adds a percent field """ objects = GeoInheritanceManager() primary_component = models.ForeignKey(PrimaryComponent) placetype_component = models.ForeignKey(PlacetypeComponent) @property def component_class(self): return self.primary_component.subclassed_built_form.__class__.__name__ @property def container_class(self): return self.placetype_component.subclassed_built_form.__class__.__name__ class Meta(object): app_label = 'main' def component(self): return BuiltForm.resolve_built_form(self.primary_component) def aggregate(self): return BuiltForm.resolve_built_form(self.placetype_component) def __unicode__(self): return '{2}: [{1}% {0}]'.format(self.primary_component.name, round(self.percent * 100, 3), self.placetype_component.name)
class ScagDmLandUse(ClientLandUse): objects = GeoInheritanceManager() land_use_definition = models.ForeignKey(ScagDmLandUseDefinition, null=False) class Meta(object): app_label = 'main'
class SacogLandUseDefinition(ClientLandUseDefinition): objects = GeoInheritanceManager() @property def label(self): return self.land_use land_use = models.CharField(max_length=100, null=True, blank=True) min_du_ac = models.DecimalField(max_digits=9, decimal_places=2, default=0) max_du_ac = models.DecimalField(max_digits=9, decimal_places=2, default=0) max_emp_ac = models.DecimalField(max_digits=9, decimal_places=2, default=0) rural_flag = models.BooleanField(default=False) detached_flag = models.BooleanField(default=False) attached_flag = models.BooleanField(default=False) pct_ret_rest = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_ret_ret = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_ret_svc = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_off_gov = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_off_off = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_off_svc = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_off_med = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_ind = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_pub_edu = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_pub_med = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_pub_gov = models.DecimalField(max_digits=9, decimal_places=2, default=0) pct_other = models.DecimalField(max_digits=9, decimal_places=2, default=0) class Meta(object): abstract = False app_label = 'main'
class LayerLibrary(Presentation): """ A library that organizes the db_entities of its inherited Presentation that are associated via presentation's media. A Library supports sorting, filtering, hiding of the underlying data. """ objects = GeoInheritanceManager() presentation_media_alias = 'layers' # We have to put this here instead of the base class as presentation_media to prevent a Django bug. # Since it is here we make the related class a Layer layers = models.ManyToManyField('Layer', related_name='layer_libraries') @property def computed_layers(self): """ All Layers of the LayerLibrary that are not deleted and do not reference an incomplete DbEntity :return: """ return self.computed_presentation_media( db_entity_interest__db_entity__setup_percent_complete=100) def layers_of_owned_db_entities(self): owned_db_entities = self.config_entity.owned_db_entities() return filter( lambda layer: layer.db_entity_interest.db_entity in owned_db_entities, self.layers.all()) class Meta(object): app_label = 'main'
class AttributeIntersection(Intersection): """ Indicates an Attribute-based intersection. Since the attribute values are specific to the DbEntities, there are no attributes here yet. The attributes are on the FeatureBehaviorIntersection """ objects = GeoInheritanceManager() class Meta(object): abstract = False app_label = 'main' join_type_key = JoinTypeKey.ATTRIBUTE # The default Token tree for a Geographic intersection uses st_intersects as the equality token # and uses the geographic functions as the left and right operator. default_tree = Token(leftSide=Token(tokenType='PROPERTY', tokenValue='{from_attribute}'), rightSide=Token(tokenType='PROPERTY', tokenValue='{to_attribute}'), tokenType="=", tokenValue="=") # The attribute of the Primary Geography DbEntity used for attribute joins from_attribute = models.CharField(max_length=50, null=True) # The attribute of the target DbEntity used for attribute joins to_attribute = models.CharField(max_length=50, null=True) @classproperty def default_template(cls): return cls.objects.get_or_create(is_template=True)
class BuildingUsePercent(Percent): """ Describes the percent of :model:`main.BuildingUseDefinition` present in a particular :model:`main.BuildingAttributeSet`. """ objects = GeoInheritanceManager() building_attribute_set = models.ForeignKey('BuildingAttributeSet') building_use_definition = models.ForeignKey('BuildingUseDefinition') # describes the ratio : use areas / (common areas + use areas) efficiency = models.DecimalField(max_digits=6, decimal_places=4, default=.85) # describes the number of square feet per unit ( dwelling unit or employee ) of the building square_feet_per_unit = models.DecimalField(max_digits=11, decimal_places=3, null=True) ## derived attributes # area measured in acres floor_area_ratio = models.DecimalField(max_digits=12, decimal_places=10, null=True) unit_density = models.DecimalField(max_digits=16, decimal_places=10, null=True) # area measured in square feet gross_built_up_area = models.DecimalField(max_digits=13, decimal_places=3, null=True) net_built_up_area = models.DecimalField(max_digits=13, decimal_places=3, null=True) class Meta(object): app_label = 'main' def __unicode__(self): use = self.building_use_definition return use.name def calculate_derived_attributes(self): """ Calculates floor_area_ratio, gross_built_up_area, net_built_up_area, and use_density based on the inputs self.built_form.total_far, self.built_form.gross_net_ratio, self.percent, self.efficiency, and either self.square_feet_per_unit or self.built_form.residential_average_lot_size (the latter for detached residential building_use_definitions). """ parcel_far = self.building_attribute_set.total_far # / self.building_attribute_set.gross_net_ratio self.floor_area_ratio = self.percent * parcel_far if self.building_use_definition.name == Keys.DETACHED_SINGLE_FAMILY: self.gross_built_up_area = self.square_feet_per_unit * (Constants.SQUARE_FEET_PER_ACRE / self.building_attribute_set.lot_size_square_feet) else: self.gross_built_up_area = self.floor_area_ratio * self.building_attribute_set.lot_size_square_feet * \ (Constants.SQUARE_FEET_PER_ACRE / self.building_attribute_set.lot_size_square_feet) self.net_built_up_area = self.gross_built_up_area * self.efficiency percent_of_parcel_acres = self.percent # / self.building_attribute_set.gross_net_ratio if self.building_use_definition.name == Keys.DETACHED_SINGLE_FAMILY and self.building_attribute_set.lot_size_square_feet: residential_lots_per_acre = Constants.SQUARE_FEET_PER_ACRE / self.building_attribute_set.lot_size_square_feet self.unit_density = percent_of_parcel_acres * residential_lots_per_acre else: self.unit_density = self.net_built_up_area / self.square_feet_per_unit self.save()
class Category(models.Model): objects = GeoInheritanceManager() key = models.CharField(max_length=100, null=False) value = models.CharField(max_length=100, null=False) class Meta: app_label = 'main'
class Building(PrimaryComponent, BuildingAttributeSetMixin): """ Building represents a template building, such as a Rural Community College """ objects = GeoInheritanceManager() class Meta(object): # This is not abstract so that django can form a many-to-many relationship with it in built_form_set app_label = 'main'
class Interest(Key): """ An indication of ownership, dependency, follower, etc, to indicate a ConfigEntity's relationship to a DbEntity """ objects = GeoInheritanceManager() class Meta(object): abstract = False app_label = 'main'
class BuiltFormSet(Key, Name, Deletable): """ A BuiltFormSet is a combination of any classes inheriting BuiltForm """ objects = GeoInheritanceManager() built_forms = models.ManyToManyField(BuiltForm) class Meta(object): app_label = 'main'
class PolicySet(Key, Name, PolicyLookup, Deletable): """ A policy set is a list of policies, which may themselves embed policies. PolicySet also defines an attributes object to store arbitrary information about the policy set """ objects = GeoInheritanceManager() policies = models.ManyToManyField(Policy) class Meta(object): app_label = 'main'
class Crop(PrimaryComponent, AgricultureAttributeSetMixin): """ Crop represents a template crop, such as "Alfalfa" or "Carrot" """ objects = GeoInheritanceManager() class Meta(object): # This is not abstract so that django can form a many-to-many relationship with it in built_form_set app_label = 'main'
class GeographicType(Key): """ Simple class to define geography function by key, such as POLYGON and CENTROID """ objects = GeoInheritanceManager() class Meta(object): abstract = False app_label = 'main'
class BuildingType(PlacetypeComponent, BuildingAttributeAggregate, BuildingAttributeSetMixin): """ BuildingType represents a mix of template building, such as a Rural Community College """ objects = GeoInheritanceManager() class Meta(object): app_label = 'main'
class AgricultureFeature(PaintingFeature): """ A dynamically subclassed abstract class that represents the agriculture canvas table for a specific Scenerio. Hence instances of subclasses of this class correspond to geography rows of the canvas table """ objects = GeoInheritanceManager() # built_form is added dynamically to subclasses api_include = [ 'built_form', 'built_form_key', 'acres_gross', 'crop_yield', 'market_value', 'production_cost', 'water_consumption', 'labor_force', 'truck_trips' ] built_form_key = models.CharField(max_length=100, default=None, null=True) acres_gross = models.DecimalField(max_digits=14, decimal_places=4, default=0) crop_yield = models.DecimalField(max_digits=14, decimal_places=4, default=0) market_value = models.DecimalField(max_digits=14, decimal_places=4, default=0) production_cost = models.DecimalField(max_digits=14, decimal_places=4, default=0) water_consumption = models.DecimalField(max_digits=14, decimal_places=4, default=0) labor_force = models.DecimalField(max_digits=14, decimal_places=4, default=0) truck_trips = models.DecimalField(max_digits=14, decimal_places=4, default=0) @classmethod def post_save(cls, user_id, objects, **kwargs): """ Called after Features are saved by the FeatureResource. This calls post save publishing for Features, which includes updating tilestache for impacted layers and calling the Agriculture Builder Analysis Tool :param user_id: :param objects: :param kwargs: :return: """ ids = map(lambda obj: obj.id, objects) from footprint.main.publishing.feature_publishing import on_feature_post_save on_feature_post_save(cls, instance=objects, ids=ids, user_id=user_id) class Meta(object): app_label = 'main' abstract = True
class LandscapeType(Placetype, AgricultureAttributeSet): """ Placetypes are a set of BuildingTypes with a percent mix applied to each BuildingType """ objects = GeoInheritanceManager() # So the model is pluralized correctly in the admin. class Meta(BuiltForm.Meta): verbose_name_plural = "Landscape Types" app_label = 'main'
class GenericModelClass(object): __metaclass__ = FootprintMetaclass objects = GeoInheritanceManager() class Meta: # Set the table name db_table = '"{0}"."{1}"'.format(schema, table) app_label = 'main' managed = is_managed
class JoinType(Key): """ Simple class to define an attribute join and a geographic join """ objects = GeoInheritanceManager() class Meta(object): abstract = False app_label = 'main'
class Intersection(models.Model): """ Describes an intersection from on geographic table to another. The tree is a Token object defined for a subclass that can embed 0 to many more Tokens recursively. The tree describes an intersection query completely or can use parameters in the form {param_name} to provide spaces that are filled in by field values of subclasses """ objects = GeoInheritanceManager() # Holds a default Token tree in memory. We don't store this in the database since it is constant. default_tree = None, # IF the customization of the default Token tree is needed, it is stored in the database here tree = PickledObjectField(default=None, null=True) # Class constant indicating the join type # This helps the front-end determine what kind of UI to show join_type_key = None # This is set True to indicate that the Intersection is a template instance that is shared among # instances, such as Behaviors, that never update the Intersection is_template = models.BooleanField(default=False) # feature_behavior is implicitly created by Django, since FeatureBehavior has a toOne @property def join_type(self): if not self.join_type_key: raise Exception("Class %s does not define a join_type_key" % self.__class__.__name__) return JoinType.objects.get(key=self.join_type_key) @property def subclassed(self): """ Return the subclassed version of the Intersection. If not yet persisted the intersection instance will be a subclass or null :return: """ return Intersection.objects.get_subclass(id=self.id) if\ self.id else\ self @property def feature_behavior(self): """ This is justed used by the API to back-dirty the feature_behavior from the Intersection. It should probably be handled exclusively in the front- end :return: """ if self.is_template: # Multiples possible, so return None return None return list(self.featurebehavior_set.all())[0] class Meta(object): abstract = False app_label = 'main'
class CensusBlockgroup(Feature): objects = GeoInheritanceManager() blockgroup = models.CharField(max_length=20) tract = models.CharField(max_length=20) @property def label(self): return self.blockgroup class Meta: abstract = True app_label = 'main'
class BaseScenario(Scenario): """ BaseScenarios represent an editing of primary or CanvasFeature data. """ objects = GeoInheritanceManager() class Meta(object): permissions = ( ('view_basescenario', 'View Base Scenario'), # Permission to merge data from another Scenario into this one ('merge_basescenario', 'Merge Base Scenario'), ) app_label = 'main'
class PresentationConfiguration(ScopedKey, Name): """ Configures what db_entities are representation as PresentationMedia in a presentation, and which of those are initially visible in the presentation. This class will likely add all kinds of other configuration options. Everything is stored in a PickledObjectField for flexibility """ objects = GeoInheritanceManager() data = PickledObjectField() class Meta(object): app_label = 'main'
class TransitStopFeature(Feature): """ A transit stop point table based on the GTFS classification schema """ objects = GeoInheritanceManager() route_id = models.IntegerField(null=True, blank=True) stop_id = models.IntegerField(null=True, blank=True) route_type = models.IntegerField(null=True, blank=True) #county = models.CharField(max_length=100, null=True, blank=True) class Meta(object): abstract = True app_label = "main"
class FutureScenario(Scenario): """ FutureScenarios represent and editing of a BuiltFormFeature table that is derived from an UrbanFootprint CanvasFeature table """ objects = GeoInheritanceManager() class Meta(object): permissions = ( ('view_futurescenario', 'View Future Scenario'), # Permission to merge data from another Scenario into this one ('merge_futurescenario', 'Merge Future Scenario'), ) app_label = 'main'
class StyleAttribute(models.Model): objects = GeoInheritanceManager() name = models.CharField(max_length=200, null=True, blank=True) key = models.CharField(max_length=200, null=True, blank=True) attribute = models.CharField(max_length=200, null=True, blank=True) style_type = models.CharField(max_length=40, null=True, blank=True) opacity = models.FloatField(default=1) style_value_contexts = PickledObjectField(default=lambda: []) visible = models.BooleanField(default=False) class Meta(object): app_label = 'main'
class LayerSelectionFeature(models.Model): objects = GeoInheritanceManager() # A class name is used to avoid circular dependency #layer_selection = models.ForeignKey(LayerSelection, null=False) #feature = models.ForeignKey(Feature, null=False) #layer_selection = None #feature = None medium = models.ForeignKey(Medium, null=True, default=None) def __unicode__(self): return "LayerSelection:{0}, Feature:{1}, Medium:{2}".format(self.layer_selection, self.feature, self.medium) class Meta(object): app_label = 'main' abstract = True
class ScagDmFarmlandDefinition(ClientFarmlandDefinition): objects = GeoInheritanceManager() farmland_description = models.CharField(max_length=100, null=True, blank=True) farmland_type = models.CharField(max_length=100, null=True, blank=True) farmland_code = models.CharField(max_length=10, null=True, blank=True) @property def label(self): return self.farmland_description class Meta(object): abstract = False app_label = 'main'
class CensusTract(Feature): tract = models.CharField(max_length=50, null=True) aland10 = models.CharField(max_length=50, null=True) awater10 = models.CharField(max_length=50, null=True) county = models.CharField(max_length=50, null=True) objects = GeoInheritanceManager() @property def label(self): return self.tract class Meta: abstract = True app_label = 'main'