예제 #1
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[force_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise DisallowedModelAdminLookup("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.
        try:
            for key, value in lookup_params.items():
                lookup_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or
                                lookup_needs_distinct(self.lookup_opts, key))
            return filter_specs, bool(filter_specs), lookup_params, use_distinct
        except FieldDoesNotExist as e:
            six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2])
예제 #2
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[force_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise DisallowedModelAdminLookup("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, BaseField):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.
        try:
            for key, value in lookup_params.items():
                lookup_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or
                                lookup_needs_distinct(self.lookup_opts, key))
            return filter_specs, bool(filter_specs), lookup_params, use_distinct
        except FieldDoesNotExist as e:
            six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2])
예제 #3
0
    def get_search_results(self, request, queryset, search_term):
        """
        Returns a tuple containing a queryset to implement the search,
        and a boolean indicating if the results may contain duplicates.
        """
        self.opts = Team._meta
        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        use_distinct = False
        if self.search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in search_term.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break

        return queryset, use_distinct
예제 #4
0
    def filter_index(self, active_index):
        use_distinct = False
        query = self.value()
        
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and query:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in query.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                active_index = active_index.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.resource.opts, search_spec):
                        use_distinct = True
                        break
        if use_distinct:
            return active_index.distinct()
        return active_index
예제 #5
0
파일: base.py 프로젝트: boogiiieee/Iskcon
	def get_queryset(self, request):
		u'''Модифицирует self.qs. Поиск.'''
		query = request.GET.get(SEARCH_VAR, '')
		qs = self.qs

		def construct_search(field_name):
			if field_name.startswith('^'):
				return "%s__istartswith" % field_name[1:]
			elif field_name.startswith('='):
				return "%s__iexact" % field_name[1:]
			elif field_name.startswith('@'):
				return "%s__search" % field_name[1:]
			else:
				return "%s__icontains" % field_name
		
		if self.search_fields and query:
			orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields]
			for bit in query.split():
				or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups]
				qs = qs.filter(reduce(operator.or_, or_queries))
				
			for search_spec in orm_lookups:
				if lookup_needs_distinct(self.opts, search_spec):
					qs = qs.distinct()
					break
				
		return qs
		
		
##########################################################################
##########################################################################
예제 #6
0
    def get_search_results(self, request, queryset, search_term):
        """
        Returns a tuple containing a queryset to implement the search,
        and a boolean indicating if the results may contain duplicates.
        """
        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        use_distinct = False
        if self.search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in search_term.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break

        return queryset, use_distinct
예제 #7
0
    def get_indexes(self):
        #from hyperadmin.resources.indexes import Index
        from hyperadmin.resources.models.filters import FieldFilter, SearchFilter

        from django.db import models
        from django.contrib.admin.util import get_fields_from_path
        try:
            from django.contrib.admin.util import lookup_needs_distinct
        except ImportError:
            from hyperadmin.resources.models.util import lookup_needs_distinct

        indexes = {'primary': ModelIndex('primary', self)}

        index = ModelIndex('filter', self)
        indexes['filter'] = index

        if self.list_filter:
            for list_filter in self.list_filter:
                use_distinct = False
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(index=index)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   field_path=field_path,
                                                   index=index)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.opts, field_path))
                if spec:
                    index.filters.append(spec)

        if self.search_fields:
            index.register_filter(SearchFilter,
                                  search_fields=self.search_fields)
        '''
        date_section = self.register_section('date', FilterSection)
        if self.date_hierarchy:
            pass
        '''
        return indexes
예제 #8
0
 def _search(self, queryset):
     if 'search' in self.cleaned_data:
         lookups = [_search_lookup(str(field)) for field in self.search]
         for bit in self.cleaned_data['search'].split():
             qlist = [models.Q(**{lookup: bit}) for lookup in lookups]
             queryset = queryset.filter(reduce(operator.or_, qlist))
         if not self.use_distinct:
             for lookup in lookups:
                 if lookup_needs_distinct(self.model._meta, lookup):
                     self.use_distinct = True
                     break
     return queryset
예제 #9
0
    def get_indexes(self):
        #from hyperadmin.resources.indexes import Index
        from hyperadmin.resources.models.filters import FieldFilter, SearchFilter

        from django.db import models
        from django.contrib.admin.util import get_fields_from_path
        try:
            from django.contrib.admin.util import lookup_needs_distinct
        except ImportError:
            from hyperadmin.resources.models.util import lookup_needs_distinct
        
        indexes = {'primary': ModelIndex('primary', self)}
        
        index = ModelIndex('filter', self)
        indexes['filter'] = index
        
        if self.list_filter:
            for list_filter in self.list_filter:
                use_distinct = False
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(index=index)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, field_path=field_path, index=index)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts,
                                                          field_path))
                if spec:
                    index.filters.append(spec)
        
        if self.search_fields:
            index.register_filter(SearchFilter, search_fields=self.search_fields)
        '''
        date_section = self.register_section('date', FilterSection)
        if self.date_hierarchy:
            pass
        '''
        return indexes
예제 #10
0
 def _search(self, queryset):
     if 'search' in self.cleaned_data:
         lookups = [_search_lookup(str(field))
                    for field in self.search]
         for bit in self.cleaned_data['search'].split():
             qlist = [models.Q(**{lookup: bit})
                      for lookup in lookups]
             queryset = queryset.filter(reduce(operator.or_, qlist))
         if not self.use_distinct:
             for lookup in lookups:
                 if lookup_needs_distinct(self.model._meta, lookup):
                     self.use_distinct = True
                     break
     return queryset
예제 #11
0
    def get_filters(self):
        lookup_params = dict(self.request.GET.items())
        use_distinct = False

        filter_specs = []
        list_filters = self.list_filter
        if list_filters:
            for list_filter in list_filters:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(
                        self.request,
                        lookup_params,
                        self.model_class,
                        self,
                    )
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given
                        # field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model_class, field_path)[-1]
                    spec = field_list_filter_class(
                        field,
                        self.request,
                        lookup_params,
                        self.model_class,
                        self,
                        field_path=field_path
                    )
                    # Check if we need to use distinct()
                    use_distinct = (
                        use_distinct or
                        lookup_needs_distinct(
                            self.model_class._meta,
                            field_path
                        )
                    )
                if spec and spec.has_output():
                    filter_specs.append(spec)
        self.filter_specs = filter_specs
        return filter_specs, bool(filter_specs), use_distinct
예제 #12
0
    def search(self, query):
        orm_lookups = [construct_search(str(search_field))
                       for search_field in self.search_fields]
        for bit in query.split():
            or_queries = [models.Q(**{orm_lookup: bit})
                          for orm_lookup in orm_lookups]
            self = self.filter(reduce(operator.or_, or_queries))

        for search_spec in orm_lookups:
            if lookup_needs_distinct(self.model._meta, search_spec):
                self = self.distinct()
                break

        return self
예제 #13
0
    def search(self, query):
        orm_lookups = [
            construct_search(str(search_field))
            for search_field in self.search_fields
        ]
        for bit in query.split():
            or_queries = [
                models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
            ]
            self = self.filter(reduce(operator.or_, or_queries))

        for search_spec in orm_lookups:
            if lookup_needs_distinct(self.model._meta, search_spec):
                self = self.distinct()
                break

        return self
예제 #14
0
    def cell_filters(self):
        lookup_params = self.params.copy() # a dictionary of the query string
        cell_filter_specs = {}
        use_distinct = False

        if self.model_admin.cell_filter:
            for cell_filter in self.model_admin.cell_filter:
                path = field_path = None
                field, field_list_filter_class = cell_filter, FieldCellFilter

                if hasattr(self.model_admin, cell_filter):
                    # if it's a ModelAdmin method get the `admin_filter_field`
                    attr = getattr(self.model_admin, cell_filter)
                    field_path = getattr(attr, 'admin_filter_field', None)
                    if not field_path:
                        continue
                    path = get_fields_from_path(self.model, field_path)
                    field = path[-1]

                if not isinstance(field, models.Field):
                    try:
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]

                    except FieldDoesNotExist:
                        raise Exception(
                            "Cannot use field `%s` in cell_filter. Only valid Field objects are allowed" % cell_filter)

                if isinstance(field, BooleanField):
                    field_list_filter_class = BooleanCellFilter
                elif hasattr(field, 'rel') and bool(field.rel):
                    field_list_filter_class = RelatedFieldCellFilter
                elif hasattr(field, 'choices'):
                    field_list_filter_class = ChoicesCellFilter
                spec = field_list_filter_class(field, self.request, lookup_params,
                    self.model, self.model_admin, field_path=field_path)

                # Check if we need to use distinct()
                use_distinct = (use_distinct or
                                lookup_needs_distinct(self.lookup_opts,
                                    field_path))
                if spec and spec.has_output():
                    cell_filter_specs[cell_filter] = spec

        return cell_filter_specs
예제 #15
0
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in self.query.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs

    def url_for_result(self, result):
        return "%s/" % quote(getattr(result, self.pk_attname))
예제 #16
0
    def get_query_set(self, request):
        '''qs = self.root_query_set
        if not(request.GET.has_key('q')):
            return EmptyQuerySet()
        (self.filter_specs, self.has_filters, remaining_lookup_params, use_distinct) = self.get_filters(request)
        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs
        try:
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)

        order_queryset = qs
        if self.search_fields and self.query:
            orm_lookups = ["%s__icontains" % (str(search_field)) for search_field in self.search_fields]
            for bit in self.query.split():
                or_queries = [models.Q(**{orm_lookup: bit})for orm_lookup in orm_lookups]
                qs = qs.filter(reduce(operator.or_, or_queries))
            queryset = set(qs.values_list('id', flat=True))
            search_world = (request.GET['q']).lower().strip()
            profile_objects = Profile.objects.select_related().exclude(user__id__in=qs)
            for pr in profile_objects:
                if compare(pr.get_company_name_or_family().lower(), search_world):
                    queryset.add(pr.user.id)
            qs = order_queryset.filter(pk__in=queryset)
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break'''
        #--------startMy--------------------
        qs = self.root_query_set
        if not(request.GET.has_key('q')):
            return EmptyQuerySet()
        (self.filter_specs, self.has_filters, remaining_lookup_params, use_distinct) = self.get_filters(request)
        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs
        try:
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)

        if self.search_fields and self.query:
            orm_lookups = ["user__%s__icontains" % (str(search_field)) for search_field in self.search_fields]
            search_fields2 = ["first_name", "last_name", "company_name", "legal_form", "billing_account_id"]
            orm_lookups3 = ["%s__icontains" % (str(search_field)) for search_field in self.search_fields]
            orm_lookups2 = ["%s__icontains" % (str(search_field)) for search_field in search_fields2]
            orm_lookups += orm_lookups2
            print orm_lookups
            profls = Profile.objects.select_related("user").all()
            for bit in self.query.split():
                or_queries = [models.Q(**{orm_lookup: bit})for orm_lookup in orm_lookups]
                profls = profls.filter(reduce(operator.or_, or_queries))
            ids = [profl.user_id for profl in profls]
            qs = qs.filter(pk__in=ids)
            if not use_distinct:
                for search_spec in orm_lookups3:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break
        #--------endMy--------------------
        ordering = self.get_ordering(request, qs)
        qs = qs.order_by(*ordering)
        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #17
0
    def get_search_results(self, request, queryset, search_term):
        def generate_q_object(orm_lookups):
            """
            Generate Or'ed queries from orm_lookups (fields)
            and every bit of the search_term (query).
            """
            q = Q()
            for bit in search_term.split():
                or_queries = [
                    Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                if or_queries:
                    q = (q & reduce(operator.or_, or_queries))
            return q

        # Apply keyword searches.
        def construct_search(field_name):
            """
            Parse field_name to allow advanced searches using the
            prefixes: '^', '=', '@' and no prefix (default)
            """
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        def parse_related_fields():
            """
            Go over the search_fields to look for fields that exist in the
            related_search_mapping
            """
            normal_fields = []
            generic_search_fields = defaultdict(list)
            for field in self.search_fields:
                for rfield in self.related_search_mapping:
                    if field.startswith(rfield):
                        inner_field = field[len(rfield) + 2:]
                        generic_search_fields[rfield].append(
                            # get the field name after 'rfield__'
                            construct_search(inner_field))
                    else:
                        normal_fields.append(field)
            return normal_fields, generic_search_fields

        def get_object_id(model, generic_field):
            """
            Return the foreign key field for a given GenericForeignKey
            in a given model
            """
            logger.debug(
                'related_search_mapping did not define object_id, '
                'attempting to find using GenericForeignKey %s in '
                'model %s', generic_field, model)
            field = get_generic_field(model, generic_field)
            if field:
                return field.fk_field
            raise Exception('Given field %s does not exist in registered model'
                            ' %s and no object_id provided' %
                            (generic_field, model))

        def get_content_types(model, generic_field):
            """
            Return the content types allowed for a given GenericForeignKey
            in a given model
            """
            logger.debug(
                'related_search_mapping did not define ctypes, '
                'attempting to find using GenericForeignKey %s in '
                'model %s', generic_field, model)
            field = get_generic_field(model, generic_field)
            if field:
                return field.ct_field
            raise Exception('Given field %s does not exist in registered model'
                            ' %s and no object_id provided' %
                            (generic_field, model))

        def get_related_ids(fields_mapping):
            """
            Takes a dict of {generic_field_name: list_of_inner_Fields}, performs
            the query on the related object models (using defined or calculated
            content types) and returns the ids of the result objects.
            """
            def get_ctype_models(ctypes):
                """
                Gets model classes from the passed argument, which can be:

                a. a dict which can be extrapolated into a query filter.
                b. a Q object which can be passed to a query filter.
                c. an iterable of 2 element tuples as (app_label, model)
                """
                if isinstance(ctypes, dict):
                    if not ctypes:
                        logger.warn("""
This is a very inefficient query! Each search argument is going to query
all model classes. Please limit ContentType choices the FK if possible,
or define a 'related_search_mapping' argument which limits the ctypes.""")
                    return [
                        ct.model_class()
                        for ct in ContentType.objects.filter(**ctypes)
                    ]
                elif isinstance(ctypes, Q):
                    return [
                        ct.model_class()
                        for ct in ContentType.objects.filter(ctypes)
                    ]
                elif isinstance(ctypes, Iterable):
                    return [
                        ContentType.objects.get(app_label=app,
                                                model=model).model_class()
                        for app, model in ctypes
                    ]
                raise Exception("Invalid argument passed, must be one of: "
                                "<dict>, <Q>, <iterable of 2 elem. tuples>")

            ids = defaultdict(list)
            for rel_field, fields in list(fields_mapping.items()):
                query = generate_q_object(fields)
                if not query:
                    logger.warn('No Q instance returned')
                    continue

                obj_id = (
                    self.related_search_mapping[rel_field].get('object_id')
                    or get_object_id(self.model, rel_field))
                ctypes = (self.related_search_mapping[rel_field].get('ctypes')
                          or get_content_types(self.model, rel_field))
                models = get_ctype_models(ctypes)
                for model in models:
                    ids[obj_id].extend(
                        model.objects.filter(query).values_list('pk',
                                                                flat=True))
            return ids

        use_distinct = False
        if not search_term:
            return queryset, use_distinct

        non_generic_fields, generic_fields = parse_related_fields()
        related_ids = get_related_ids(generic_fields)

        # initial orm lookups (for normal fields)
        orm_lookups = [
            construct_search(str(search_field))
            for search_field in non_generic_fields
        ]
        for bit in search_term.split():
            or_queries = [Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups]

            # append generic related filters to or_queries
            for obj_id, ids_list in list(related_ids.items()):
                or_queries.append(Q(**{'%s__in' % obj_id: ids_list}))
            query = reduce(operator.or_, or_queries)
            queryset = queryset.filter(query)
        if not use_distinct:
            for search_spec in orm_lookups:
                if lookup_needs_distinct(self.opts, search_spec):
                    use_distinct = True
                    break
        return queryset, use_distinct
예제 #18
0
    def get_queryset(self, request):
        # First, we collect all the declared list filters.
        (self.filter_specs, self.has_filters, remaining_lookup_params,
         use_distinct) = self.get_filters(request)

        # Then, we let every list filter modify the queryset to its liking.
        qs = self.root_queryset
        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs

        try:
            # Finally, we apply the remaining lookup parameters from the query
            # string (i.e. those that haven't already been processed by the
            # filters).
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            # Allow certain types of errors to be re-raised as-is so that the
            # caller can treat them in a special way.
            raise
        except Exception as e:
            # Every other error is caught with a naked except, because we don't
            # have any other way of validating lookup parameters. They might be
            # invalid if the keyword arguments are incorrect, or if the values
            # are not in the correct type, so we might get FieldError,
            # ValueError, ValidationError, or ?.
            raise IncorrectLookupParameters(e)

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        field = self.lookup_opts.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(field.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        ordering = self.get_ordering(request, qs)
        qs = qs.order_by(*ordering)

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in self.query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #19
0
    def get_filters(self, request):
        if not request.session.get('use_new_filters'):
            return super(CustomChangeList, self).get_filters(request)

        new_filter, created = CustomFilter.objects.get_or_create(
            user=request.user,
            model_name=self.model.__name__,
            app_name=self.model._meta.app_label,
            default=True)
        form = CustomFilterForm(request.GET.copy(), custom_filter=new_filter)
        if len(request.GET) and form.is_valid():
            form.save()

        self.current_filter = CustomFilter.objects.filter(
            user=request.user, path_info=request.path_info, default=True)

        # loading filter set params into change list, so they will be applied in queryset
        if self.current_filter:
            filter_params, self.exclude_params, self.bundled_params = self.current_filter[
                0].get_filter_params()
            self.params.update(**filter_params)

        lookup_params = self.params.copy()  # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params, self.model,
                                       self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   request,
                                                   lookup_params,
                                                   self.model,
                                                   self.model_admin,
                                                   field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.

        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            try:
                use_distinct = (use_distinct or lookup_needs_distinct(
                    self.lookup_opts, key))
            except FieldDoesNotExist, e:
                lookup_params.pop(key)
예제 #20
0
파일: main.py 프로젝트: Aliced3645/django
    def get_query_set(self, request):
        # First, we collect all the declared list filters.
        (self.filter_specs, self.has_filters, remaining_lookup_params,
         use_distinct) = self.get_filters(request)

        # Then, we let every list filter modify the queryset to its liking.
        qs = self.root_query_set
        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs

        try:
            # Finally, we apply the remaining lookup parameters from the query
            # string (i.e. those that haven't already been processed by the
            # filters).
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            # Allow certain types of errors to be re-raised as-is so that the
            # caller can treat them in a special way.
            raise
        except Exception as e:
            # Every other error is caught with a naked except, because we don't
            # have any other way of validating lookup parameters. They might be
            # invalid if the keyword arguments are incorrect, or if the values
            # are not in the correct type, so we might get FieldError,
            # ValueError, ValidationError, or ?.
            raise IncorrectLookupParameters(e)

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        field = self.lookup_opts.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(field.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        ordering = self.get_ordering(request, qs)
        qs = qs.order_by(*ordering)

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in self.query.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #21
0
class ChangeList(object):
    def __init__(self, request, model, list_display, list_display_links,
                 list_filter, date_hierarchy, search_fields,
                 list_select_related, list_per_page, list_max_show_all,
                 list_editable, model_admin):
        self.model = model
        self.opts = model._meta
        self.lookup_opts = self.opts
        self.root_query_set = model_admin.queryset(request)
        self.list_display = list_display
        self.list_display_links = list_display_links
        self.list_filter = list_filter
        self.date_hierarchy = date_hierarchy
        self.search_fields = search_fields
        self.list_select_related = list_select_related
        self.list_per_page = list_per_page
        self.list_max_show_all = list_max_show_all
        self.model_admin = model_admin

        # Get search parameters from the query string.
        try:
            self.page_num = int(request.GET.get(PAGE_VAR, 0))
        except ValueError:
            self.page_num = 0
        self.show_all = ALL_VAR in request.GET
        self.is_popup = IS_POPUP_VAR in request.GET
        self.to_field = request.GET.get(TO_FIELD_VAR)
        self.params = dict(request.GET.items())
        if PAGE_VAR in self.params:
            del self.params[PAGE_VAR]
        if ERROR_FLAG in self.params:
            del self.params[ERROR_FLAG]

        if self.is_popup:
            self.list_editable = ()
        else:
            self.list_editable = list_editable
        self.ordering = self.get_ordering(request)
        self.query = request.GET.get(SEARCH_VAR, '')
        self.query_set = self.get_query_set(request)
        self.get_results(request)
        if self.is_popup:
            title = ugettext('Select %s')
        else:
            title = ugettext('Select %s to change')
        self.title = title % force_unicode(self.opts.verbose_name)
        self.pk_attname = self.lookup_opts.pk.attname

    def get_filters(self, request):
        lookup_params = self.params.copy()  # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params, self.model,
                                       self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   request,
                                                   lookup_params,
                                                   self.model,
                                                   self.model_admin,
                                                   field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct().
        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            use_distinct = (use_distinct
                            or lookup_needs_distinct(self.lookup_opts, key))

        return filter_specs, bool(filter_specs), lookup_params, use_distinct

    def get_query_string(self, new_params=None, remove=None):
        if new_params is None: new_params = {}
        if remove is None: remove = []
        p = self.params.copy()
        for r in remove:
            for k in p.keys():
                if k.startswith(r):
                    del p[k]
        for k, v in new_params.items():
            if v is None:
                if k in p:
                    del p[k]
            else:
                p[k] = v
        return '?%s' % urlencode(p)

    def get_results(self, request):
        paginator = self.model_admin.get_paginator(request, self.query_set,
                                                   self.list_per_page)
        # Get the number of objects, with admin filters applied.
        result_count = paginator.count

        # Get the total number of objects, with no admin filters applied.
        # Perform a slight optimization: Check to see whether any filters were
        # given. If not, use paginator.hits to calculate the number of objects,
        # because we've already done paginator.hits and the value is cached.
        if not self.query_set.query.where:
            full_result_count = result_count
        else:
            full_result_count = self.root_query_set.count()

        can_show_all = result_count <= self.list_max_show_all
        multi_page = result_count > self.list_per_page

        # Get the list of objects to display on this page.
        if (self.show_all and can_show_all) or not multi_page:
            result_list = self.query_set._clone()
        else:
            try:
                result_list = paginator.page(self.page_num + 1).object_list
            except InvalidPage:
                raise IncorrectLookupParameters

        self.result_count = result_count
        self.full_result_count = full_result_count
        self.result_list = result_list
        self.can_show_all = can_show_all
        self.multi_page = multi_page
        self.paginator = paginator

    def _get_default_ordering(self):
        ordering = []
        if self.model_admin.ordering:
            ordering = self.model_admin.ordering
        elif self.lookup_opts.ordering:
            ordering = self.lookup_opts.ordering
        return ordering

    def get_ordering_field(self, field_name):
        """
        Returns the proper model field name corresponding to the given
        field_name to use for ordering. field_name may either be the name of a
        proper model field or the name of a method (on the admin or model) or a
        callable with the 'admin_order_field' attribute. Returns None if no
        proper model field name can be matched.
        """
        try:
            field = self.lookup_opts.get_field(field_name)
            return field.name
        except models.FieldDoesNotExist:
            # See whether field_name is a name of a non-field
            # that allows sorting.
            if callable(field_name):
                attr = field_name
            elif hasattr(self.model_admin, field_name):
                attr = getattr(self.model_admin, field_name)
            else:
                attr = getattr(self.model, field_name)
            return getattr(attr, 'admin_order_field', None)

    def get_ordering(self, request):
        params = self.params
        # For ordering, first check the if exists the "get_ordering" method
        # in model admin, then check "ordering" parameter in the admin
        # options, then check the object's default ordering. Finally, a
        # manually-specified ordering from the query string overrides anything.
        ordering = self.model_admin.get_ordering(
            request) or self._get_default_ordering()
        if ORDER_VAR in params:
            # Clear ordering and used params
            ordering = []
            order_params = params[ORDER_VAR].split('.')
            for p in order_params:
                try:
                    none, pfx, idx = p.rpartition('-')
                    field_name = self.list_display[int(idx)]
                    order_field = self.get_ordering_field(field_name)
                    if not order_field:
                        continue  # No 'admin_order_field', skip it
                    ordering.append(pfx + order_field)
                except (IndexError, ValueError):
                    continue  # Invalid ordering specified, skip it.
        return ordering

    def get_ordering_field_columns(self):
        """
        Returns a SortedDict of ordering field column numbers and asc/desc
        """

        # We must cope with more than one column having the same underlying sort
        # field, so we base things on column numbers.
        ordering = self._get_default_ordering()
        ordering_fields = SortedDict()
        if ORDER_VAR not in self.params:
            # for ordering specified on ModelAdmin or model Meta, we don't know
            # the right column numbers absolutely, because there might be more
            # than one column associated with that ordering, so we guess.
            for field in ordering:
                if field.startswith('-'):
                    field = field[1:]
                    order_type = 'desc'
                else:
                    order_type = 'asc'
                for index, attr in enumerate(self.list_display):
                    if self.get_ordering_field(attr) == field:
                        ordering_fields[index] = order_type
                        break
        else:
            for p in self.params[ORDER_VAR].split('.'):
                none, pfx, idx = p.rpartition('-')
                try:
                    idx = int(idx)
                except ValueError:
                    continue  # skip it
                ordering_fields[idx] = 'desc' if pfx == '-' else 'asc'
        return ordering_fields

    def get_query_set(self, request):
        try:
            # First, we collect all the declared list filters.
            (self.filter_specs, self.has_filters, remaining_lookup_params,
             use_distinct) = self.get_filters(request)

            # Then, we let every list filter modify the qs to its liking.
            qs = self.root_query_set
            for filter_spec in self.filter_specs:
                new_qs = filter_spec.queryset(request, qs)
                if new_qs is not None:
                    qs = new_qs

            # Finally, we apply the remaining lookup parameters from the query
            # string (i.e. those that haven't already been processed by the
            # filters).
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            # Allow certain types of errors to be re-raised as-is so that the
            # caller can treat them in a special way.
            raise
        except Exception, e:
            # Every other error is caught with a naked except, because we don't
            # have any other way of validating lookup parameters. They might be
            # invalid if the keyword arguments are incorrect, or if the values
            # are not in the correct type, so we might get FieldError,
            # ValueError, ValidationError, or ? from a custom field that raises
            # yet something else when handed impossible data.
            raise IncorrectLookupParameters(e)

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        field = self.lookup_opts.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(field.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        if self.ordering:
            qs = qs.order_by(*self.ordering)

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in self.query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #22
0
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and self.query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in self.query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs

    def url_for_result(self, result):
        return "%s/" % quote(getattr(result, self.pk_attname))
예제 #23
0
class PowerChangeList(ChangeList):
    def __init__(self, request, model, list_display, list_display_links,
                 list_filter, date_hierarchy, search_fields,
                 list_select_related, list_per_page, list_max_show_all,
                 list_editable, model_admin):
        #Criando o multi_search_query
        self.multi_search_query = {}
        request.GET._mutable = True
        for k, l, f in model_admin.multi_search:
            if k in request.GET:
                self.multi_search_query[k] = request.GET.get(k, '')
                del request.GET[k]
        request.GET._mutable = False
        super(PowerChangeList,
              self).__init__(request, model, list_display, list_display_links,
                             list_filter, date_hierarchy, search_fields,
                             list_select_related, list_per_page,
                             list_max_show_all, list_editable, model_admin)

    def get_query_set(self, request):

        MULTI_SEARCH_VAR = []
        for var, label, query in self.model_admin.multi_search:
            MULTI_SEARCH_VAR.append(var)

        # First, we collect all the declared list filters.
        (self.filter_specs, self.has_filters, remaining_lookup_params,
         use_distinct) = self.get_filters(request)

        # Then, we let every list filter modify the queryset to its liking.
        qs = self.root_query_set
        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs

        try:
            # Finally, we apply the remaining lookup parameters from the query
            # string (i.e. those that haven't already been processed by the
            # filters).
            qs = qs.filter(**remaining_lookup_params)
        except (SuspiciousOperation, ImproperlyConfigured):
            # Allow certain types of errors to be re-raised as-is so that the
            # caller can treat them in a special way.
            raise
        except Exception, e:
            # Every other error is caught with a naked except, because we don't
            # have any other way of validating lookup parameters. They might be
            # invalid if the keyword arguments are incorrect, or if the values
            # are not in the correct type, so we might get FieldError,
            # ValueError, ValidationError, or ?.
            raise IncorrectLookupParameters(e)

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        field = self.lookup_opts.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(field.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        ordering = self.get_ordering(request, qs)
        qs = qs.order_by(*ordering)

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        #Faz o filter do multi_search
        if self.multi_search_query:
            for k_query, query in self.multi_search_query.items():
                for k, l, f in self.model_admin.multi_search:
                    if k_query == k:
                        fields = f
                        break
                if fields and query:
                    orm_lookups = [
                        construct_search(str(field)) for field in fields
                    ]
                    for bit in query.split():
                        or_queries = [
                            models.Q(**{orm_lookup: bit})
                            for orm_lookup in orm_lookups
                        ]
                        qs = qs.filter(reduce(operator.or_, or_queries))

        elif self.search_fields and self.query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in self.query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #24
0
    def get_filters(self, request):
        lookup_params = self.params.copy()  # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params, self.model,
                                       self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   request,
                                                   lookup_params,
                                                   self.model,
                                                   self.model_admin,
                                                   field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct().
        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            use_distinct = (use_distinct
                            or lookup_needs_distinct(self.lookup_opts, key))

        return filter_specs, bool(filter_specs), lookup_params, use_distinct
예제 #25
0
파일: main.py 프로젝트: BillyWu/django
    def get_filters(self, request):
        lookup_params = self.params.copy() # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct().
        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            use_distinct = (use_distinct or
                            lookup_needs_distinct(self.lookup_opts, key))

        return filter_specs, bool(filter_specs), lookup_params, use_distinct
예제 #26
0
    def _queryset(self):
        (filter_specs, has_filters, use_distinct) = self.filter.get_filters()

        # Then, we let every list filter modify the queryset to its liking.
        if self.queryset:
            qs = self.queryset
        else:
            qs = self.model_class.objects.all()
        for filter_spec in filter_specs:
            new_qs = filter_spec.queryset(self.request, qs)
            if new_qs is not None:
                qs = new_qs

        # Use select_related() if one of the list_display options is a field
        # with a relationship and the provided queryset doesn't already have
        # select_related defined.
        if not qs.query.select_related:
            if self.list_select_related:
                qs = qs.select_related()
            else:
                for field_name in self.list_display:
                    try:
                        field = self.model_class._meta.get_field(field_name)
                    except models.FieldDoesNotExist:
                        pass
                    else:
                        if isinstance(field.rel, models.ManyToOneRel):
                            qs = qs.select_related()
                            break

        # Set ordering.
        ordering = self.get_ordering()
        qs = qs.order_by(*ordering)

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        search_query = self.request.GET.get(SEARCH_VAR, '')
        if self.search_fields and search_query:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in self.query.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break

        if use_distinct:
            return qs.distinct()
        else:
            return qs
예제 #27
0
    def get_search_results(self, request, queryset, search_term):
        def generate_q_object(orm_lookups):
            """
            Generate Or'ed queries from orm_lookups (fields)
            and every bit of the search_term (query).
            """
            q = Q()
            for bit in search_term.split():
                or_queries = [Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                if or_queries:
                    q = (q & reduce(operator.or_, or_queries))
            return q

        # Apply keyword searches.
        def construct_search(field_name):
            """
            Parse field_name to allow advanced searches using the
            prefixes: '^', '=', '@' and no prefix (default)
            """
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        def parse_related_fields():
            """
            Go over the search_fields to look for fields that exist in the
            related_search_mapping
            """
            normal_fields = []
            generic_search_fields = defaultdict(list)
            for field in self.search_fields:
                for rfield in self.related_search_mapping:
                    if field.startswith(rfield):
                        inner_field = field[len(rfield) + 2:]
                        generic_search_fields[rfield].append(
                            # get the field name after 'rfield__'
                            construct_search(inner_field)
                        )
                    else:
                        normal_fields.append(field)
            return normal_fields, generic_search_fields

        def get_object_id(model, generic_field):
            """
            Return the foreign key field for a given GenericForeignKey
            in a given model
            """
            logger.debug('related_search_mapping did not define object_id, '
                         'attempting to find using GenericForeignKey %s in '
                         'model %s', generic_field, model)
            field = get_generic_field(model, generic_field)
            if field:
                return field.fk_field
            raise Exception('Given field %s does not exist in registered model'
                            ' %s and no object_id provided' % (
                                generic_field, model))

        def get_content_types(model, generic_field):
            """
            Return the content types allowed for a given GenericForeignKey
            in a given model
            """
            logger.debug('related_search_mapping did not define ctypes, '
                         'attempting to find using GenericForeignKey %s in '
                         'model %s', generic_field, model)
            field = get_generic_field(model, generic_field)
            if field:
                return field.ct_field
            raise Exception('Given field %s does not exist in registered model'
                            ' %s and no object_id provided' % (
                                generic_field, model))

        def get_related_ids(fields_mapping):
            """
            Takes a dict of {generic_field_name: list_of_inner_Fields}, performs
            the query on the related object models (using defined or calculated
            content types) and returns the ids of the result objects.
            """
            def get_ctype_models(ctypes):
                """
                Gets model classes from the passed argument, which can be:

                a. a dict which can be extrapolated into a query filter.
                b. a Q object which can be passed to a query filter.
                c. an iterable of 2 element tuples as (app_label, model)
                """
                if isinstance(ctypes, dict):
                    if not ctypes:
                        logger.warn("""
This is a very inefficient query! Each search argument is going to query
all model classes. Please limit ContentType choices the FK if possible,
or define a 'related_search_mapping' argument which limits the ctypes.""")
                    return [ct.model_class()
                            for ct in ContentType.objects.filter(**ctypes)]
                elif isinstance(ctypes, Q):
                    return [ct.model_class()
                            for ct in ContentType.objects.filter(ctypes)]
                elif isinstance(ctypes, Iterable):
                    return [ContentType.objects.get(
                            app_label=app, model=model).model_class()
                            for app, model in ctypes]
                raise Exception("Invalid argument passed, must be one of: "
                                "<dict>, <Q>, <iterable of 2 elem. tuples>")

            ids = defaultdict(list)
            for rel_field, fields in fields_mapping.items():
                query = generate_q_object(fields)
                if not query:
                    logger.warn('No Q instance returned')
                    continue

                obj_id = (self.related_search_mapping[rel_field].get(
                          'object_id') or get_object_id(self.model, rel_field))
                ctypes = (self.related_search_mapping[rel_field].get(
                          'ctypes') or get_content_types(self.model, rel_field))
                models = get_ctype_models(ctypes)
                for model in models:
                    ids[obj_id].extend(
                        model.objects.filter(query).values_list(
                            'pk', flat=True)
                    )
            return ids

        use_distinct = False
        if not search_term:
            return queryset, use_distinct

        non_generic_fields, generic_fields = parse_related_fields()
        related_ids = get_related_ids(generic_fields)

        # initial orm lookups (for normal fields)
        orm_lookups = [construct_search(str(search_field))
                       for search_field in non_generic_fields]
        for bit in search_term.split():
            or_queries = [Q(**{orm_lookup: bit})
                          for orm_lookup in orm_lookups]

            # append generic related filters to or_queries
            for obj_id, ids_list in related_ids.items():
                or_queries.append(Q(
                    **{
                        '%s__in' % obj_id: ids_list
                    }
                ))
            query = reduce(operator.or_, or_queries)
            queryset = queryset.filter(query)
        if not use_distinct:
            for search_spec in orm_lookups:
                if lookup_needs_distinct(self.opts, search_spec):
                    use_distinct = True
                    break
        return queryset, use_distinct
예제 #28
0
    def get_filters(self, request):
        if not request.session.get('use_new_filters'):
            return super(CustomChangeList, self).get_filters(request)

        new_filter, created = CustomFilter.objects.get_or_create(user=request.user, model_name=self.model.__name__, app_name=self.model._meta.app_label, default=True)
        form = CustomFilterForm(request.GET.copy(), custom_filter=new_filter)
        if len(request.GET) and form.is_valid():
            form.save()

        self.current_filter = CustomFilter.objects.filter(user=request.user, path_info=request.path_info, default=True)

        # loading filter set params into change list, so they will be applied in queryset
        if self.current_filter:
            filter_params, self.exclude_params, self.bundled_params = self.current_filter[0].get_filter_params()
            self.params.update(**filter_params)

        lookup_params = self.params.copy() # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.

        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            try:
                use_distinct = (use_distinct or lookup_needs_distinct(self.lookup_opts, key))
            except FieldDoesNotExist, e:
                lookup_params.pop(key)