'Django filter qs contains filename not working with underscores

my goal is to filter if the name of an uploaded document contains a search (a simple string from an input field submitted by the user). Strangely this works for long substring but not for short ones.

Example

My filter query is the following:

Tab.objects.filter(document__file__icontains=search)

where Tab is in simplest form a Model class like:

class Tab(models.Model):
    name = models.CharField(max_length=50)

and Document is another Model class wit a relation to Tabs and a file field.

class Document(models.Model):
    tab = models.ForeignKey(Tab, on_delete=models.CASCADE)
    file = models.FileField(upload_to=custom_location)

Weird behavior

I've uploaded a file called example_test_123.pdf and if my search = example_test or test_123.pdf it results in a hit like expected.

However, if search = test the filter doesn't find the file.

Is this behaviour known or am I missing something here? Is it possible that the built-in name file is doing some trouble?

Edit

  1. I changed file to document_file without success
  2. Even _test or test_ is working

Edit #2

@ Iain Shelvington (Comment)

This is no special function... only setting the subdirs the file should be saved

from django.utils.text import slugify

def custom_location(instance, filename):
    return os.path.join('documents', slugify(instance.tab.name), filename)

But your question is pointing me in the right direction for a workaround (thanks):

I'm doing an annotation before filtering. companies is in this case a ManyToManyField to another model:

tabs = Tab.objects.all().annotate(num_companies=Count('companies'))

and then filtering for some stuff like

tabs = tabs.filter(num_companies__gte=3)

Removing these lines results in a correct filtering. So I'm doing the annotations after filtering for the filename.

But I'm still curious what's happening here...

Thanks.

(Django 3.2.9 and Python 3.6.8)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source