sadat
sadat

Reputation: 4352

How to ignore special characters from the search field in Django

The model is something like

class Product(BaseModel):
    name = models.CharField(db_column='name', max_length=200, blank=False, null=False, unique=True)

View is

class ProductViewSet(BaseViewSet):
    queryset = Product.objects.all()
    ...
    filterset_class = ProductFilter

The filter is

class ProductFilter(django_filters.FilterSet):
    search = django_filters.CharFilter(field_name='name', lookup_expr='icontains')

    class Meta:
        model = Product
        fields = []

Now.. if the name field has a value something like "This is a/sample" and search text is "asample". I would like to return that row.

Thanks in advance.

Upvotes: 1

Views: 2335

Answers (2)

HTTP ERROR 500
HTTP ERROR 500

Reputation: 67

Use PostGreSQL, which currently supports the 'unaccent' extension. This makes searching for 'año' possible when only typing 'ano'.

Best thing is, you can decide whether to use this extension for every filter by, for example using

Person.objects.filter(first_name__unaccent__icontains=search)

Switch your database to PostgreSQL and add the unaccent extension as follows:

Part of answer from @SaeX in another thread: How can I activate the unaccent extension on an already existing model


A migration file needs to be manually made and applied.

  1. First, create an empty migration:

./manage.py makemigrations myapp --empty

  1. Then open the file and add UnaccentExtension to operations:
from django.contrib.postgres.operations import UnaccentExtension


class Migration(migrations.Migration):

    dependencies = [
        (<snip>)
    ]

    operations = [
        UnaccentExtension()
    ]
  1. Now apply the migration using ./manage.py migrate.

If you'd get following error during that last step:

django.db.utils.ProgrammingError: permission denied to create extension "unaccent"
HINT:  Must be superuser to create this extension.

... then temporarily allow superuser rights to your user by performing postgres# ALTER ROLE <user_name> SUPERUSER; and its NOSUPERUSER counterpart. pgAdminIII can do this, too.

Now enjoy the unaccent functionality using Django:

>>> Person.objects.filter(first_name__unaccent=u"Helène")
[<Person: Michels Hélène>]

Again, part of this answer belongs to @SaeX


IMPORTANT

But for me his answer still didn't work, so don't forget to add the line django.contrib.postgresin INSTALLED_APPS (settings.py)

Upvotes: 1

Neeraj
Neeraj

Reputation: 997

If the question is only for one special character ie. '/' then you can create a custom filter method with Replace like this :

class ProductFilter(django_filters.FilterSet):
    def filter_without_special_chars(self, queryset, field, value):
        return queryset.annotate(search_field=Replace('name', Value('/'), Value('')).filter(search_field__icontains=value)

    search = django_filters.CharFilter(method='filter_without_special_chars')

    class Meta:
        model = Product
        fields = []

You can also do this for multiple special characters BUT it won't be the optimal solution, I would suggest you user ElasticSearch (or something similar) for that.

For multiple char replacement the function would look something like this :

def filter_without_special_chars(self, queryset, field, value):
        return queryset.annotate(sf1=Replace('name', Value('!'), Value('')),
                                 sf2=Replace('sf1', Value('%'), Value(''))).filter(sf2__icontains=value)

Upvotes: 2

Related Questions