Пример #1
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        for key, value in lookup_params.items():
            if not self.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 = list_filter
                        field_list_filter_class = 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.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.opts, key))
            return (filter_specs, bool(filter_specs), lookup_params,
                    use_distinct)
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters from e
Пример #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, 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])
Пример #3
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        for key, value in lookup_params.items():
            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]

                    lookup_params_count = len(lookup_params)
                    spec = field_list_filter_class(
                        field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path
                    )
                    # field_list_filter_class removes any lookup_params it
                    # processes. If that happened, check if distinct() is
                    # needed to remove duplicate results.
                    if lookup_params_count > len(lookup_params):
                        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:
            raise IncorrectLookupParameters(e) from e
Пример #4
0
    def get_filters(self):
        params = dict(self.request.GET.items())
        opts = self.model._meta
        use_distinct = False
        list_filters = self.get_list_filters()
        new_params = {}
        has_filters = False

        # Normalize the types of keys
        list_names = [f if isinstance(f, str) else f.parameter_name for f in list_filters]
        for key, value in params.items():
            # ignore keys not in list_filters
            if key.startswith(tuple(list_names)):
                new_params[force_str(key)] = value

        has_filters = bool(new_params)
        filter_specs = []
        for list_filter in list_filters:
            if callable(list_filter):
                # This is simply a custom list filter class.
                spec = list_filter(self.request, new_params, self.model, None)
            else:
                field_path = None
                if isinstance(list_filter, (tuple, list)):
                    # Custom FieldListFilter class for a given field.
                    field, field_list_filter_class = list_filter
                else:
                    # Field name, so use the default registered FieldListFilter
                    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]
                model_admin = admin.ModelAdmin(self.model, admin.site)
                spec = field_list_filter_class(field, self.request, new_params, self.model, model_admin, field_path=field_path)
                # Check if we need to use distinct()
                use_distinct = (use_distinct or lookup_needs_distinct(opts, field_path))
            if spec and spec.has_output():
                filter_specs.append(spec)

        # All the parameters used by the various ListFilters have been removed
        # lookup_params, 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 new_params.items():
                new_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or lookup_needs_distinct(opts, key))
            return filter_specs, has_filters, use_distinct
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters from e
Пример #5
0
    def filter_queryset(self,
                        request,
                        term,
                        queryset=None,
                        **dependent_fields):
        """
        Return QuerySet filtered by search_fields matching the passed term.

        Args:
            request (django.http.request.HttpRequest): The request is being passed from
                the JSON view and can be used to dynamically alter the response queryset.
            term (str): Search term
            queryset (django.db.models.query.QuerySet): QuerySet to select choices from.
            **dependent_fields: Dependent fields and their values. If you want to inherit
                from ModelSelect2Mixin and later call to this method, be sure to pop
                everything from keyword arguments that is not a dependent field.

        Returns:
            QuerySet: Filtered QuerySet

        """
        if queryset is None:
            queryset = self.get_queryset()
        search_fields = self.get_search_fields()
        select = Q()

        use_distinct = False
        if search_fields and term:
            for bit in term.split():
                or_queries = [
                    Q(**{orm_lookup: bit}) for orm_lookup in search_fields
                ]
                select &= reduce(operator.or_, or_queries)
            or_queries = [
                Q(**{orm_lookup: term}) for orm_lookup in search_fields
            ]
            select |= reduce(operator.or_, or_queries)
            use_distinct |= any(
                lookup_needs_distinct(queryset.model._meta, search_spec)
                for search_spec in search_fields)

        if dependent_fields:
            select &= Q(**dependent_fields)

        use_distinct |= any(
            lookup_needs_distinct(queryset.model._meta, search_spec)
            for search_spec in dependent_fields.keys())

        if use_distinct:
            return queryset.filter(select).distinct()
        return queryset.filter(select)
    def get_search_results(self, queryset, search_term):
        """Filter the results based on the query."""
        search_fields = self.get_search_fields()
        if search_fields and search_term:
            orm_lookups = [
                self._construct_search(search_field) for search_field in search_fields
            ]
            if self.split_words is not None:
                word_conditions = []
                for word in search_term.split():
                    or_queries = [Q(**{orm_lookup: word}) for orm_lookup in orm_lookups]
                    word_conditions.append(reduce(operator.or_, or_queries))
                op_ = operator.or_ if self.split_words == "or" else operator.and_
                queryset = queryset.filter(reduce(op_, word_conditions))
            else:
                or_queries = [
                    Q(**{orm_lookup: search_term}) for orm_lookup in orm_lookups
                ]
                queryset = queryset.filter(reduce(operator.or_, or_queries))

            if any(
                lookup_needs_distinct(queryset.model._meta, search_spec)
                for search_spec in orm_lookups
            ):
                queryset = queryset.distinct()

        return queryset
Пример #7
0
    def _search(self, queryset):
        # Originally from django.contrib.admin.options
        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
        search_fields = self.search_fields
        search_term = self.data.get(SEARCH_FIELD, '') if self.data else ''
        opts = self.model._meta
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            for bit in search_term.split():
                or_queries = [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(opts, search_spec):
                        use_distinct = True
                        break
        return queryset, use_distinct
Пример #8
0
    def get_search_results(self, request, queryset, search_term):
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__iexact" % field_name

        use_distinct = False
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field)) for search_field in search_fields]

            for bit in search_term.split():
                or_queries = [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
Пример #9
0
    def get_search_results(self, request, queryset, search_term):
        """
        Adapted from the defaulf implementation in django.contrib.admin.options,
        this get_search_results does not split the search term into tokens.
        """
        # 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
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            or_queries = [models.Q(**{orm_lookup: search_term})
                          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
Пример #10
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
Пример #11
0
    def get_search_results(self, queryset, search_term):
        """
        Generate a queryset according to the search term. Words in the search term are searched using the OR operator
        :param queryset: queryset to filter
        :param search_term: search string
        :return: tuple (queryset, distinct), distinct will be True if queryset is likely to contain duplicates
        """
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "{}__istartswith".format(field_name[1:])
            elif field_name.startswith('='):
                return "{}__iexact".format(field_name[1:])
            elif field_name.startswith('@'):
                return "{}__search".format(field_name[1:])
            else:
                return "{}__icontains".format(field_name)

        opts = queryset.model._meta
        search_fields = self.get_list_search()
        use_distinct = False
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field)) for search_field in search_fields]
            queryset = queryset.filter(
                reduce(operator.or_, [
                    models.Q(**{orm_lookup: bit}) for bit in search_term.split() for orm_lookup in orm_lookups
                ])
            )
            use_distinct = any(lookup_needs_distinct(opts, search_spec) for search_spec in orm_lookups)
        return queryset, use_distinct
Пример #12
0
    def _search(self, queryset):
        # Originally from django.contrib.admin.options
        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
        search_fields = self.search_fields
        search_term = self.data.get(SEARCH_FIELD, '') if self.data else ''
        opts = self.model._meta
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            for bit in search_term.split():
                or_queries = [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(opts, search_spec):
                        use_distinct = True
                        break
        return queryset, use_distinct
Пример #13
0
    def get_search_results(self, request, queryset, search_term):
        """
        Copy-paste of https://github.com/django/django/blob/1.8.4/django/contrib/admin/options.py#L965-L996
        Replace models.Q with mongoengine's Q
        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
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            for bit in search_term.split():
                or_queries = [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
Пример #14
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
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            for bit in search_term.split():
                or_queries = [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
Пример #15
0
    def queryset(self, request, queryset):
        from_option = self._values[0]
        if from_option and from_option != "" and from_option != "''":
            lookup = '%s__gte' % self.field_path
            if lookup_needs_distinct(self.model._meta, lookup):
                queryset = queryset.distinct()
            queryset = queryset.filter(**{lookup: from_option})

        to_option = self._values[1]
        if to_option and to_option != "" and to_option != "''":
            lookup = '%s__lte' % self.field_path
            if lookup_needs_distinct(self.model._meta, lookup):
                queryset = queryset.distinct()
            queryset = queryset.filter(**{lookup: to_option})

        return queryset
Пример #16
0
 def queryset(self, request, queryset):
     search_option = self._values[0]
     if search_option and search_option != []:
         lookup = '%s%s__in' % (self.field_path, '_id')
         if lookup_needs_distinct(self.model._meta, lookup):
             queryset = queryset.distinct()
         queryset = queryset.filter(**{lookup: search_option})
     return queryset
Пример #17
0
def annotation_friendly_search_results(self, request, queryset, search_term):  # noqa
    """
    - fully copied from django.... used nested select insteed of classic one
    - should be used if search is made by FK for example: userprofile__telephone...
    - why? because if not, django joins search tables and annotation result is multiplicated :(
    - see below
    """
    # 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:]
        # Use field_name if it includes a lookup.
        opts = queryset.model._meta
        lookup_fields = field_name.split(LOOKUP_SEP)
        # Go through the fields, following all relations.
        prev_field = None
        for path_part in lookup_fields:
            if path_part == "pk":
                path_part = opts.pk.name
            try:
                field = opts.get_field(path_part)
            except FieldDoesNotExist:
                # Use valid query lookups.
                if prev_field and prev_field.get_lookup(path_part):
                    return field_name
            else:
                prev_field = field
                if hasattr(field, "get_path_info"):
                    # Update opts to follow the relation.
                    opts = field.get_path_info()[-1].to_opts
        # Otherwise, use the field with icontains.
        return "%s__icontains" % field_name

    use_distinct = False
    search_fields = self.get_search_fields(request)
    if search_fields and search_term:
        orm_lookups = [
            construct_search(str(search_field)) for search_field in search_fields
        ]
        for bit in search_term.split():
            or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups]
            # THIS IS CHANGED!!!!
            # queryset = queryset.filter(reduce(operator.or_, or_queries))
            filtered_ids = self.model.objects.filter(
                reduce(operator.or_, or_queries)
            ).values_list("id", flat=True)
            queryset = queryset.filter(id__in=filtered_ids)
            # ^^^^^^^
        use_distinct |= any(
            lookup_needs_distinct(self.opts, search_spec) for search_spec in orm_lookups
        )

    return queryset, use_distinct
Пример #18
0
    def get_search_results(self, request, queryset, search_fields,
                           search_term):
        """
        Return a tuple containing a queryset to implement the search
        and a boolean indicating if the results may contain duplicates.
        """

        # override ModelAdmin.get_search_results to use a custom search_fields

        # 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:]
            # Use field_name if it includes a lookup.
            opts = queryset.model._meta
            lookup_fields = field_name.split(LOOKUP_SEP)
            # Go through the fields, following all relations.
            prev_field = None
            for path_part in lookup_fields:
                if path_part == "pk":
                    path_part = opts.pk.name
                try:
                    field = opts.get_field(path_part)
                except FieldDoesNotExist:
                    # Use valid query lookups.
                    if prev_field and prev_field.get_lookup(path_part):
                        return field_name
                else:
                    prev_field = field
                    if hasattr(field, "get_path_info"):
                        # Update opts to follow the relation.
                        opts = field.get_path_info()[-1].to_opts
            # Otherwise, use the field with icontains.
            return "%s__icontains" % field_name

        use_distinct = False
        if search_fields and search_term:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in 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))
            use_distinct |= any(
                lookup_needs_distinct(queryset.model._meta, search_spec)
                for search_spec in orm_lookups)

        return queryset, use_distinct
Пример #19
0
 def queryset(self, request, queryset):
     search_option = self._values[0]
     if search_option and search_option != '':
         lookup = '%s__exact' % self.field_path
         if lookup_needs_distinct(self.model._meta, lookup):
             queryset = queryset.distinct()
         if search_option == "True":
             queryset = queryset.filter(**{lookup: True})
         if search_option == "False":
             queryset = queryset.filter(**{lookup: False})
     return queryset
Пример #20
0
 def queryset(self, request, queryset):
     search_terms = self._values[0]
     if search_terms and search_terms != '':
         lookup = '%s__icontains' % self.field_path
         if lookup_needs_distinct(self.model._meta, lookup):
             queryset = queryset.distinct()
         for bit in search_terms.split():
             if bit.startswith('!'):
                 queryset = queryset.exclude(**{lookup: bit[1:]})
             else:
                 queryset = queryset.filter(**{lookup: bit})
     return queryset
Пример #21
0
    def queryset(self, request, queryset):
        from_option = self._values[0]
        if from_option:
            if isinstance(from_option, text_type):
                from_option = parse_date(from_option)
            if from_option:
                lookup = '%s__gte' % self.field_path
                if lookup_needs_distinct(self.model._meta, lookup):
                    queryset = queryset.distinct()
                queryset = queryset.filter(**{lookup: from_option})

        to_option = self._values[1]
        if to_option:
            if isinstance(to_option, text_type):
                to_option = parse_date(to_option)
            if to_option:
                lookup = '%s__lte' % self.field_path
                if lookup_needs_distinct(self.model._meta, lookup):
                    queryset = queryset.distinct()
                queryset = queryset.filter(**{lookup: to_option})

        return queryset
Пример #22
0
    def get_search_results(self, request, queryset, search_term):

        # 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:]
            # Use field_name if it includes a lookup.
            opts = queryset.model._meta
            lookup_fields = field_name.split(LOOKUP_SEP)
            # Go through the fields, following all relations.
            prev_field = None
            for path_part in lookup_fields:
                if path_part == 'pk':
                    path_part = opts.pk.name
                try:
                    field = opts.get_field(path_part)
                except FieldDoesNotExist:
                    # Use valid query lookups.
                    if prev_field and prev_field.get_lookup(path_part):
                        return field_name
                else:
                    prev_field = field
                    if hasattr(field, 'get_path_info'):
                        # Update opts to follow the relation.
                        opts = field.get_path_info()[-1].to_opts
            # Otherwise, use the field with icontains.
            return "%s__icontains" % field_name

        query_field_params = request.GET.get('f', None)

        use_distinct = False
        search_fields = self.get_search_fields(request)
        if search_fields and search_term and query_field_params in search_fields:
            # orm_lookups = [construct_search(str(search_field))
            #                for search_field in search_fields]
            orm_lookups = [construct_search(str(query_field_params))]
            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))
            use_distinct |= any(
                lookup_needs_distinct(self.opts, search_spec)
                for search_spec in orm_lookups)

        return queryset, use_distinct
Пример #23
0
    def search_queryset(self, queryset, search_term, **kwargs):
        if not search_term or not self.search_fields:
            return queryset

        orm_lookups = ['%s__icontains' % str(search_field)
                       for search_field in self.search_fields]
        for bit in search_term.split():
            or_queries = [Q(**{orm_lookup: bit})
                          for orm_lookup in orm_lookups]
            queryset = queryset.filter(reduce(operator.or_, or_queries))
        opts = queryset.model._meta
        for search_spec in orm_lookups:
            if lookup_needs_distinct(opts, search_spec):
                return queryset.distinct()
        return queryset
Пример #24
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

        # Group using quotes
        def unescape_string_literal_if_possible(bit):
            try:
                return unescape_string_literal(bit)
            except ValueError:
                return bit

        use_distinct = False
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            search_term_list = [
                unescape_string_literal_if_possible(bit)
                for bit in smart_split(search_term)
            ]
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in search_fields
            ]
            for bit in search_term_list:
                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
Пример #25
0
def buscador(request, queryset, search_term='arroz'):
    return HttpResponse(request.GET['selec-model'])
    model = request.GET['selec-model']()
    search = request.GET['q']
    queryset = model.objects.all()
    """
        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
    search_fields = 'nombre'  #get_search_fields(request)
    if search_fields and search_term:
        #orm_lookups = [construct_search(str(search_field))
        #               for search_field in search_fields]
        orm_lookups = [construct_search(str(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(opts, search_spec):
                    use_distinct = True
                    break
    for i in queryset:
        print i.nombre.upper()
        print i.nombre_cientifico.upper()

    return HttpResponse(queryset, use_distinct)
Пример #26
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.
        """
        use_distinct = False
        if self.search_fields and search_term:
            orm_lookups = ['%s__icontains' % 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
Пример #27
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.
        """
        use_distinct = False
        if self.search_fields and search_term:
            orm_lookups = ['%s__icontains' % 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
Пример #28
0
    def get_search_results(self, request, queryset, search_term):
        # 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__istartswith" % field_name  # 优化级别1
                # 优化级别2 暂时用不到 使用__istartswith
                # 优化级别3 暂时用不到 使用__iexact  会产生一个id相关的bug, 可调

        use_distinct = False
        search_fields = self.get_search_fields(request)
        search_term = search_term.strip()
        if search_fields and search_term:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in search_fields
            ]

            # 优化or语句为多条sql, 获取每个条件的id list
            ids = []
            for orm_lookup in orm_lookups:
                bit_ids = queryset.filter(**{
                    orm_lookup: search_term
                }).values_list('id', flat=True)
                ids.extend(bit_ids)
            queryset = queryset.filter(id__in=ids)

            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
Пример #29
0
    def get_search_results(self, request, queryset, search_term):
        """
        Copy-paste of https://github.com/django/django/blob/1.8.4/django/contrib/admin/options.py#L965-L996
        Replace models.Q with mongoengine's Q
        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
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in search_fields
            ]
            for bit in search_term.split():
                or_queries = [
                    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
Пример #30
0
    def get_search_results(self, request, queryset, search_term):
        """
        Adapted from the defaulf implementation in django.contrib.admin.options,
        this get_search_results does not split the search term into tokens.
        """

        # 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
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in search_fields
            ]
            or_queries = [
                models.Q(**{orm_lookup: search_term})
                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
Пример #31
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([
            (smart_str(k)[len(FILTER_PREFIX):], v)
            for k, v in self.admin_view.params.items()
            if smart_str(k).startswith(FILTER_PREFIX) and v != ''
        ])
        for p_key, p_val in iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(
            remove=[
                k for k in self.request.GET.keys()
                if k.startswith(FILTER_PREFIX)
            ])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation("Filtering by %s not allowed" %
                                              key)

        self.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(self.request, lookup_params, self.model,
                                       self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(field,
                                                   self.request,
                                                   lookup_params,
                                                   self.model,
                                                   self.admin_view,
                                                   field_path=field_path)

                    if len(field_parts) > 1:
                        # Add related model name to title
                        spec.title = "%s %s" % (field_parts[-2].name,
                                                spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError as e:
                        new_qs = None
                        self.admin_view.message_user(
                            _("<b>Filtering error:</b> %s") % e.messages[0],
                            'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        obj = filter(lambda f: f.is_used, self.filter_specs)
        if six.PY3:
            obj = list(obj)
        self.admin_view.used_filter_num = len(obj)

        try:
            for key, value in lookup_params.items():
                use_distinct = (use_distinct
                                or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)

        try:
            # fix a bug by david: In demo, quick filter by IDC Name() cannot be used.
            if isinstance(queryset, models.query.QuerySet) and lookup_params:
                new_lookup_parames = dict()
                for k, v in lookup_params.iteritems():
                    list_v = v.split(',')
                    if len(list_v) > 0:
                        new_lookup_parames.update({k: list_v})
                    else:
                        new_lookup_parames.update({k: v})
                queryset = queryset.filter(**new_lookup_parames)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)
        else:
            if not isinstance(queryset, models.query.QuerySet):
                pass

        query = self.request.GET.get(SEARCH_VAR, '')

        # 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 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
                ]
                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
            self.admin_view.search_query = query

        if use_distinct:
            return queryset.distinct()
        else:
            return queryset
Пример #32
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

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

        filter_specs = []
        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]

                lookup_params_count = len(lookup_params)
                spec = field_list_filter_class(
                    field,
                    request,
                    lookup_params,
                    self.model,
                    self.model_admin,
                    field_path=field_path,
                )
                # field_list_filter_class removes any lookup_params it
                # processes. If that happened, check if distinct() is needed to
                # remove duplicate results.
                if lookup_params_count > len(lookup_params):
                    use_distinct = use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path)
            if spec and spec.has_output():
                filter_specs.append(spec)

        if self.date_hierarchy:
            # Create bounded lookup parameters so that the query is more
            # efficient.
            year = lookup_params.pop('%s__year' % self.date_hierarchy, None)
            if year is not None:
                month = lookup_params.pop('%s__month' % self.date_hierarchy,
                                          None)
                day = lookup_params.pop('%s__day' % self.date_hierarchy, None)
                try:
                    from_date = datetime(
                        int(year),
                        int(month if month is not None else 1),
                        int(day if day is not None else 1),
                    )
                except ValueError as e:
                    raise IncorrectLookupParameters(e) from e
                if settings.USE_TZ:
                    from_date = make_aware(from_date)
                if day:
                    to_date = from_date + timedelta(days=1)
                elif month:
                    # In this branch, from_date will always be the first of a
                    # month, so advancing 32 days gives the next month.
                    to_date = (from_date + timedelta(days=32)).replace(day=1)
                else:
                    to_date = from_date.replace(year=from_date.year + 1)
                lookup_params.update({
                    '%s__gte' % self.date_hierarchy: from_date,
                    '%s__lt' % self.date_hierarchy: to_date,
                })

        # 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:
            raise IncorrectLookupParameters(e) from e
    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.
        """
        # BEGIN CUSTOMIZATION #
        search_terms = self.get_search_terms(search_term)

        # END CUSTOMIZATION #

        # 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
        search_fields = self.get_search_fields(request)

        # BEGIN CUSTOMIZATION #
        if search_terms:
            for search_term in search_terms:
                qs = self.model.objects.none()  # Create an empty queryset
                # END CUSTOMIZATION #
                if search_fields and search_term:
                    orm_lookups = [
                        construct_search(str(search_field))
                        for search_field in search_fields
                    ]
                    for bit in search_term.split():
                        or_queries = [
                            models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                        ]

                        # BEGIN CUSTOMIZATION #
                        qs |= self.get_method_for_queryset(queryset)(
                            reduce(operator.or_, or_queries)
                        )
                        # END CUSTOMIZATION #

                    if not use_distinct:
                        for search_spec in orm_lookups:
                            if lookup_needs_distinct(self.opts, search_spec):
                                use_distinct = True
                                break

        # BEGIN CUSTOMIZATION #
        else:
            qs = queryset
        if hasattr(self, "filter_class") and hasattr(self, "filterset_params"):
            kwargs = {"request": request, "queryset": qs, "passed_validation": True}
            if issubclass(self.filter_class, SemanticExcludeAllFilterSet):
                kwargs["exclude"] = self.filterset_exclude
            filterset = self.filter_class(self.filterset_params, **kwargs)
            try:
                filterset = self.filter_class(self.filterset_params, **kwargs)
            except Exception:
                pass
            else:
                self.filterset = filterset
                qs = filterset.qs
        # END CUSTOMIZATION #
        return qs, use_distinct
Пример #34
0
                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]
                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
            self.admin_view.search_query = query

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

    # Media
    def get_media(self, media):
        if bool(filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs)):
            media = media + self.vendor('datepicker.css', 'datepicker.js',
                                        'xadmin.widget.datetime.js')
        if bool(filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs)):
Пример #35
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 & functools.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_generic_field(model, field_name):
            """
            Find the given generic_field name in the given model and verify
            it is a GenericForeignKey, otherwise raise an Exeption.
            """
            for f in model._meta.virtual_fields:
                if f.name == field_name:
                    if not isinstance(f, GenericForeignKey):
                        raise Exception('Given field %s is not an instance of '
                                        'GenericForeignKey' % field_name)
                    return f

        def get_object_id(model, generic_field):
            """
            Return the foreign key field for a given GenericForeignKey
            in a given model
            """
            self.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
            """
            self.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:
                        self.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):
                    if issubclass(ctypes[0], django.db.models.Model):
                        return ctypes
                    else:
                        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>")

            or_queries = []
            for rel_field, fields in fields_mapping.items():
                query = generate_q_object(fields)
                if not query:
                    self.logger.warn('No Q instance returned')
                    continue
                cont_type = (
                    self.related_search_mapping[rel_field].get('content_type'))
                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:

                    result = model.objects.filter(query).values_list('pk',
                                                                     flat=True)

                    or_queries.append(
                        Q(**{'%s__in' % obj_id: result}) & Q(
                            **{
                                '%s' % cont_type:
                                ContentType.objects.get_for_model(model)
                            }))
            return or_queries

        use_distinct = False
        if not search_term:
            return queryset, use_distinct

        non_generic_fields, generic_fields = parse_related_fields()
        related_query = 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]
            or_queries = or_queries + related_query

            query = functools.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
Пример #36
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in lookup_params.iteritems():
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=
                                                                           [k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts)>1:
                        # Add related model name to title
                        spec.title = "%s %s"%(field_parts[-2].name,spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError, e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)
Пример #37
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=[k for k in self.request.GET.keys() if
                                                                                   k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts) > 1:
                        # Add related model name to title
                        spec.title = "%s %s" % (field_parts[-2].name, spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError as e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        obj = filter(lambda f: f.is_used, self.filter_specs)
        if six.PY3:
            obj = list(obj)
        self.admin_view.used_filter_num = len(obj)

        try:
            for key, value in lookup_params.items():
                use_distinct = (
                    use_distinct or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)

        try:
            # fix a bug by david: In demo, quick filter by IDC Name() cannot be used.
            if isinstance(queryset, models.query.QuerySet) and lookup_params:
                new_lookup_parames = dict()
                for k, v in lookup_params.items():
                    list_v = v.split(',')
                    if len(list_v) > 0:
                        new_lookup_parames.update({k: list_v})
                    else:
                        new_lookup_parames.update({k: v})
                queryset = queryset.filter(**new_lookup_parames)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)
        else:
            if not isinstance(queryset, models.query.QuerySet):
                pass

        query = self.request.GET.get(SEARCH_VAR, '')

        # 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 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]
                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
            self.admin_view.search_query = query

        if use_distinct:
            return queryset.distinct()
        else:
            return queryset
Пример #38
0
                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]
                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
            self.admin_view.search_query = query

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

    # Media
    def get_media(self, media):
        if bool(filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs)):
            media = media + self.vendor('datepicker.css', 'datepicker.js',
                                        'xadmin.widget.datetime.js')
        if bool(filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs)):
Пример #39
0
class FilterPlugin(BaseAdminPlugin):
    list_filter = ()
    search_fields = ()
    free_query_filter = True

    def lookup_allowed(self, lookup, value):
        model = self.model
        # Check FKey lookups that are allowed, so that popups produced by
        # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to,
        # are allowed to work.
        for l in model._meta.related_fkey_lookups:
            for k, v in widgets.url_params_from_lookup_dict(l).items():
                if k == lookup and v == value:
                    return True

        parts = lookup.split(LOOKUP_SEP)

        # Last term in lookup is a query term (__exact, __startswith etc)
        # This term can be ignored.
        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
            parts.pop()

        # Special case -- foo__id__exact and foo__id queries are implied
        # if foo has been specificially included in the lookup list; so
        # drop __id if it is the last part. However, first we need to find
        # the pk attribute name.
        rel_name = None
        for part in parts[:-1]:
            try:
                field = model._meta.get_field(part)
            except FieldDoesNotExist:
                # Lookups on non-existants fields are ok, since they're ignored
                # later.
                return True
            if hasattr(field, 'rel'):
                model = field.rel.to
                rel_name = field.rel.get_related_field().name
            elif is_related_field(field):
                model = field.model
                rel_name = model._meta.pk.name
            else:
                rel_name = None
        if rel_name and len(parts) > 1 and parts[-1] == rel_name:
            parts.pop()

        if len(parts) == 1:
            return True
        clean_lookup = LOOKUP_SEP.join(parts)
        return clean_lookup in self.list_filter

    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in lookup_params.iteritems():
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=
                                                                           [k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts)>1:
                        # Add related model name to title
                        spec.title = "%s %s"%(field_parts[-2].name,spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError, e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        self.admin_view.used_filter_num = len(
            filter(lambda f: f.is_used, self.filter_specs))

        try:
            for key, value in lookup_params.items():
                use_distinct = (
                    use_distinct or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist, e:
            raise IncorrectLookupParameters(e)
Пример #40
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

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

        filter_specs = []
        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]

                lookup_params_count = len(lookup_params)
                spec = field_list_filter_class(
                    field, request, lookup_params,
                    self.model, self.model_admin, field_path=field_path,
                )
                # field_list_filter_class removes any lookup_params it
                # processes. If that happened, check if distinct() is needed to
                # remove duplicate results.
                if lookup_params_count > len(lookup_params):
                    use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, field_path)
            if spec and spec.has_output():
                filter_specs.append(spec)

        if self.date_hierarchy:
            # Create bounded lookup parameters so that the query is more
            # efficient.
            year = lookup_params.pop('%s__year' % self.date_hierarchy, None)
            if year is not None:
                month = lookup_params.pop('%s__month' % self.date_hierarchy, None)
                day = lookup_params.pop('%s__day' % self.date_hierarchy, None)
                try:
                    from_date = datetime(
                        int(year),
                        int(month if month is not None else 1),
                        int(day if day is not None else 1),
                    )
                except ValueError as e:
                    raise IncorrectLookupParameters(e) from e
                if settings.USE_TZ:
                    from_date = make_aware(from_date)
                if day:
                    to_date = from_date + timedelta(days=1)
                elif month:
                    # In this branch, from_date will always be the first of a
                    # month, so advancing 32 days gives the next month.
                    to_date = (from_date + timedelta(days=32)).replace(day=1)
                else:
                    to_date = from_date.replace(year=from_date.year + 1)
                lookup_params.update({
                    '%s__gte' % self.date_hierarchy: from_date,
                    '%s__lt' % self.date_hierarchy: to_date,
                })

        # 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:
            raise IncorrectLookupParameters(e) from e
Пример #41
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in lookup_params.iteritems():
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=
                                                                           [k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts)>1:
                        # Add related model name to title
                        spec.title = "%s %s"%(field_parts[-2].name,spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError, e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)