想要在搜索查询中添加功能以按任意列字段进行搜索,当前按名称进行搜索

时间:2019-07-10 08:51:59

标签: django-views

我想在搜索查询中添加功能以按任何列字段进行搜索。目前,搜索是按名称进行的。

我该怎么做?

Views.py

class ApplicationList(APIView):
    permission_classes = (IsAuthenticated,)

    # parser_classes = (JSONParser,)

    def post(self, request, format=None):
        # Get a list of fields dynamically
        fields = list()
        for f in Application._meta.fields:
            if f.is_relation:
                continue
            fields.append(f.name)

        queryset = Application.objects_with_sprint_name.all()

        # Looking for a specific bubble?
        if 'bubble' in request.data:
            if request.data['bubble'] == '4-1':
                queryset = queryset.filter(assessment_phase__id=request.data['bubble']).exclude(attributes__contains={'application_disposition':'Removed'})
            else:
                queryset = queryset.filter(assessment_phase__id=request.data['bubble'])

        # Providing a search query?
        if 'search' in request.data:
            q_search = request.data['search']

            # Build the query
            q = get_query(q_search, fields)
            queryset = queryset.filter(q)

        if 'filter' in request.data:
            q = get_filter(request.data['filter'])
            if q:
                queryset = queryset.filter(q)

        page = int(request.data.get('page', 1))
        per_page = int(request.data.get('per_page', 25))

        # Sorting
        sort_by = request.data.get('sort_by', 'name') or 'name'
        sort_dir = request.data.get('sort_dir', 'asc') or 'asc'

        if sort_dir == 'desc':
            sort_dir = '-'
        else:
            sort_dir = ''

        # Is this an actual field or do we need to sort by the attributes__*?
        if sort_by not in fields:
            sort_by = 'attributes__' + sort_by

        queryset = queryset.order_by('{0}{1}'.format(sort_dir, sort_by))

        # Do a little data massaging
        untreated_data = queryset.values()

        data = list()
        for app in untreated_data:
            this_app = {}
            for k, v in app.items():
                if k == 'attributes':
                    continue
                if k == 'sprint_name':
                    this_app[k] = v
                    this_app['sprint'] = v
                    continue

                this_app[k] = v
            this_app.update(app['attributes'])

            data.append(this_app)

        start = (page-1) * per_page
        end = (page) * per_page

        response = {
            'total_rows': len(data),
            'data': data[start:end],
        }
        return Response(response)

#Util.py

def normalize_query(query_string,
                    findterms=re.compile(r'r'""([^"]+)"|(\S+)').findall,
                    normspace=re.compile(r'\s{2,}').sub):
    ''' Splits the query string in invidual keywords, getting rid of unnecessary spaces
        and grouping quoted words together.
        Example:

        >>> normalize_query('  some random  words "with   quotes  " and   spaces')
        ['some', 'random', 'words', 'with quotes', 'and', 'spaces']

    '''
    return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)]


def get_query(query_string, search_fields):
    ''' Returns a query, that is a combination of Q objects. That combination
        aims to search keywords within a model by testing the given search fields.

    '''
    query = None  # Query to search for every search term
    terms = normalize_query(query_string)
    for term in terms:
        or_query = None  # Query to search for a given term in each field
        for field_name in search_fields:
            q = Q(**{"%s__icontains" % field_name: term})
            if or_query is None:
                or_query = q
            else:
                or_query = or_query | q
        if query is None:
            query = or_query
        else:
            query = query & or_query
    return query


def get_filter(filter_dict):
    available_fields = [ field.name for field in Application._meta.fields ] \
                       + ApplicationManager.annotated_fields

    query = None
    if filter_dict is None:
        return query

    for field_name, val in filter_dict.items():
        query_field = field_name

        # Quicksearch box
        if field_name == '_quicksearch_':
            q = Q(name__icontains=val)

            if query is None:
                query = q
            else:
                query = query & q

            continue

        # Figure out if this field is part of the model
        # or in the attributes json field
        if query_field not in available_fields:
            query_field = 'attributes__{0}'.format(query_field)

        if isinstance(val, list):
            q = None

            # Are we looking for null or blank?
            if '#is_null_or_blank#' in val:
                val.remove('#is_null_or_blank#')
                q = Q(**{"%s__isnull" % query_field: True}) | \
                    Q(**{query_field: ''}) | \
                    Q(**{query_field: []})

            # Loop through the list and create some "OR" expressions
            for v in val:
                tmp = Q(**{"%s__contains" % query_field: v})
                if q is None:
                    q = tmp
                q = q | tmp

        elif val.startswith('#bool#'):
            bval = val[6:].lower() == 'true'
            q = Q(**{"%s" % query_field: bval})
        else:
            q = Q(**{"%s__icontains" % query_field: val})

        # Add to our master query of all fields
        if query is None:
            query = q
        else:
            query = query & q

    return query

0 个答案:

没有答案