class ScenarioSerializer(serializers.ModelSerializer): measures = PropertyMeasureSerializer(many=True) temporal_status = ChoiceField(choices=Scenario.TEMPORAL_STATUS_TYPES) class Meta: model = Scenario fields = '__all__'
class ColumnMappingProfileSerializer(serializers.ModelSerializer): profile_type = ChoiceField( choices=ColumnMappingProfile.COLUMN_MAPPING_PROFILE_TYPES, default=ColumnMappingProfile.NORMAL) class Meta: model = ColumnMappingProfile fields = '__all__' def validate_mappings(self, mappings): """if the profile is for BuildingSync, make sure it has valid mappings""" profile_types_dict = dict( ColumnMappingProfile.COLUMN_MAPPING_PROFILE_TYPES) bsync_profiles = [ profile_types_dict[ColumnMappingProfile.BUILDINGSYNC_DEFAULT], profile_types_dict[ColumnMappingProfile.BUILDINGSYNC_CUSTOM] ] profile_type = self.initial_data.get('profile_type') if profile_type is None or profile_type not in bsync_profiles: return mappings for mapping in mappings: if mapping.get('from_field_value') is None: raise serializers.ValidationError( f'All BuildingSync mappings must include "from_field_value": for mapping {mapping["from_field"]}' ) return mappings
class BuildingFileSerializer(serializers.ModelSerializer): file_type = ChoiceField(choices=BuildingFile.BUILDING_FILE_TYPES) organization_id = serializers.IntegerField(allow_null=True, read_only=True) class Meta: model = BuildingFile fields = '__all__'
class PropertyStateWritableSerializer(serializers.ModelSerializer): """ Used by PropertyViewAsState as a nested serializer Not sure why this is different than PropertyStateSerializer """ extra_data = serializers.JSONField(required=False) measures = PropertyMeasureSerializer(source='propertymeasure_set', many=True, read_only=True) scenarios = ScenarioSerializer(many=True, read_only=True) files = BuildingFileSerializer(source='building_files', many=True, read_only=True) analysis_state = ChoiceField(choices=PropertyState.ANALYSIS_STATE_TYPES) # to support the old state serializer method with the PROPERTY_STATE_FIELDS variables import_file_id = serializers.IntegerField(allow_null=True, read_only=True) organization_id = serializers.IntegerField() # support the pint objects gross_floor_area_pint = PintQuantitySerializerField(allow_null=True) conditioned_floor_area_pint = PintQuantitySerializerField(allow_null=True) occupied_floor_area_pint = PintQuantitySerializerField(allow_null=True) site_eui_pint = PintQuantitySerializerField(allow_null=True) source_eui_weather_normalized_pint = PintQuantitySerializerField( allow_null=True) site_eui_weather_normalized_pint = PintQuantitySerializerField( allow_null=True) source_eui_pint = PintQuantitySerializerField(allow_null=True) class Meta: fields = '__all__' model = PropertyState def to_representation(self, data): """Overwritten to handle time conversion""" result = super(PropertyStateWritableSerializer, self).to_representation(data) # for datetime to be isoformat and remove timezone data if data.generation_date: result['generation_date'] = make_naive( data.generation_date).isoformat() if data.recent_sale_date: result['recent_sale_date'] = make_naive( data.recent_sale_date).isoformat() if data.release_date: result['release_date'] = make_naive(data.release_date).isoformat() if data.analysis_start_time: result['analysis_start_time'] = make_naive( data.analysis_start_time).isoformat() if data.analysis_end_time: result['analysis_end_time'] = make_naive( data.analysis_end_time).isoformat() return result
class PropertyStateWritableSerializer(serializers.ModelSerializer): """ Used by PropertyViewAsState as a nested serializer This serializer is for use with the PropertyViewAsStateSerializer such that PropertyState can be created and updated through a single call to the associated PropertyViewViewSet. """ extra_data = serializers.JSONField(required=False) measures = PropertyMeasureSerializer(source='propertymeasure_set', many=True, read_only=True) scenarios = ScenarioSerializer(many=True, read_only=True) files = BuildingFileSerializer(source='building_files', many=True, read_only=True) analysis_state = ChoiceField(choices=PropertyState.ANALYSIS_STATE_TYPES, required=False) # to support the old state serializer method with the PROPERTY_STATE_FIELDS variables import_file_id = serializers.IntegerField(allow_null=True, read_only=True) organization_id = serializers.IntegerField(read_only=True) # support naive datetime objects # support naive datetime objects generation_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) recent_sale_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) release_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) analysis_start_time = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) analysis_end_time = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) # support the pint objects conditioned_floor_area = PintQuantitySerializerField(allow_null=True, required=False) gross_floor_area = PintQuantitySerializerField(allow_null=True, required=False) occupied_floor_area = PintQuantitySerializerField(allow_null=True, required=False) site_eui = PintQuantitySerializerField(allow_null=True, required=False) site_eui_modeled = PintQuantitySerializerField(allow_null=True, required=False) source_eui_weather_normalized = PintQuantitySerializerField( allow_null=True, required=False) source_eui = PintQuantitySerializerField(allow_null=True, required=False) source_eui_modeled = PintQuantitySerializerField(allow_null=True, required=False) site_eui_weather_normalized = PintQuantitySerializerField(allow_null=True, required=False) class Meta: fields = '__all__' model = PropertyState
class NoteSerializer(serializers.ModelSerializer): note_type = ChoiceField(choices=Note.NOTE_TYPES) organization_id = serializers.IntegerField(allow_null=True, read_only=True) property_view_id = serializers.IntegerField(allow_null=True, read_only=True) taxlot_view_id = serializers.IntegerField(allow_null=True, read_only=True) user_id = serializers.IntegerField(allow_null=True, read_only=True) class Meta: model = Note exclude = ('property_view', 'taxlot_view', 'user', 'organization')
class ColumnSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField('concat_name') organization_id = serializers.PrimaryKeyRelatedField(source='organization', read_only=True) unit_name = serializers.SlugRelatedField(source='unit', slug_field='unit_name', read_only=True) unit_type = serializers.SlugRelatedField(source='unit', slug_field='unit_type', read_only=True) merge_protection = ChoiceField(choices=Column.COLUMN_MERGE_PROTECTION, default=Column.COLUMN_MERGE_FAVOR_NEW) shared_field_type = ChoiceField(choices=Column.SHARED_FIELD_TYPES) class Meta: model = Column fields = ( 'id', 'name', 'organization_id', 'table_name', 'merge_protection', 'shared_field_type', 'column_name', 'is_extra_data', 'unit_name', 'unit_type', 'display_name', 'data_type', 'is_matching_criteria', 'geocoding_order', 'recognize_empty', 'comstock_mapping', ) def concat_name(self, obj): """ set the name of the column which is a special field because it can take on a relationship with the table_name and have an _extra associated with it """ return '%s_%s' % (obj.column_name, obj.id)
class PropertyMeasureSerializer(serializers.HyperlinkedModelSerializer): id = serializers.ReadOnlyField(source='measure.id') measure_id = serializers.SerializerMethodField('measure_id_name') name = serializers.ReadOnlyField(source='measure.name') display_name = serializers.ReadOnlyField(source='measure.display_name') category = serializers.ReadOnlyField(source='measure.category') category_display_name = serializers.ReadOnlyField( source='measure.category_display_name') implementation_status = ChoiceField( choices=PropertyMeasure.IMPLEMENTATION_TYPES) application_scale = ChoiceField( choices=PropertyMeasure.APPLICATION_SCALE_TYPES) category_affected = ChoiceField( choices=PropertyMeasure.CATEGORY_AFFECTED_TYPE) class Meta: model = PropertyMeasure fields = ( 'id', 'measure_id', 'category', 'name', 'category_display_name', 'display_name', 'category_affected', 'application_scale', 'recommended', 'implementation_status', 'cost_mv', 'description', 'cost_total_first', 'cost_installation', 'cost_material', 'cost_capital_replacement', 'cost_residual_value', ) def measure_id_name(self, obj): return "{}.{}".format(obj.measure.category, obj.measure.name)
class PropertyStateSerializer(serializers.ModelSerializer): extra_data = serializers.JSONField(required=False) measures = PropertyMeasureSerializer(source='propertymeasure_set', many=True, read_only=True) scenarios = ScenarioSerializer(many=True, read_only=True) files = BuildingFileSerializer(source='building_files', many=True, read_only=True) analysis_state = ChoiceField(choices=PropertyState.ANALYSIS_STATE_TYPES) # support the pint objects conditioned_floor_area = PintQuantitySerializerField(allow_null=True) gross_floor_area = PintQuantitySerializerField(allow_null=True) occupied_floor_area = PintQuantitySerializerField(allow_null=True) site_eui = PintQuantitySerializerField(allow_null=True) site_eui_modeled = PintQuantitySerializerField(allow_null=True) source_eui_weather_normalized = PintQuantitySerializerField( allow_null=True) source_eui = PintQuantitySerializerField(allow_null=True) source_eui_modeled = PintQuantitySerializerField(allow_null=True) site_eui_weather_normalized = PintQuantitySerializerField(allow_null=True) # support naive datetime objects generation_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) recent_sale_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) release_date = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) analysis_start_time = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) analysis_end_time = serializers.DateTimeField('%Y-%m-%dT%H:%M:%S', allow_null=True) # to support the old state serializer method with the PROPERTY_STATE_FIELDS variables import_file_id = serializers.IntegerField(allow_null=True, read_only=True) organization_id = serializers.IntegerField() class Meta: model = PropertyState fields = '__all__' extra_kwargs = {'organization': {'read_only': True}} def __init__(self, instance=None, data=empty, all_extra_data_columns=None, show_columns=None, **kwargs): """ If show_columns is passed, then all_extra_data_columns is not needed since the extra_data columns are embedded in the show_columns. TODO: remove the use of all_extra_data_columns. :param instance: instance to serialize :param data: initial data :param all_extra_data_columns: :param show_columns: dict of list, Which columns to show in the form of c['fields']=[] and c['extra_data']. """ if show_columns is not None: self.all_extra_data_columns = show_columns['extra_data'] else: self.all_extra_data_columns = all_extra_data_columns super().__init__(instance=instance, data=data, **kwargs) # remove the fields to display based on the show_columns list. if show_columns is not None: for field_name in set(self.fields) - set(show_columns['fields']): self.fields.pop(field_name) def to_representation(self, data): """Overwritten to handle time conversion and extra_data null fields""" result = super().to_representation(data) # Prepopulate the extra_data columns with a default of None so that they will appear in the result # This will also handle the passing of the show_columns extra data list. If the show_columns isn't # requiring a column, then it won't show up here. if self.all_extra_data_columns and data.extra_data: prepopulated_extra_data = { col_name: data.extra_data.get(col_name, None) for col_name in self.all_extra_data_columns } result['extra_data'] = prepopulated_extra_data return result
class ColumnListSettingSerializer(serializers.ModelSerializer): columns = ColumnListSettingColumnSerializer( source="columnlistsettingcolumn_set", read_only=True, many=True) settings_location = ChoiceField( choices=ColumnListSetting.VIEW_LOCATION_TYPES) inventory_type = ChoiceField( choices=ColumnListSetting.VIEW_LIST_INVENTORY_TYPE) class Meta: model = ColumnListSetting fields = ('id', 'name', 'settings_location', 'inventory_type', 'columns') def update(self, instance, validated_data): # remove the relationships -- to be added again in next step ColumnListSettingColumn.objects.filter( column_list_setting_id=instance.id).delete() for column in self.initial_data.get("columns", []): column_id = column.get("id") order = column.get("order") pinned = column.get("pinned") ColumnListSettingColumn(column_list_setting=instance, column_id=column_id, pinned=pinned, order=order).save() instance.__dict__.update(**validated_data) instance.save() return instance def create(self, validated_data): cls = ColumnListSetting.objects.create(**validated_data) if "columns" in self.initial_data: for column in self.initial_data.get("columns", []): # At this point the column will exist for the organization based on the validation # step column_id = column.get("id") order = column.get("order") pinned = column.get("pinned") ColumnListSettingColumn(column_list_setting=cls, column_id=column_id, pinned=pinned, order=order).save() cls.save() return cls def validate(self, data): # run some custom validation on the Columns data to make sure that the columns exist are # part of the org if "columns" in self.initial_data: request = self.context.get('request', None) # Org ID is in the request param org = Organization.objects.get( id=request.query_params['organization_id']) for column in self.initial_data.get("columns", []): # note that the org is the user's existing org, not the parent org! if not Column.objects.filter(pk=column.get("id"), organization_id=org.pk).exists(): raise ValidationError( 'Column does not exist for organization, column id: %s' % column.get("id")) return super().validate(data)
class PropertyStateSerializer(serializers.ModelSerializer): extra_data = serializers.JSONField(required=False) measures = PropertyMeasureSerializer(source='propertymeasure_set', many=True, read_only=True) scenarios = ScenarioSerializer(many=True, read_only=True) files = BuildingFileSerializer(source='building_files', many=True, read_only=True) analysis_state = ChoiceField(choices=PropertyState.ANALYSIS_STATE_TYPES) # support the pint objects conditioned_floor_area = PintQuantitySerializerField(allow_null=True) gross_floor_area = PintQuantitySerializerField(allow_null=True) occupied_floor_area = PintQuantitySerializerField(allow_null=True) site_eui = PintQuantitySerializerField(allow_null=True) site_eui_modeled = PintQuantitySerializerField(allow_null=True) source_eui_weather_normalized = PintQuantitySerializerField( allow_null=True) source_eui = PintQuantitySerializerField(allow_null=True) source_eui_modeled = PintQuantitySerializerField(allow_null=True) site_eui_weather_normalized = PintQuantitySerializerField(allow_null=True) # to support the old state serializer method with the PROPERTY_STATE_FIELDS variables import_file_id = serializers.IntegerField(allow_null=True, read_only=True) organization_id = serializers.IntegerField() class Meta: model = PropertyState fields = '__all__' extra_kwargs = {'organization': {'read_only': True}} def __init__(self, instance=None, data=empty, all_extra_data_columns=None, **kwargs): """Override __init__ for the optional all_extra_data_columns argument""" self.all_extra_data_columns = all_extra_data_columns super(PropertyStateSerializer, self).__init__(instance=instance, data=data, **kwargs) def to_representation(self, data): """Overwritten to handle time conversion and extra_data null fields""" result = super(PropertyStateSerializer, self).to_representation(data) # Prepopulate the extra_data columns with a default of None so that they will appear in the result if self.all_extra_data_columns and data.extra_data: prepopulated_extra_data = { col_name: data.extra_data.get(col_name, None) for col_name in self.all_extra_data_columns } result['extra_data'] = prepopulated_extra_data # for datetime to be isoformat and remove timezone data if data.generation_date: result['generation_date'] = make_naive( data.generation_date).isoformat() if data.recent_sale_date: result['recent_sale_date'] = make_naive( data.recent_sale_date).isoformat() if data.release_date: result['release_date'] = make_naive(data.release_date).isoformat() if data.analysis_start_time: result['analysis_start_time'] = make_naive( data.analysis_start_time).isoformat() if data.analysis_end_time: result['analysis_end_time'] = make_naive( data.analysis_end_time).isoformat() return result
class ColumnListProfileSerializer(serializers.ModelSerializer): columns = ColumnListProfileColumnSerializer( source='columnlistprofilecolumn_set', many=True) profile_location = ChoiceField(choices=VIEW_LOCATION_TYPES) inventory_type = ChoiceField(choices=VIEW_LIST_INVENTORY_TYPE) class Meta: model = ColumnListProfile fields = ('id', 'name', 'profile_location', 'inventory_type', 'columns') def update(self, instance, validated_data): # remove the relationships -- to be added again in next step ColumnListProfileColumn.objects.filter( column_list_profile_id=instance.id).delete() for column in self.initial_data.get('columns', []): column_id = column.get('id') order = column.get('order') pinned = column.get('pinned') ColumnListProfileColumn(column_list_profile=instance, column_id=column_id, pinned=pinned, order=order).save() instance.__dict__.update(**validated_data) instance.save() return instance def create(self, validated_data): # Remove *reformatted* ColumnListSettingColumn data, use unformatted initial_data later. del validated_data['columnlistprofilecolumn_set'] # Add the already-validated organization_id validated_data['organization_id'] = self.context.get( 'request', None).query_params['organization_id'] cls = ColumnListProfile.objects.create(**validated_data) if 'columns' in self.initial_data: for column in self.initial_data.get('columns', []): # At this point the column will exist for the organization based on the validation # step column_id = column.get('id') order = column.get('order') pinned = column.get('pinned') ColumnListProfileColumn(column_list_profile=cls, column_id=column_id, pinned=pinned, order=order).save() cls.save() return cls def validate(self, data): # run some custom validation on the Columns data to make sure that the columns exist are # part of the org if 'columns' in self.initial_data: request = self.context.get('request', None) # Org ID is in the request param org = Organization.objects.get( id=request.query_params['organization_id']) for column in self.initial_data.get('columns', []): # note that the org is the user's existing org, not the parent org! if not Column.objects.filter(pk=column.get('id'), organization_id=org.pk).exists(): raise ValidationError( "Column does not exist for organization, column id: %s" % column.get('id')) return super().validate(data)