Skip to content

Instantly share code, notes, and snippets.

@jfeldstein
Created March 31, 2022 22:11
Show Gist options
  • Save jfeldstein/d2ac31606610d63877b5e908108019b0 to your computer and use it in GitHub Desktop.
Save jfeldstein/d2ac31606610d63877b5e908108019b0 to your computer and use it in GitHub Desktop.
Spec for Geography CRUD tool
class Geographies(models.Model):
id = models.BigIntegerField(db_column="geo_id", primary_key=True, null=False)
name = models.CharField(db_column="geo_name", max_length=256)
slug = models.CharField(db_column="geo_slug", max_length=200)
latitude = models.FloatField(db_column="geo_centroid_latitude")
longitude = models.FloatField(db_column="geo_centroid_longitude")
update_date_time = models.DateTimeField()
@property
def defaultMap(self):
return {
"longitude": self.longitude,
"latitude": self.latitude,
"zoom": 13
}
@property
def filterSet(self):
return [{
"group_name": group_name,
"filters": [f for f in filters],
} for (group_name, filters) in self.grouped_filters]
@property
def grouped_filters(self):
return groupby(self.filters.active(), lambda f: f.group_name)
class Meta:
managed = True
db_table = 'geographies'
class params:
db = 'blocmaps_db'
class GeographyFilters(models.Model):
BUILDING_TYPE = 'buildings_geographies__building_subtype'
YEAR_BUILT = 'year_built'
EE_POTENTIAL_SCORE = 'ee_potential_score'
EJ_SCORE = 'ej_score'
ASHP_FEASIBILITY_SCORE = 'ashp_feasibility_score'
FIELD_NAME_CHOICES = [
(BUILDING_TYPE, 'Building Type'),
(YEAR_BUILT, 'Year Built'),
(EE_POTENTIAL_SCORE, 'EE Potential Score'),
(EJ_SCORE, 'EJ Score'),
(ASHP_FEASIBILITY_SCORE, 'ASHP Feasibility Score'),
]
id = models.BigIntegerField(db_column="geo_filter_id", primary_key=True, null=False)
geography = models.ForeignKey('Geographies', related_name='filters', on_delete=models.CASCADE, null=False,
db_index=False, to_field='id', db_column='geo_id')
field_name = models.CharField(choices=FIELD_NAME_CHOICES, max_length=200, blank=False, db_column="filter_name")
group_name = models.CharField(max_length=200)
display_name = models.CharField(max_length=200, blank=False, db_column="filter_display_name")
action_description = models.CharField(max_length=500, db_column="filter_action_description")
tooltip = models.CharField(max_length=500, db_column="filter_tooltip")
is_active = models.BooleanField(db_column="filter_active")
class QuerySet(QuerySet):
def active(self, *args, **kwargs):
return self.filter(is_active=True, *args, **kwargs)
objects = PassManager.from_queryset(QuerySet)()
class Meta:
managed = True
db_table = 'geography_filters'
ordering = ('group_name', )
class params:
db = 'blocmaps_db'
class FilterOptions(models.Model):
IN = 'IN'
RANGE = 'RANGE'
LESS_THAN = 'LESS_THAN'
GREATER_THAN = 'GREATER_THAN'
OPERATOR_CHOICES = [
(IN, 'IN'),
(RANGE, 'RANGE'),
(LESS_THAN, 'LESS_THAN'),
(GREATER_THAN, 'GREATER_THAN')
]
id = models.BigIntegerField(db_column="filter_option_id", primary_key=True, null=False)
filter = models.ForeignKey('GeographyFilters', related_name='options', on_delete=models.CASCADE, null=False,
db_index=False, to_field='id', db_column='geo_filter_id')
display_name = models.CharField(max_length=200, blank=False, db_column="option_display_name")
operator = models.CharField(choices=OPERATOR_CHOICES, max_length=255, blank=False, db_column="option_operator")
values = models.CharField(max_length=255, blank=False, db_column="option_values")
sort_order = models.IntegerField(db_column="sort_order")
class Meta:
managed = True
db_table = 'filter_options'
ordering = ('sort_order', )
class params:
db = 'blocmaps_db'
  • Admin should be able to modify the geography's core attributes, thereby making it public
    • Flow: Admin has to fill in display_name and slug, then submit, then confirm latitude and longitude by submitting again.
      • Validation: slug and display_name must either both be filled, or neither. Admin cannot fill in only one or the other.
      • Admin should not see latitude, longitude, nor zoom if slug or display_name are empty.
      • Admin should see latitude, longitude, and zoom if slug and display_name are set.
        • When latitude and longitude are shown, system should show a small thumbnail map to confirm the map configuration is accurate
      • Existing behavior of the API:
        • If slug is NULL, the geograhy will not be exposed publicly
        • If slug is provided, the geography is accessible at /geography/:slug
      • New Behavior:
        • If latitude and longitude are empty when display_name is updated, system should attempt to geolocate the city using the entered name and fill those fields
  • Admin should have to enable filters displayed for each Geography
    • Flow: After filling in display_name and slug, the filters config is also visible and editable
      • Admin should not see filters config if slug or display_name are empty
      • Admin should see filters config if slug and display_name are present
      • Filters config consists of ability to add, modify, or remove FilterGroups in a list.
      • Each FilterGroup has the following attributes the Admin must configure. All Required:
        • group_name - Text shown on the dropdown in the filters tab
          • Single-line text input
          • Required
        • Each FilterGroup has a sublist of Filters, and the Admin can Add Remove or Update items in the list.
          • At least one filter is required
          • Each Filter has the following attributes the Admin must configure:
            • field_name - what data is queried to apply this Filter
              • Required
              • Dropdown, showing these options (and corresponding values):
                • Building Type (buildings_geographies__building_subtype)
                • Year Built (year_built)
                • Energy Usage Intensity (eui)
                • Heating Fuel Type (fuel_type)
                • Heat Pump Feasibility (ashp_feasibility_score)
                • Energy Efficiency Improvement Potential (ee_potential_score)
                • EJ Need (ej_score)
                • Media Family Income (tract_income_level)
            • tooltip - Text shown when the (i) icon is hovered
              • Single-line text input
              • NULL if left blank
            • Options -
              • Each filter has a sublist of options, and the Admin can Add Remove or Edit items in the list
              • At least one option is required
              • Each Option has the following attributes the Admin must configure. All required:
                • display_name - what the user sees when selecting this option
                  • Single-line text input
                • operator - how the Filter queries the field, given the value
                  • Dropdown:
                    • "IN" ("IN")
                    • "RANGE" ("RANGE")
                    • "LESS_THAN" ("LESS_THAN")
                    • "GREATER_THAN" ("GREATER_THAN")
                    • Valid values for operator depend on the field_name on the Filter:
                    • The following field_names are considered numeric and cannot use the "IN" operator
                    • ej_score
                    • ashp_feasibility_score
                    • year_built
                    • The following field_names are considered categorical and must only use the "IN" operator
                    • buildings_geographies__building_subtype
                    • year_built
                    • eui
                    • ee_potential_score
                    • tract_income_level
                    • fuel_type
                • value
                  • Single-line text input
                  • Valid values for value depend on the operator on the option:
                    • "IN" can be any string
                    • "RANGE" must be two, comma-separated integers (eg "50,100")
                    • "LESS_THAN" must be an integer
                    • "GREATER_THAN" must be an integer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment