1

I have a simple search box that searches for posts(filters post) by title, first_name, last_name, however no matter how hard I try I am not able to search by users full_name

In my models I have

User.full_name = property(lambda u: u"%s %s" % (u.first_name, u.last_name))

In my terminal Django Shell I get the below results

>>> user.first_name
'Blake'
>>> user.last_name
'Lively'
>>> user.full_name
'Blake Lively'

Now when I try searching with the users full_name I get the below error

Related Field got invalid lookup: full_name

Q(user__full_name__icontains=query)

Below are my views

class QList(SelectRelatedMixin, ListView):
    model = Question
    select_related = ('user', 'group')
    template_name = 'questions/all_questions.html'
    context_object_name = 'all_questions'
    paginate_by = 5

    def get_queryset(self):
        queryset = super(QList, self).get_queryset().order_by('-created_at')
        query = self.request.GET.get('q')
        if query:
            queryset = queryset.filter(
                Q(title__icontains=query) | #This works
                Q(user__username__iexact=query) | #This works
                Q(user__first_name__iexact=query) | #This works
                Q(user__last_name__iexact=query) | #This works
                Q(user__full_name__icontains=query) #This Fails what am I doing worng

                )
        return queryset

Tried this

class QList(SelectRelatedMixin, ListView):
    model = Question
    select_related = ('user', 'group')
    template_name = 'questions/all_questions.html'
    context_object_name = 'all_questions'
    paginate_by = 5

    def get_queryset(self):
        queryset = super(QList, self).get_queryset().order_by('-created_at')
        query = self.request.GET.get('q')

        if ' ' in query:
            query = query.split()
            queryset = queryset.filter(
                chain(User.objects.filter(first_name__icontains=query[0], last_name__icontains=query[1]),
                      User.objects.filter(first_name__icontains=query[1], last_name__icontains=query[0])))

            return queryset
        else:
            queryset = queryset.filter(
                Q(title__icontains=query) |
                Q(user__username__iexact=query) |
                Q(user__first_name__iexact=query) |
                Q(user__last_name__iexact=query)

                )
        return queryset

Getting error

argument of type 'NoneType' is not iterable

if ' ' in query:
Samir Tendulkar
  • 1,151
  • 3
  • 19
  • 47
  • 1
    Can you show model User. If its only property, you cant filter backend it – Ngoc Pham Apr 02 '19 at 01:31
  • @NgocPham Its the django default user model – Samir Tendulkar Apr 02 '19 at 01:33
  • Ivan's answer in the [question you mentioned](https://stackoverflow.com/questions/46688826/django-having-q-object-filter-by-function-in-model) provides exactly what you need (even the field names are the same). What problems do you have with that approach? – Endre Both Apr 02 '19 at 06:03
  • Possible duplicate of [Django, having Q object filter by function in model](https://stackoverflow.com/questions/46688826/django-having-q-object-filter-by-function-in-model) – Endre Both Apr 02 '19 at 06:04

2 Answers2

4

Using filter() with a property like that is not possible, for filter to work it must be a model field.

Check this thread to see some possible workarounds using managers or annotations.

Edit for the new error:

Your query = self.request.GET.get('q') is returning None when there is no q, and you can't check for something in None. Change that line to query = self.request.GET.get('q', '') so if there is no q, it defaults to the empty string.

gdef_
  • 1,888
  • 9
  • 17
  • Do you think you type a workaround that would work around my code. I looked at this question https://stackoverflow.com/questions/46688826/django-having-q-object-filter-by-function-in-model. But could not integrate it to my code – Samir Tendulkar Apr 02 '19 at 01:50
  • @MarcoBianchi i updated my answer taking into account the new error – gdef_ Apr 02 '19 at 13:16
2

Thanks to @gdef_ The below code did the job

class QList(SelectRelatedMixin, ListView):
    model = Question
    select_related = ('user', 'group')
    template_name = 'questions/all_questions.html'
    context_object_name = 'all_questions'
    paginate_by = 5

    def get_queryset(self):
        queryset = super(QList, self).get_queryset().order_by('-created_at')
        query = self.request.GET.get('q', None)

        if query:
            queryset = queryset.annotate(
                full_name=Concat(
                    'user__first_name',
                    Value(' '),
                    'user__last_name',
                    output_field=CharField()
                )
            ).filter(
                Q(full_name__icontains=query) |
                Q(title__icontains=query) |
                Q(user__username__iexact=query) |
                Q(user__first_name__iexact=query) |
                Q(user__last_name__iexact=query)

                )
        return queryset
Samir Tendulkar
  • 1,151
  • 3
  • 19
  • 47