Home > OS >  Multiple search with django foreign key (Related Field got invalid lookup: icontains)
Multiple search with django foreign key (Related Field got invalid lookup: icontains)

Time:07-04

I understand that you can't directly use icontains on a foreign key when searching but I haven't found a solution yet.

Here is my search view in views.py (I have imported every model needed):

def search(request):
    # if the user actually fills up the form
    if request.method == "POST":
        searched = request.POST['searched']
        # author__icontains part is not working
        posts = Post.objects.filter(Q(title__icontains=searched) | Q(author__author__icontains=searched))

        return render(request, 'blog/search.html', {'searched': searched, 'posts': posts})
    else:
        return render(request, 'blog/search.html', {})

Here is my model in model.py:


class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

Mainly, this is not working:

        posts = Post.objects.filter(Q(title__icontains=searched) | Q(author__author__icontains=searched))

The error is Related Field got invalid lookup: icontains

CodePudding user response:

author is a User object. Therefore you should work with username, or first_name, or some other field. Likely author is also the value of a related_name=… [Django-doc] that thus makes a LEFT OUTER JOIN on another table, and thus would work on the primary key(s) of that table.

You thus filter with:

def search(request):
    # if the user actually fills up the form
    if request.method == 'POST':
        searched = request.POST['searched']
        # author__icontains part is not working
        posts = Post.objects.filter(
            Q(title__icontains=searched) |
            Q(author__username__icontains=searched)
        )

        return render(request, 'blog/search.html', {'searched': searched, 'posts': posts})
    return render(request, 'blog/search.html')

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Note: Searching is usually done through a GET rquest, since that means the query is stored in the querystring and thus the URL. This makes it convenient to for example share the URL with the query to someone else, or bookmark the result. POST requests are usually used for state-changing actions, or for requests with sensitive data.

CodePudding user response:

This problem is caused by Django's inability to handle foreign keys with multiple values for a single field. The reason for this limitation is that Django doesn't know how to resolve these conflicts, so it simply ignores them. In your case, since there are two fields in your model that match the search criteria, Django will ignore both of those results and display an empty list.

To fix this issue, we need to add a new attribute to our model called "icontains" which would contain the value of the other field. Then, we'll set this attribute as a default value for the "author" field when querying from the database. Here is what your model should look like now:

class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField() date_posted = models.DateTimeField(default=timezone.now) author = models.ForeignKey(User, on_delete=models.CASCADE) icontains = models.CharField(max_length=100, null=True, blank=True) def __str__(self): return self.title def get_absolute_url(self): return reverse('post-detail', kwargs=dict(pk=self.pk))

With this change, the code will work properly.

For more information about this limitation, see the Django documentation here: https://docs.djangoproject.com/en/1.9/topics/db/queries/#lookups-that-span-relationships

  • Related