示例#1
0
 def filter_queryset(self, request, queryset, view):
     try:
         types = None
         for key, value in request.query_params.items():
             if key == 'type':
                 if ',' in value:
                     types = value.split(',')
                 else:
                     types = (value,)
         if types:
             types_map = {}
             for ct in ContentType.objects.filter(Q(app_label='main') | Q(app_label='auth', model='user')):
                 ct_model = ct.model_class()
                 if not ct_model:
                     continue
                 ct_type = get_type_for_model(ct_model)
                 types_map[ct_type] = ct.pk
             model = queryset.model
             model_type = get_type_for_model(model)
             if 'polymorphic_ctype' in get_all_field_names(model):
                 types_pks = set([v for k, v in types_map.items() if k in types])
                 queryset = queryset.filter(polymorphic_ctype_id__in=types_pks)
             elif model_type in types:
                 queryset = queryset
             else:
                 queryset = queryset.none()
         return queryset
     except FieldError as e:
         # Return a 400 for invalid field names.
         raise ParseError(*e.args)
示例#2
0
    def filter_queryset(self, request, queryset, view):
        try:
            order_by = None
            for key, value in request.query_params.items():
                if key in ('order', 'order_by'):
                    order_by = value
                    if ',' in value:
                        order_by = value.split(',')
                    else:
                        order_by = (value,)
            if order_by:
                order_by = self._strip_sensitive_model_fields(queryset.model, order_by)

                # Special handling of the type field for ordering. In this
                # case, we're not sorting exactly on the type field, but
                # given the limited number of views with multiple types,
                # sorting on polymorphic_ctype.model is effectively the same.
                new_order_by = []
                if 'polymorphic_ctype' in get_all_field_names(queryset.model):
                    for field in order_by:
                        if field == 'type':
                            new_order_by.append('polymorphic_ctype__model')
                        elif field == '-type':
                            new_order_by.append('-polymorphic_ctype__model')
                        else:
                            new_order_by.append(field)
                else:
                    for field in order_by:
                        if field not in ('type', '-type'):
                            new_order_by.append(field)
                queryset = queryset.order_by(*new_order_by)
            return queryset
        except FieldError as e:
            # Return a 400 for invalid field names.
            raise ParseError(*e.args)
示例#3
0
 def get_description_context(self):
     if 'username' in get_all_field_names(self.model):
         order_field = 'username'
     else:
         order_field = 'name'
     d = super(ListAPIView, self).get_description_context()
     d.update({'order_field': order_field})
     return d
示例#4
0
    def get_field_from_lookup(self, model, lookup):
        field = None
        parts = lookup.split('__')
        if parts and parts[-1] not in self.SUPPORTED_LOOKUPS:
            parts.append('exact')
        # FIXME: Could build up a list of models used across relationships, use
        # those lookups combined with request.user.get_queryset(Model) to make
        # sure user cannot query using objects he could not view.
        new_parts = []

        # Store of all the fields used to detect repeats
        field_set = set([])

        for name in parts[:-1]:
            # HACK: Make project and inventory source filtering by old field names work for backwards compatibility.
            if model._meta.object_name in ('Project', 'InventorySource'):
                name = {
                    'current_update': 'current_job',
                    'last_update': 'last_job',
                    'last_update_failed': 'last_job_failed',
                    'last_updated': 'last_job_run',
                }.get(name, name)

            if name == 'type' and 'polymorphic_ctype' in get_all_field_names(model):
                name = 'polymorphic_ctype'
                new_parts.append('polymorphic_ctype__model')
            else:
                new_parts.append(name)

            if name in getattr(model, 'PASSWORD_FIELDS', ()):
                raise PermissionDenied(_('Filtering on password fields is not allowed.'))
            elif name == 'pk':
                field = model._meta.pk
            else:
                name_alt = name.replace("_", "")
                if name_alt in model._meta.fields_map.keys():
                    field = model._meta.fields_map[name_alt]
                    new_parts.pop()
                    new_parts.append(name_alt)
                else:
                    field = model._meta.get_field(name)
                if 'auth' in name or 'token' in name:
                    raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
                if isinstance(field, ForeignObjectRel) and getattr(field.field, '__prevent_search__', False):
                    raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
                elif getattr(field, '__prevent_search__', False):
                    raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
            if field in field_set:
                # Field traversed twice, could create infinite JOINs, DoSing Tower
                raise ParseError(_('Loops not allowed in filters, detected on field {}.').format(field.name))
            field_set.add(field)
            model = getattr(field, 'related_model', None) or field.model

        if parts:
            new_parts.append(parts[-1])
        new_lookup = '__'.join(new_parts)
        return field, new_lookup
示例#5
0
def get_fields_from_path(model, path):
    '''
    Given a Django ORM lookup path (possibly over multiple models)
    Returns the fields in the line, and also the revised lookup path
    ex., given
        model=Organization
        path='project__timeout'
    returns tuple of fields traversed as well and a corrected path,
    for special cases we do substitutions
        ([<IntegerField for timeout>], 'project__timeout')
    '''
    # Store of all the fields used to detect repeats
    field_list = []
    new_parts = []
    for name in path.split('__'):
        if model is None:
            raise ParseError(_('No related model for field {}.').format(name))
        # HACK: Make project and inventory source filtering by old field names work for backwards compatibility.
        if model._meta.object_name in ('Project', 'InventorySource'):
            name = {
                'current_update': 'current_job',
                'last_update': 'last_job',
                'last_update_failed': 'last_job_failed',
                'last_updated': 'last_job_run',
            }.get(name, name)

        if name == 'type' and 'polymorphic_ctype' in get_all_field_names(model):
            name = 'polymorphic_ctype'
            new_parts.append('polymorphic_ctype__model')
        else:
            new_parts.append(name)

        if name in getattr(model, 'PASSWORD_FIELDS', ()):
            raise PermissionDenied(_('Filtering on password fields is not allowed.'))
        elif name == 'pk':
            field = model._meta.pk
        else:
            name_alt = name.replace("_", "")
            if name_alt in model._meta.fields_map.keys():
                field = model._meta.fields_map[name_alt]
                new_parts.pop()
                new_parts.append(name_alt)
            else:
                field = model._meta.get_field(name)
            if isinstance(field, ForeignObjectRel) and getattr(field.field, '__prevent_search__', False):
                raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
            elif getattr(field, '__prevent_search__', False):
                raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
        if field in field_list:
            # Field traversed twice, could create infinite JOINs, DoSing Tower
            raise ParseError(_('Loops not allowed in filters, detected on field {}.').format(field.name))
        field_list.append(field)
        model = getattr(field, 'related_model', None)

    return field_list, '__'.join(new_parts)