def green_infrastructure(request, instance):
    json_data = json_from_request(request)
    new_data = {}
    increment_universal_rev = False
    for identifier, value in json_data.iteritems():
        model, field_name = dotted_split(identifier, 2, maxsplit=1)
        if field_name.startswith('config.map_feature_types') or \
           field_name.startswith('config.map_feature_config'):
            if not instance.feature_enabled('green_infrastructure'):
                raise PermissionDenied("The Green Infrastructure module is "
                                       "not enabled for this tree map")
            increment_universal_rev = True
        if field_name.startswith('config.map_feature_types'):
            __, __, mft_name = dotted_split(field_name, 3, maxsplit=2)
            if value:
                instance.add_map_feature_types([mft_name])
            else:
                instance.remove_map_feature_types([mft_name])
        else:
            new_data[identifier] = value

    error_dict = {}
    _validate_and_set_individual_values(new_data, instance, error_dict)
    _cross_validate_values(new_data, instance, error_dict)
    if error_dict:
        raise ValidationError(package_field_errors('instance',
                              ValidationError(error_dict)))
    if increment_universal_rev:
        instance.update_universal_rev()
    instance.save()
    return {'ok': True}
def green_infrastructure(request, instance):
    json_data = json_from_request(request)
    new_data = {}
    increment_universal_rev = False
    for identifier, value in json_data.iteritems():
        model, field_name = dotted_split(identifier, 2, maxsplit=1)
        if field_name.startswith('config.map_feature_types') or \
           field_name.startswith('config.map_feature_config'):
            if not instance.feature_enabled('green_infrastructure'):
                raise PermissionDenied("The Green Infrastructure module is "
                                       "not enabled for this tree map")
            increment_universal_rev = True
        if field_name.startswith('config.map_feature_types'):
            __, __, mft_name = dotted_split(field_name, 3, maxsplit=2)
            if value:
                instance.add_map_feature_types([mft_name])
            else:
                instance.remove_map_feature_types([mft_name])
        else:
            new_data[identifier] = value

    error_dict = {}
    _validate_and_set_individual_values(new_data, instance, error_dict)
    _cross_validate_values(new_data, instance, error_dict)
    if error_dict:
        raise ValidationError(
            package_field_errors('instance', ValidationError(error_dict)))
    if increment_universal_rev:
        instance.update_universal_rev()
    instance.save()
    return {'ok': True}
def _validate_and_set_individual_values(json_data, instance, error_dict):
    errors = None
    INVALID_KEY_MESSAGE = _("An invalid key was sent in the request")
    for identifier, value in json_data.iteritems():
        if not '.' in identifier:
            error_dict[identifier] = [INVALID_KEY_MESSAGE]
        __, field_name = dotted_split(identifier, 2, maxsplit=1)

        if not identifier.startswith('instance.config.'):
            error_dict[field_name] = [INVALID_KEY_MESSAGE]
            continue

        if field_name == 'config.annual_rainfall_inches':
            errors = _annual_rainfall_validator(value)
            if errors is None:
                _set_annual_rainfall(value, instance)
        elif field_name.startswith('config.map_feature_config'):
            errors = _map_feature_config_validator(field_name, value, instance)
            if errors is None:
                _set_map_feature_config(field_name, value, instance)
        elif field_name.startswith('config.terms'):
            errors = _terminology_validator(field_name, value, instance)
            if errors is None:
                set_attr_on_json_field(instance, field_name, value)
        else:
            errors = [INVALID_KEY_MESSAGE]

        if errors is not None:
            error_dict[field_name] = errors
Example #4
0
def _update_instance_fields(json_data, instance, validation_fn=None):
    error_dict = {}
    for identifier, value in json_data.iteritems():
        model, field_name = dotted_split(identifier, 2, maxsplit=1)

        obj = instance

        if validation_fn:
            errors = validation_fn(field_name, value, model)
            if errors is not None:
                error_dict[field_name] = errors

        if is_json_field_reference(field_name):
            set_attr_on_json_field(obj, field_name, value)
        else:
            setattr(obj, field_name, value)

    if error_dict:
        validation_error = ValidationError(error_dict)
    else:
        try:
            validate_is_public(instance)
            instance.save()
            return {'ok': True}
        except ValidationError, ve:
            validation_error = ve
Example #5
0
    def validate_and_save_field_perm(role, field_perm):
        for model_field_name, perm_type in field_perm.iteritems():
            model_name, field_name = dotted_split(model_field_name, 2)
            validate_model_name(model_name, valid_field_model_names)

            field_perm = field_perms.get((role, model_field_name), None)

            create = field_perm is None
            if create:
                field_perm = FieldPermission.objects.create(
                    field_name=field_name,
                    model_name=model_name,
                    role=role,
                    instance=role.instance)

            perm_type = int(perm_type)
            if create or field_perm.permission_level != perm_type:
                valid_levels = [level
                                for __, level
                                in options_for_permission(field_perm)]

                if perm_type in valid_levels:
                    field_perm.permission_level = perm_type
                    field_perm.save()
                else:
                    raise Exception('Invalid field type '
                                    '(allowed %s, given %s)' %
                                    (valid_levels, perm_type))

                notifications = instance.config.get('udf_notifications', [])
                if field_perm.full_name in notifications:
                    remove_udf_notification(instance, field_perm.full_name)
def _validate_and_set_individual_values(json_data, instance, error_dict):
    errors = None
    INVALID_KEY_MESSAGE = _("An invalid key was sent in the request")
    for identifier, value in json_data.iteritems():
        if not '.' in identifier:
            error_dict[identifier] = [INVALID_KEY_MESSAGE]
        __, field_name = dotted_split(identifier, 2, maxsplit=1)

        if not identifier.startswith('instance.config.'):
            error_dict[field_name] = [INVALID_KEY_MESSAGE]
            continue

        if field_name == 'config.annual_rainfall_inches':
            errors = _annual_rainfall_validator(value)
            if errors is None:
                _set_annual_rainfall(value, instance)
        elif field_name.startswith('config.map_feature_config'):
            errors = _map_feature_config_validator(field_name, value,
                                                   instance)
            if errors is None:
                _set_map_feature_config(field_name, value, instance)
        elif field_name.startswith('config.terms'):
            errors = _terminology_validator(field_name, value, instance)
            if errors is None:
                set_attr_on_json_field(instance, field_name, value)
        else:
            errors = [INVALID_KEY_MESSAGE]

        if errors is not None:
            error_dict[field_name] = errors
Example #7
0
    def test_annual_rainfall_unit_conversion(self):
        rainfall_unit_key, rainfall_unit = get_value_display_attr(
            self.instance, 'greenInfrastructure', 'rainfall', 'units')
        self.assertEqual(rainfall_unit, 'in')
        __, __, unit_key = dotted_split(rainfall_unit_key, 3, maxsplit=2)

        self.assertEqual(rainfall_unit, 'in')

        config_key = 'annual_rainfall_inches'
        request_key = 'instance.config.annual_rainfall_inches'
        updates = {request_key: 10}
        json_updates = json.dumps(updates)
        request = make_request(method='PUT',
                               body=json_updates,
                               user=self.commander)

        green_infrastructure(request, self.instance)

        self.assertEqual(self.instance.config[config_key], 10.0)

        self.instance.config[unit_key] = 'cm'

        config_key = 'annual_rainfall_inches'
        request_key = 'instance.config.{}'.format(config_key)
        updates = {request_key: 25.4}
        json_updates = json.dumps(updates)
        request = make_request(method='PUT',
                               body=json_updates,
                               user=self.commander)

        green_infrastructure(request, self.instance)

        self.assertEqual(self.instance.config[config_key], 10.0)
Example #8
0
def _update_instance_fields(json_data, instance, validation_fn=None,
                            should_update_universal_rev=False):
    error_dict = {}
    for identifier, value in json_data.iteritems():
        model, field_name = dotted_split(identifier, 2, maxsplit=1)

        obj = instance

        if validation_fn:
            errors = validation_fn(field_name, value, model)
            if errors is not None:
                error_dict[field_name] = errors

        if is_json_field_reference(field_name):
            set_attr_on_json_field(obj, field_name, value)
        else:
            setattr(obj, field_name, value)

    if error_dict:
        validation_error = ValidationError(error_dict)
    else:
        try:
            validate_is_public(instance)
            instance.save()
            if should_update_universal_rev:
                instance.update_universal_rev()
            return {'ok': True}
        except ValidationError, ve:
            validation_error = ve
Example #9
0
def update_benefits(request, instance):
    conv = instance.eco_benefits_conversion or _get_default_conversions()

    valid_fields = ('currency_symbol', 'electricity_kwh_to_currency',
                    'natural_gas_kbtu_to_currency', 'h20_gal_to_currency',
                    'co2_lb_to_currency', 'o3_lb_to_currency',
                    'nox_lb_to_currency', 'pm10_lb_to_currency',
                    'sox_lb_to_currency', 'voc_lb_to_currency')

    valid_fields = [
        "benefitCurrencyConversion." + field for field in valid_fields
    ]

    updated_values = json_from_request(request)

    for field, value in updated_values.iteritems():
        if field in valid_fields:
            field_part = dotted_split(field, 2)[1]
            setattr(conv, field_part, value)
        else:
            raise Exception(
                'invalid field specified %s for benefit conversion' % field)

    try:
        conv.save()
    except ValidationError as e:
        raise ValidationError(
            package_field_errors('benefitCurrencyConversion', e))

    instance.eco_benefits_conversion = conv
    instance.update_eco_rev()
    instance.save()

    return {'ok': True}
Example #10
0
def identifier_model_name(identifier):
    """
    Takes an identifier like "model.field" and returns the model's display name
    """
    object_name, __ = dotted_split(identifier, 2, maxsplit=1)

    return display_name(to_model_name(object_name))
Example #11
0
    def validate_and_save_field_perm(role, field_perm):
        for model_field_name, perm_type in field_perm.iteritems():
            model_name, field_name = dotted_split(model_field_name, 2)
            validate_model_name(model_name, valid_field_model_names)

            field_perm = field_perms.get((role, model_field_name), None)

            create = field_perm is None
            if create:
                field_perm = FieldPermission.objects.create(
                    field_name=field_name,
                    model_name=model_name,
                    role=role,
                    instance=role.instance)

            perm_type = int(perm_type)
            if create or field_perm.permission_level != perm_type:
                valid_levels = [
                    level for __, level in options_for_permission(field_perm)
                ]

                if perm_type in valid_levels:
                    field_perm.permission_level = perm_type
                    field_perm.save()
                else:
                    raise Exception('Invalid field type '
                                    '(allowed %s, given %s)' %
                                    (valid_levels, perm_type))

                notifications = instance.config.get('udf_notifications', [])
                if field_perm.full_name in notifications:
                    remove_udf_notification(instance, field_perm.full_name)
Example #12
0
def identifier_model_name(identifier):
    """
    Takes an identifier like "model.field" and returns the model's display name
    """
    object_name, __ = dotted_split(identifier, 2, maxsplit=1)

    return display_name(to_model_name(object_name))
Example #13
0
def convert_filter_units(instance, filter_dict):
    """
    Convert the values in a filter dictionary from display units to database
    units. Mutates the `filter_dict` argument and returns it.
    """
    for field_name, value in filter_dict.iteritems():
        if field_name not in ['tree.diameter', 'tree.height',
                              'tree.canopy_height', 'plot.width',
                              'plot.length', 'bioswale.drainage_area',
                              'rainBarrel.capacity',
                              'rainGarden.drainage_area']:
            continue

        model_name, field = dotted_split(field_name, 2, maxsplit=1)

        if isinstance(value, dict):
            factor = 1 / storage_to_instance_units_factor(instance,
                                                          model_name,
                                                          field)
            for k in ['MIN', 'MAX', 'IS']:
                if k in value:
                    try:
                        if isinstance(value[k], dict):
                            float_val = float(value[k]['VALUE'])
                            value[k]['VALUE'] = factor * float_val
                        else:
                            float_val = float(value[k])
                            value[k] = factor * float_val
                    except ValueError:
                        # If the value is non-numeric we can just leave is as
                        # is and let the filter logic handle it.
                        pass
    return filter_dict
Example #14
0
def _split_key(key):
    format_string = 'Keys must be in the form of "model.field", not "%s"'

    return dotted_split(key,
                        2,
                        failure_format_string=format_string,
                        cls=ParseException)
Example #15
0
def _get_json_as_dotdict(model, field_path):
    field, json_path = dotted_split(field_path, 2, maxsplit=1)
    if not hasattr(model, field):
        raise ValueError('Field %s not found' % field_path)
    dotdict = getattr(model, field)
    if type(dotdict) is not DotDict:
        raise ValueError('Field %s does not contain JSON' % field_path)
    return dotdict, json_path
def _set_map_feature_config(field_name, value, instance):
    __, __, model_name, setting = dotted_split(field_name, 4, maxsplit=3)
    Classes = _get_replaceable_models(instance)
    Cls = next(Cls for Cls in Classes if Cls.__name__ == model_name)
    if setting == 'diversion_rate':
        value = float(value)
    elif setting == 'should_show_eco':
        value = bool(value)
    Cls.set_config_property(instance, setting, value, save=False)
def _set_map_feature_config(field_name, value, instance):
    __, __, model_name, setting = dotted_split(field_name, 4, maxsplit=3)
    Classes = _get_replaceable_models(instance)
    Cls = next(Cls for Cls in Classes if Cls.__name__ == model_name)
    if setting == 'diversion_rate':
        value = float(value)
    elif setting == 'should_show_eco':
        value = bool(value)
    Cls.set_config_property(instance, setting, value, save=False)
def _cross_validate_values(json_data, instance, error_dict):
    errors = None
    for identifier, value in json_data.iteritems():
        __, field_name = dotted_split(identifier, 2, maxsplit=1)
        if field_name in error_dict:
            continue

        if field_name.startswith('config.map_feature_config'):
            errors = _map_feature_cross_validator(field_name, value, instance)

        if errors is not None:
            error_dict[field_name] = errors
def _cross_validate_values(json_data, instance, error_dict):
    errors = None
    for identifier, value in json_data.iteritems():
        __, field_name = dotted_split(identifier, 2, maxsplit=1)
        if field_name in error_dict:
            continue

        if field_name.startswith('config.map_feature_config'):
            errors = _map_feature_cross_validator(field_name, value, instance)

        if errors is not None:
            error_dict[field_name] = errors
Example #20
0
        def get_search_query_value(column, display, identifier,
                                   related_class, search_query):
            if not search_query:
                return ''
            search_map = json.loads(search_query) or {}
            model_name, field_name = tuple(dotted_split(
                identifier, 2, maxsplit=1))
            search_field = '{}.{}'.format(model_name, column)
            pred = search_map.get(search_field)
            if not pred:
                return ''

            query_value = pred[FOREIGN_KEY_PREDICATE]
            related_model = related_class.objects.get(id=query_value)
            return getattr(related_model, display)
def _terminology_validator(field_name, value, instance):
    acceptable_terms = REPLACEABLE_TERMS.keys() + [
        Cls.__name__ for Cls in _get_replaceable_models(instance)
    ]

    __, terms, term, form = dotted_split(field_name, 4, maxsplit=3)
    field_name_valid = (terms == 'terms' and term in acceptable_terms
                        and form in ('singular', 'plural'))
    if not field_name_valid:
        return [_("An invalid key was sent in the request")]

    if term == 'Resource' and len(value) > 20:
        return [_('Please limit replacement text to 20 characters.')]

    return None
Example #22
0
        def get_search_query_value(column, display, identifier,
                                   related_class, search_query):
            if not search_query:
                return ''
            search_map = json.loads(search_query) or {}
            model_name, field_name = tuple(dotted_split(
                identifier, 2, maxsplit=1))
            search_field = '{}.{}'.format(model_name, column)
            pred = search_map.get(search_field)
            if not pred:
                return ''

            query_value = pred[FOREIGN_KEY_PREDICATE]
            related_model = related_class.objects.get(id=query_value)
            return getattr(related_model, display)
def _terminology_validator(field_name, value, instance):
    acceptable_terms = REPLACEABLE_TERMS.keys() + [
        Cls.__name__ for Cls in _get_replaceable_models(instance)]

    __, terms, term, form = dotted_split(field_name, 4, maxsplit=3)
    field_name_valid = (terms == 'terms' and
                        term in acceptable_terms and
                        form in ('singular', 'plural'))
    if not field_name_valid:
        return [_("An invalid key was sent in the request")]

    if term == 'Resource' and len(value) > 20:
        return [_('Please limit replacement text to 20 characters.')]

    return None
Example #24
0
    def test_model_assignment(self):
        self.instance.add_map_feature_types(['Bioswale'])
        permissions = [
            'Plot.add_plot', 'Plot.delete_plot', 'Tree.add_tree',
            'Tree.delete_tree', 'TreePhoto.add_treephoto',
            'TreePhoto.delete_treephoto', 'Bioswale.add_bioswale',
            'Bioswale.delete_bioswale', 'MapFeaturePhoto.add_bioswalephoto',
            'MapFeaturePhoto.delete_bioswalephoto'
        ]

        self.request_updates(dict(zip(permissions, [True] * len(permissions))))

        for existing in permissions:
            __, codename = dotted_split(existing, 2, maxsplit=1)
            permission = Permission.objects.get(codename=codename)
            self.assert_assignment(permission, self.new_role)
def _map_feature_cross_validator(field_name, value, instance):
    __, __, model_name, setting = dotted_split(field_name, 4, maxsplit=3)
    Classes = _get_replaceable_models(instance)
    Cls = next(Cls for Cls in Classes if Cls.__name__ == model_name)
    config = Cls.get_config(instance)

    if setting == 'should_show_eco':
        value = config.get(setting)
        if value:
            rainfall_inches = instance.annual_rainfall_inches
            if rainfall_inches is None or rainfall_inches == '':
                return [_("Ecobenefits cannot be calculated unless "
                          "annual rainfall is given")]
            diversion_rate = config.get('diversion_rate')
            if diversion_rate is None or diversion_rate == '':
                return [_("Ecobenefits cannot be calculated unless "
                          "a runoff coefficient is given")]
Example #26
0
def _parse_predicate_key(key, mapping):
    format_string = 'Keys must be in the form of "model.field", not "%s"'
    model, field = dotted_split(key, 2,
                                failure_format_string=format_string,
                                cls=ParseException)

    if _is_udf(model):
        _, mapping_model, _ = model.split(':')
        field = 'id'
    else:
        mapping_model = model

    if mapping_model not in mapping:
        raise ParseException(
            'Valid models are: %s or a collection UDF, not "%s"' %
            (mapping.keys(), model))

    return model, mapping[mapping_model] + field
Example #27
0
 def validate_and_save_model_perm(role, model_perm):
     unassign = []
     for model_perm_name, should_be_assigned in model_perm.iteritems():
         model_name, codename = dotted_split(model_perm_name, 2)
         validate_model_name(model_name,
                             set(valid_perm_models_by_name.keys()))
         Model = valid_perm_models_by_name[model_name]
         permission = get_and_validate_permission(codename, Model)
         validate_permission_assignment(codename, should_be_assigned, Model)
         if should_be_assigned:
             RolePermissionModel.objects.get_or_create(
                 role=role, permission=permission)
         else:
             unassign.append({'role': role, 'permission': permission})
     if unassign:
         unassign_q = reduce(lambda q1, q2: q1 | q2,
                             [Q(**rpm) for rpm in unassign])
         RolePermissionModel.objects.filter(unassign_q).delete()
Example #28
0
def update_user(request, user):
    new_values = json_from_request(request) or {}
    for key in new_values:
        try:
            model, field = dotted_split(key, 2, cls=ValueError)
            if model != 'user':
                raise ValidationError(
                    'All fields should be prefixed with "user."')
            if field not in USER_PROFILE_FIELDS:
                raise ValidationError(field + ' is not an updatable field')
        except ValueError:
            raise ValidationError('All fields should be prefixed with "user."')
        setattr(user, field, new_values[key])
    try:
        user.save()
        return {"ok": True}
    except ValidationError as ve:
        raise ValidationError(package_field_errors('user', ve))
Example #29
0
def _parse_predicate_key(key, mapping):
    format_string = 'Keys must be in the form of "model.field", not "%s"'
    model, field = dotted_split(key, 2,
                                failure_format_string=format_string,
                                cls=ParseException)

    if _is_udf(model):
        __, mapping_model, __ = model.split(':')
        field = 'id'
    else:
        mapping_model = model

    if mapping_model not in mapping:
        raise ParseException(
            'Valid models are: %s or a collection UDF, not "%s"' %
            (mapping.keys(), model))

    return model, mapping[mapping_model] + field
Example #30
0
 def validate_and_save_model_perm(role, model_perm):
     unassign = []
     for model_perm_name, should_be_assigned in model_perm.iteritems():
         model_name, codename = dotted_split(model_perm_name, 2)
         validate_model_name(
             model_name, set(valid_perm_models_by_name.keys()))
         Model = valid_perm_models_by_name[model_name]
         permission = get_and_validate_permission(codename, Model)
         validate_permission_assignment(codename, should_be_assigned, Model)
         if should_be_assigned:
             RolePermissionModel.objects.get_or_create(
                 role=role, permission=permission)
         else:
             unassign.append({'role': role, 'permission': permission})
     if unassign:
         unassign_q = reduce(lambda q1, q2: q1 | q2,
                             [Q(**rpm) for rpm in unassign])
         RolePermissionModel.objects.filter(unassign_q).delete()
Example #31
0
def update_user(request, user):
    new_values = json_from_request(request) or {}
    for key in new_values:
        try:
            model, field = dotted_split(key, 2, cls=ValueError)
            if model != 'user':
                raise ValidationError(
                    'All fields should be prefixed with "user."')
            if field not in USER_PROFILE_FIELDS:
                raise ValidationError(field + ' is not an updatable field')
        except ValueError:
            raise ValidationError('All fields should be prefixed with "user."')
        setattr(user, field, new_values[key])
    try:
        user.save()
        return {"ok": True}
    except ValidationError as ve:
        raise ValidationError(package_field_errors('user', ve))
def _map_feature_config_validator(field_name, value, instance):
    acceptable_terms = [
        Cls.__name__ for Cls in _get_replaceable_models(instance)
    ]

    __, __, term, key = dotted_split(field_name, 4, maxsplit=3)
    field_name_valid = (term in acceptable_terms
                        and key in ('should_show_eco', 'diversion_rate'))
    if not field_name_valid:
        return [_("An invalid key was sent in the request")]

    plural = get_attr_from_json_field(instance,
                                      'config.terms.{}.plural'.format(term))

    if key == 'should_show_eco':
        if term == 'RainBarrel':
            return [
                _("Showing Ecobenefits is not applicable to {RainBarrels}").
                format(RainBarrels=plural)
            ]
    elif key == 'diversion_rate':
        if term == 'RainBarrel':
            return [
                _("The runoff coefficient is not applicable to {RainBarrels}").
                format(RainBarrels=plural)
            ]
        error_message = ("Please enter a number between 0 and 1 "
                         "for the runoff coefficient")

        if value is None or value == '':
            return [_(error_message)]

        try:
            float_value = float(value)
        except ValueError:
            return [_(error_message)]

        if not 0.0 <= float_value <= 1.0:
            return [_(error_message)]

    return None
Example #33
0
    def test_model_assignment(self):
        self.instance.add_map_feature_types(['Bioswale'])
        permissions = [
            'Plot.add_plot',
            'Plot.delete_plot',
            'Tree.add_tree',
            'Tree.delete_tree',
            'TreePhoto.add_treephoto',
            'TreePhoto.delete_treephoto',
            'Bioswale.add_bioswale',
            'Bioswale.delete_bioswale',
            'MapFeaturePhoto.add_bioswalephoto',
            'MapFeaturePhoto.delete_bioswalephoto']

        self.request_updates(
            dict(zip(permissions, [True] * len(permissions))))

        for existing in permissions:
            __, codename = dotted_split(existing, 2, maxsplit=1)
            permission = Permission.objects.get(codename=codename)
            self.assert_assignment(permission, self.new_role)
def _map_feature_cross_validator(field_name, value, instance):
    __, __, model_name, setting = dotted_split(field_name, 4, maxsplit=3)
    Classes = _get_replaceable_models(instance)
    Cls = next(Cls for Cls in Classes if Cls.__name__ == model_name)
    config = Cls.get_config(instance)

    if setting == 'should_show_eco':
        value = config.get(setting)
        if value:
            rainfall_inches = instance.annual_rainfall_inches
            if rainfall_inches is None or rainfall_inches == '':
                return [
                    _("Ecobenefits cannot be calculated unless "
                      "annual rainfall is given")
                ]
            diversion_rate = config.get('diversion_rate')
            if diversion_rate is None or diversion_rate == '':
                return [
                    _("Ecobenefits cannot be calculated unless "
                      "a runoff coefficient is given")
                ]
Example #35
0
def update_benefits(request, instance):
    conv = instance.eco_benefits_conversion or _get_default_conversions()

    valid_fields = ('currency_symbol',
                    'electricity_kwh_to_currency',
                    'natural_gas_kbtu_to_currency',
                    'h20_gal_to_currency',
                    'co2_lb_to_currency',
                    'o3_lb_to_currency',
                    'nox_lb_to_currency',
                    'pm10_lb_to_currency',
                    'sox_lb_to_currency',
                    'voc_lb_to_currency')

    valid_fields = ["benefitCurrencyConversion." + field
                    for field in valid_fields]

    updated_values = json_from_request(request)

    for field, value in updated_values.iteritems():
        if field in valid_fields:
            field_part = dotted_split(field, 2)[1]
            setattr(conv, field_part, value)
        else:
            raise Exception(
                'invalid field specified %s for benefit conversion' % field)

    try:
        conv.save()
    except ValidationError as e:
        raise ValidationError(
            package_field_errors('benefitCurrencyConversion', e))

    instance.eco_benefits_conversion = conv
    instance.update_eco_rev()
    instance.save()

    return {'ok': True}
def _map_feature_config_validator(field_name, value, instance):
    acceptable_terms = [
        Cls.__name__ for Cls in _get_replaceable_models(instance)]

    __, __, term, key = dotted_split(field_name, 4, maxsplit=3)
    field_name_valid = (term in acceptable_terms and
                        key in ('should_show_eco', 'diversion_rate'))
    if not field_name_valid:
        return [_("An invalid key was sent in the request")]

    plural = get_attr_from_json_field(instance, 'config.terms.{}.plural'
                                      .format(term))

    if key == 'should_show_eco':
        if term == 'RainBarrel':
            return [_("Showing Ecobenefits is not applicable to {RainBarrels}")
                    .format(RainBarrels=plural)]
    elif key == 'diversion_rate':
        if term == 'RainBarrel':
            return [_(
                "The runoff coefficient is not applicable to {RainBarrels}")
                .format(RainBarrels=plural)]
        error_message = ("Please enter a number between 0 and 1 "
                         "for the runoff coefficient")

        if value is None or value == '':
            return [_(error_message)]

        try:
            float_value = float(value)
        except ValueError:
            return [_(error_message)]

        if not 0.0 <= float_value <= 1.0:
            return [_(error_message)]

    return None
Example #37
0
def _split_key(key):
    format_string = 'Keys must be in the form of "model.field", not "%s"'

    return dotted_split(key, 2, failure_format_string=format_string,
                        cls=ParseException)
Example #38
0
def update_map_feature(request_dict, user, feature):
    """
    Update a map feature. Expects JSON in the request body to be:
    {'model.field', ...}

    Where model is either 'tree', 'plot', or another map feature type
    and field is any field on the model.
    UDF fields should be prefixed with 'udf:'.

    This method can be used to create a new map feature by passing in
    an empty MapFeature object (i.e. Plot(instance=instance))
    """
    feature_object_names = [
        to_object_name(ft) for ft in feature.instance.map_feature_types
    ]

    if isinstance(feature, Convertible):
        # We're going to always work in display units here
        feature.convert_to_display_units()

    def set_attr_on_model(model, attr, val):
        field_classname = \
            model._meta.get_field_by_name(attr)[0].__class__.__name__

        if field_classname.endswith('PointField'):
            srid = val.get('srid', 3857)
            val = Point(val['x'], val['y'], srid=srid)
            val.transform(3857)
        elif field_classname.endswith('MultiPolygonField'):
            srid = val.get('srid', 4326)
            val = MultiPolygon(Polygon(val['polygon'], srid=srid), srid=srid)
            val.transform(3857)

        if attr == 'mapfeature_ptr':
            if model.mapfeature_ptr_id != value:
                raise Exception('You may not change the mapfeature_ptr_id')
        elif attr == 'id':
            if val != model.pk:
                raise Exception("Can't update id attribute")
        elif attr.startswith('udf:'):
            udf_name = attr[4:]

            if udf_name in [
                    field.name for field in model.get_user_defined_fields()
            ]:
                model.udfs[udf_name] = val
            else:
                raise KeyError('Invalid UDF %s' % attr)
        elif attr in model.fields():
            model.apply_change(attr, val)
        else:
            raise Exception('Malformed request - invalid field %s' % attr)

    def save_and_return_errors(thing, user):
        try:
            if isinstance(thing, Convertible):
                thing.convert_to_database_units()

            thing.save_with_user(user)
            return {}
        except ValidationError as e:
            return package_field_errors(thing._model_name, e)

    tree = None

    rev_updates = ['universal_rev']
    old_geom = feature.geom
    for (identifier, value) in request_dict.iteritems():
        split_template = 'Malformed request - invalid field %s'
        object_name, field = dotted_split(identifier,
                                          2,
                                          failure_format_string=split_template)
        if (object_name not in feature_object_names + ['tree']):
            raise Exception(split_template % identifier)

        tree_udfc_names = [
            fdef.canonical_name for fdef in udf_defs(feature.instance, 'Tree')
            if fdef.iscollection
        ]

        if ((field in tree_udfc_names
             and feature.safe_get_current_tree() is None and value == [])):
            continue
        elif object_name in feature_object_names:
            model = feature
        elif object_name == 'tree' and feature.feature_type == 'Plot':
            # Get the tree or spawn a new one if needed
            tree = (tree or feature.safe_get_current_tree()
                    or Tree(instance=feature.instance))

            # We always edit in display units
            tree.convert_to_display_units()

            model = tree
            if field == 'species' and value:
                value = get_object_or_404(Species,
                                          instance=feature.instance,
                                          pk=value)
            elif field == 'plot' and value == unicode(feature.pk):
                value = feature
        else:
            raise Exception('Malformed request - invalid model %s' %
                            object_name)

        set_attr_on_model(model, field, value)

        field_class = model._meta.get_field_by_name(field)[0]
        if isinstance(field_class, GeometryField):
            rev_updates.append('geo_rev')
            rev_updates.append('eco_rev')
        elif identifier in ['tree.species', 'tree.diameter']:
            rev_updates.append('eco_rev')

    errors = {}

    if feature.fields_were_updated():
        errors.update(save_and_return_errors(feature, user))
    if tree and tree.fields_were_updated():
        tree.plot = feature
        errors.update(save_and_return_errors(tree, user))

    if errors:
        # It simplifies the templates and client-side logic if the geometry
        # field errors are returned under the generic name
        if feature.geom_field_name in errors:
            errors['mapFeature.geom'] = errors[feature.geom_field_name]
        raise ValidationError(errors)

    if old_geom is not None and feature.geom != old_geom:
        update_hide_at_zoom_after_move(feature, user, old_geom)

    feature.instance.update_revs(*rev_updates)

    return feature, tree
Example #39
0
def update_map_feature(request_dict, user, feature):
    """
    Update a map feature. Expects JSON in the request body to be:
    {'model.field', ...}

    Where model is either 'tree', 'plot', or another map feature type
    and field is any field on the model.
    UDF fields should be prefixed with 'udf:'.

    This method can be used to create a new map feature by passing in
    an empty MapFeature object (i.e. Plot(instance=instance))
    """
    feature_object_names = [to_object_name(ft)
                            for ft in feature.instance.map_feature_types]

    if isinstance(feature, Convertible):
        # We're going to always work in display units here
        feature.convert_to_display_units()

    def set_attr_on_model(model, attr, val):
        field_classname = \
            model._meta.get_field_by_name(attr)[0].__class__.__name__

        if field_classname.endswith('PointField'):
            srid = val.get('srid', 3857)
            val = Point(val['x'], val['y'], srid=srid)
            val.transform(3857)
        elif field_classname.endswith('MultiPolygonField'):
            srid = val.get('srid', 4326)
            val = MultiPolygon(Polygon(val['polygon'], srid=srid), srid=srid)
            val.transform(3857)

        if attr == 'mapfeature_ptr':
            if model.mapfeature_ptr_id != value:
                raise Exception(
                    'You may not change the mapfeature_ptr_id')
        elif attr == 'id':
            if val != model.pk:
                raise Exception("Can't update id attribute")
        elif attr.startswith('udf:'):
            udf_name = attr[4:]

            if udf_name in [field.name
                            for field
                            in model.get_user_defined_fields()]:
                model.udfs[udf_name] = val
            else:
                raise KeyError('Invalid UDF %s' % attr)
        elif attr in model.fields():
            model.apply_change(attr, val)
        else:
            raise Exception('Malformed request - invalid field %s' % attr)

    def save_and_return_errors(thing, user):
        try:
            if isinstance(thing, Convertible):
                thing.convert_to_database_units()

            thing.save_with_user(user)
            return {}
        except ValidationError as e:
            return package_field_errors(thing._model_name, e)

    tree = None

    rev_updates = ['universal_rev']
    old_geom = feature.geom
    for (identifier, value) in request_dict.iteritems():
        split_template = 'Malformed request - invalid field %s'
        object_name, field = dotted_split(identifier, 2,
                                          failure_format_string=split_template)
        if (object_name not in feature_object_names + ['tree']):
            raise Exception(split_template % identifier)

        tree_udfc_names = [fdef.canonical_name
                           for fdef in udf_defs(feature.instance, 'Tree')
                           if fdef.iscollection]

        if ((field in tree_udfc_names and
             feature.safe_get_current_tree() is None and
             value == [])):
            continue
        elif object_name in feature_object_names:
            model = feature
        elif object_name == 'tree' and feature.feature_type == 'Plot':
            # Get the tree or spawn a new one if needed
            tree = (tree or
                    feature.safe_get_current_tree() or
                    Tree(instance=feature.instance))

            # We always edit in display units
            tree.convert_to_display_units()

            model = tree
            if field == 'species' and value:
                value = get_object_or_404(Species,
                                          instance=feature.instance, pk=value)
            elif field == 'plot' and value == unicode(feature.pk):
                value = feature
        else:
            raise Exception(
                'Malformed request - invalid model %s' % object_name)

        set_attr_on_model(model, field, value)

        field_class = model._meta.get_field_by_name(field)[0]
        if isinstance(field_class, GeometryField):
            rev_updates.append('geo_rev')
            rev_updates.append('eco_rev')
        elif identifier in ['tree.species', 'tree.diameter']:
            rev_updates.append('eco_rev')

    errors = {}

    if feature.fields_were_updated():
        errors.update(save_and_return_errors(feature, user))
    if tree and tree.fields_were_updated():
        tree.plot = feature
        errors.update(save_and_return_errors(tree, user))

    if errors:
        # It simplifies the templates and client-side logic if the geometry
        # field errors are returned under the generic name
        if feature.geom_field_name in errors:
            errors['mapFeature.geom'] = errors[feature.geom_field_name]
        raise ValidationError(errors)

    if old_geom is not None and feature.geom != old_geom:
        update_hide_at_zoom_after_move(feature, user, old_geom)

    feature.instance.update_revs(*rev_updates)

    return feature, tree
Example #40
0
def update_map_feature(request_dict, user, feature):
    """
    Update a map feature. Expects JSON in the request body to be:
    {'model.field', ...}

    Where model is either 'tree', 'plot', or another map feature type
    and field is any field on the model.
    UDF fields should be prefixed with 'udf:'.

    This method can be used to create a new map feature by passing in
    an empty MapFeature object (i.e. Plot(instance=instance))
    """
    feature_object_names = [to_object_name(ft) for ft in feature.instance.map_feature_types]

    if isinstance(feature, Convertible):
        # We're going to always work in display units here
        feature.convert_to_display_units()

    def set_attr_on_model(model, attr, val):
        field_classname = model._meta.get_field_by_name(attr)[0].__class__.__name__

        if field_classname.endswith("PointField"):
            srid = val.get("srid", 3857)
            val = Point(val["x"], val["y"], srid=srid)
            val.transform(3857)
        elif field_classname.endswith("MultiPolygonField"):
            srid = val.get("srid", 4326)
            val = MultiPolygon(Polygon(val["polygon"], srid=srid), srid=srid)
            val.transform(3857)

        if attr == "mapfeature_ptr":
            if model.mapfeature_ptr_id != value:
                raise Exception("You may not change the mapfeature_ptr_id")
        elif attr == "id":
            if val != model.pk:
                raise Exception("Can't update id attribute")
        elif attr.startswith("udf:"):
            udf_name = attr[4:]

            if udf_name in [field.name for field in model.get_user_defined_fields()]:
                model.udfs[udf_name] = val
            else:
                raise KeyError("Invalid UDF %s" % attr)
        elif attr in model.fields():
            model.apply_change(attr, val)
        else:
            raise Exception("Malformed request - invalid field %s" % attr)

    def save_and_return_errors(thing, user):
        try:
            if isinstance(thing, Convertible):
                thing.convert_to_database_units()

            thing.save_with_user(user)
            return {}
        except ValidationError as e:
            return package_field_errors(thing._model_name, e)

    old_location = feature.geom

    tree = None

    for (identifier, value) in request_dict.iteritems():
        split_template = "Malformed request - invalid field %s"
        object_name, field = dotted_split(identifier, 2, failure_format_string=split_template)
        if object_name not in feature_object_names + ["tree"]:
            raise Exception(split_template % identifier)

        tree_udfc_names = [fdef.canonical_name for fdef in udf_defs(feature.instance, "Tree") if fdef.iscollection]

        if field in tree_udfc_names and feature.safe_get_current_tree() is None and value == []:
            continue
        elif object_name in feature_object_names:
            model = feature
        elif object_name == "tree" and feature.feature_type == "Plot":
            # Get the tree or spawn a new one if needed
            tree = tree or feature.safe_get_current_tree() or Tree(instance=feature.instance)

            # We always edit in display units
            tree.convert_to_display_units()

            model = tree
            if field == "species" and value:
                value = get_object_or_404(Species, instance=feature.instance, pk=value)
            elif field == "plot" and value == unicode(feature.pk):
                value = feature
        else:
            raise Exception("Malformed request - invalid model %s" % object_name)

        set_attr_on_model(model, field, value)

    errors = {}

    if feature.fields_were_updated():
        errors.update(save_and_return_errors(feature, user))
    if tree and tree.fields_were_updated():
        tree.plot = feature
        errors.update(save_and_return_errors(tree, user))

    if errors:
        # It simplifies the templates and client-side logic if the geometry
        # field errors are returned under the generic name
        if feature.geom_field_name in errors:
            errors["mapFeature.geom"] = errors[feature.geom_field_name]
        raise ValidationError(errors)

    if old_location is None or not feature.geom.equals_exact(old_location):
        feature.instance.update_geo_rev()

    return feature, tree
Example #41
0
    def render(self, context):
        explanation = _resolve_variable(self.explanation, context)
        label, identifier = self.resolve_label_and_identifier(context)
        user = _resolve_variable(self.user, context)
        instance = _resolve_variable(self.instance, context)
        field_template = get_template(_resolve_variable(
                                      self.field_template, context)).template

        if not isinstance(identifier, basestring)\
           or not _identifier_regex.match(identifier):
            raise template.TemplateSyntaxError(
                'expected a string with the format "object_name.property" '
                'to follow "from" %s' % identifier)

        model_name_or_object_name, field_name = dotted_split(identifier, 2,
                                                             maxsplit=1)
        model = self.get_model(context, model_name_or_object_name, instance)

        object_name = to_object_name(model_name_or_object_name)

        identifier = "%s.%s" % (object_name, field_name)

        def _field_value(model, field_name, data_type):
            udf_field_name = field_name.replace('udf:', '')
            val = None
            if field_name in [f.name for f in model._meta.get_fields()]:
                try:
                    val = getattr(model, field_name)
                except (ObjectDoesNotExist, AttributeError):
                    pass
            elif _is_udf(model, udf_field_name):
                if udf_field_name in model.udfs:
                    val = model.udfs[udf_field_name]
                    # multichoices place a json serialized data-value
                    # on the dom element and client-side javascript
                    # processes it into a view table and edit widget
                    if data_type == 'multichoice':
                        val = json.dumps(val)
                elif data_type == 'multichoice':
                    val = '[]'
            else:
                raise ValueError('Could not find field: %s' % field_name)

            return val

        if is_json_field_reference(field_name):
            field_value = get_attr_from_json_field(model, field_name)
            choices = None
            is_visible = is_editable = True
            data_type = "string"
        else:
            add_blank = (ADD_BLANK_ALWAYS if self.treat_multichoice_as_choice
                         else ADD_BLANK_IF_CHOICE_FIELD)
            data_type, label, explanation, choices = field_type_label_choices(
                model, field_name, label, explanation=explanation,
                add_blank=add_blank)
            field_value = _field_value(model, field_name, data_type)

            if user is not None and hasattr(model, 'field_is_visible'):
                is_visible = model.field_is_visible(user, field_name)
                is_editable = model.field_is_editable(user, field_name)
            else:
                # This tag can be used without specifying a user. In that case
                # we assume that the content is visible and upstream code is
                # responsible for only showing the content to the appropriate
                # user
                is_visible = True
                is_editable = True

        digits = units = ''

        if hasattr(model, 'instance'):
            digits = get_digits_if_formattable(
                model.instance, object_name, field_name)

            units = get_units_if_convertible(
                model.instance, object_name, field_name)
            if units != '':
                units = get_unit_abbreviation(units)

        if data_type == 'foreign_key':
            # rendered clientside
            display_val = ''
        elif field_value is None:
            display_val = None
        elif data_type in ['date', 'datetime']:
            fmt = (model.instance.short_date_format if model.instance
                   else settings.SHORT_DATE_FORMAT)
            display_val = dateformat.format(field_value, fmt)
        elif is_convertible_or_formattable(object_name, field_name):
            display_val = format_value(
                model.instance, object_name, field_name, field_value)
            if units != '':
                display_val += (' %s' % units)
        elif data_type == 'bool':
            display_val = _('Yes') if field_value else _('No')
        elif data_type == 'multichoice':
            # this is rendered clientside from data attributes so
            # there's no meaningful intermediate value to send
            # without rendering the same markup server-side.
            display_val = None
        elif choices:
            display_vals = [choice['display_value'] for choice in choices
                            if choice['value'] == field_value]
            display_val = display_vals[0] if display_vals else field_value
        else:
            display_val = unicode(field_value)

        context['field'] = {
            'label': label,
            'explanation': explanation,
            'identifier': identifier,
            'value': field_value,
            'display_value': display_val,
            'units': units,
            'digits': digits,
            'data_type': data_type,
            'is_visible': is_visible,
            'is_editable': is_editable,
            'choices': choices,
        }
        self.get_additional_context(
            context['field'], model, field_name, context.get('q', ''))

        return field_template.render(context)
Example #42
0
    def render(self, context):
        label, identifier = self.resolve_label_and_identifier(context)
        user = _resolve_variable(self.user, context)
        instance = _resolve_variable(self.instance, context)
        field_template = get_template(_resolve_variable(
                                      self.field_template, context))

        if not isinstance(identifier, basestring)\
           or not _identifier_regex.match(identifier):
            raise template.TemplateSyntaxError(
                'expected a string with the format "object_name.property" '
                'to follow "from" %s' % identifier)

        model_name_or_object_name, field_name = dotted_split(identifier, 2,
                                                             maxsplit=1)
        model = self.get_model(context, model_name_or_object_name, instance)

        object_name = to_object_name(model_name_or_object_name)
        identifier = "%s.%s" % (object_name, field_name)

        def _field_value(model, field_name):
            udf_field_name = field_name.replace('udf:', '')
            if field_name in model._meta.get_all_field_names():
                try:
                    val = getattr(model, field_name)
                except ObjectDoesNotExist:
                    val = None
            elif _is_udf(model, udf_field_name):
                val = model.udfs[udf_field_name]
            else:
                raise ValueError('Could not find field: %s' % field_name)

            return val

        if is_json_field_reference(field_name):
            field_value = get_attr_from_json_field(model, field_name)
            choices = None
            is_visible = is_editable = True
            data_type = "string"
        else:
            field_value = _field_value(model, field_name)
            data_type, label, choices = field_type_label_choices(
                model, field_name, label)

            if user is not None and hasattr(model, 'field_is_visible'):
                is_visible = model.field_is_visible(user, field_name)
                is_editable = model.field_is_editable(user, field_name)
            else:
                # This tag can be used without specifying a user. In that case
                # we assume that the content is visible and upstream code is
                # responsible for only showing the content to the appropriate
                # user
                is_visible = True
                is_editable = True

        digits = units = ''

        if hasattr(model, 'instance'):
            digits = get_digits_if_formattable(
                model.instance, object_name, field_name)

            units = get_units_if_convertible(
                model.instance, object_name, field_name)

        if field_value is None:
            display_val = None
        elif data_type == 'date' and model.instance:
            display_val = dateformat.format(field_value,
                                            model.instance.short_date_format)
        elif data_type == 'date':
            display_val = dateformat.format(field_value,
                                            settings.SHORT_DATE_FORMAT)
        elif is_convertible_or_formattable(object_name, field_name):
            display_val = format_value(
                model.instance, object_name, field_name, field_value)
            if units != '':
                display_val += (' %s' % units)
        elif data_type == 'bool':
            display_val = trans('Yes') if field_value else trans('No')
        else:
            display_val = unicode(field_value)

        context['field'] = {
            'label': label,
            'identifier': identifier,
            'value': field_value,
            'display_value': display_val,
            'units': units,
            'digits': digits,
            'data_type': data_type,
            'is_visible': is_visible,
            'is_editable': is_editable,
            'choices': choices
        }
        self.get_additional_context(context['field'])

        return field_template.render(context)
Example #43
0
    def render(self, context):
        explanation = _resolve_variable(self.explanation, context)
        label, identifier = self.resolve_label_and_identifier(context)
        user = _resolve_variable(self.user, context)
        instance = _resolve_variable(self.instance, context)
        field_template = get_template(_resolve_variable(
                                      self.field_template, context)).template

        if not isinstance(identifier, basestring)\
           or not _identifier_regex.match(identifier):
            raise template.TemplateSyntaxError(
                'expected a string with the format "object_name.property" '
                'to follow "from" %s' % identifier)

        model_name_or_object_name, field_name = dotted_split(identifier, 2,
                                                             maxsplit=1)
        model = self.get_model(context, model_name_or_object_name, instance)

        object_name = to_object_name(model_name_or_object_name)

        identifier = "%s.%s" % (object_name, field_name)

        def _field_value(model, field_name, data_type):
            udf_field_name = field_name.replace('udf:', '')
            val = None
            if field_name in [f.name for f in model._meta.get_fields()]:
                try:
                    val = getattr(model, field_name)
                except (ObjectDoesNotExist, AttributeError):
                    pass
            elif _is_udf(model, udf_field_name):
                if udf_field_name in model.udfs:
                    val = model.udfs[udf_field_name]
                    # multichoices place a json serialized data-value
                    # on the dom element and client-side javascript
                    # processes it into a view table and edit widget
                    if data_type == 'multichoice':
                        val = json.dumps(val)
                elif data_type == 'multichoice':
                    val = '[]'
            else:
                raise ValueError('Could not find field: %s' % field_name)

            return val

        if is_json_field_reference(field_name):
            field_value = get_attr_from_json_field(model, field_name)
            choices = None
            is_visible = is_editable = True
            data_type = "string"
        else:
            add_blank = (ADD_BLANK_ALWAYS if self.treat_multichoice_as_choice
                         else ADD_BLANK_IF_CHOICE_FIELD)
            data_type, label, explanation, choices = field_type_label_choices(
                model, field_name, label, explanation=explanation,
                add_blank=add_blank)
            field_value = _field_value(model, field_name, data_type)

            if user is not None and hasattr(model, 'field_is_visible'):
                is_visible = model.field_is_visible(user, field_name)
                is_editable = model.field_is_editable(user, field_name)
            else:
                # This tag can be used without specifying a user. In that case
                # we assume that the content is visible and upstream code is
                # responsible for only showing the content to the appropriate
                # user
                is_visible = True
                is_editable = True

        digits = units = ''

        if hasattr(model, 'instance'):
            digits = get_digits_if_formattable(
                model.instance, object_name, field_name)

            units = get_units_if_convertible(
                model.instance, object_name, field_name)
            if units != '':
                units = get_unit_abbreviation(units)

        if data_type == 'foreign_key':
            # rendered clientside
            display_val = ''
        elif field_value is None:
            display_val = None
        elif data_type in ['date', 'datetime']:
            fmt = (model.instance.short_date_format if model.instance
                   else settings.SHORT_DATE_FORMAT)
            display_val = dateformat.format(field_value, fmt)
        elif is_convertible_or_formattable(object_name, field_name):
            display_val = format_value(
                model.instance, object_name, field_name, field_value)
            if units != '':
                display_val += (' %s' % units)
        elif data_type == 'bool':
            display_val = _('Yes') if field_value else _('No')
        elif data_type == 'multichoice':
            # this is rendered clientside from data attributes so
            # there's no meaningful intermediate value to send
            # without rendering the same markup server-side.
            display_val = None
        elif choices:
            display_vals = [choice['display_value'] for choice in choices
                            if choice['value'] == field_value]
            display_val = display_vals[0] if display_vals else field_value
        elif data_type == 'float':
            display_val = num_format(field_value)
        else:
            display_val = unicode(field_value)

        context['field'] = {
            'label': label,
            'explanation': explanation,
            'identifier': identifier,
            'value': field_value,
            'display_value': display_val,
            'units': units,
            'digits': digits,
            'data_type': data_type,
            'is_visible': is_visible,
            'is_editable': is_editable,
            'choices': choices,
        }
        self.get_additional_context(
            context['field'], model, field_name, context.get('q', ''))

        return field_template.render(context)