29

I need to implement full text search for my Django application, running MySQL as backend.

Let's say I've got a model as follows:

class MyItem(models.Model):
    title = models.CharField()
    short_description = models.TextField()
    description = models.TextField()

I would like to have results first for search term occurences in title, then in short_description and at the end in description field. I'll be happier if I don't have to use additional modules/applications for this task.

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
edkirin
  • 507
  • 1
  • 4
  • 11

6 Answers6

42

The previously highest rated answer is deprecated. As of Django 1.10 there is no more search field lookup for MySQL databases (see the search section in the 1.10 documentation).

The release notes for 1.10 also propose a solution to this, by defining a custom lookup:

###__search query lookup

The search lookup, which supports MySQL only and is extremely limited in features, is deprecated. Replace it with a custom lookup:

from django.db import models

class Search(models.Lookup):
   lookup_name = 'search'

   def as_mysql(self, compiler, connection):
       lhs, lhs_params = self.process_lhs(compiler, connection)
       rhs, rhs_params = self.process_rhs(compiler, connection)
       params = lhs_params + rhs_params
       return 'MATCH (%s) AGAINST (%s IN BOOLEAN MODE)' % (lhs, rhs), params

models.CharField.register_lookup(Search)
models.TextField.register_lookup(Search)
Collin Anderson
  • 14,787
  • 6
  • 68
  • 57
tbrlpld
  • 776
  • 6
  • 16
  • 2
    This needs to be higher now, much more up-to-date answer + no dependency to external packages. – Geekfish Jun 07 '19 at 11:51
  • 1
    This worked well me too on Django 2+, thanks for sharing it! – gtalarico Apr 24 '20 at 22:16
  • This is working for me however it fails during tests - thought I would drop this here in case someone using this snippet has the same issue: https://stackoverflow.com/questions/61486725/django-mysql-fulltext-search-works-but-not-on-tests – gtalarico Apr 28 '20 at 18:05
26

You can use full text search in django

MyItem.objects.filter(title__search="some search text")

One thing is - you can't define a fulltext index from a Django model, you need to do in directly in a database (using PHPMyAdmin or SQL query)

See Django documentation for field lookup called search

JPG
  • 82,442
  • 19
  • 127
  • 206
Silver Light
  • 44,202
  • 36
  • 123
  • 164
  • 2
    This doesn't work by default when using MySQL because it doesn't use the table type MyISAM. You get the error "The used table type doesn't support FULLTEXT indexes" – Timmmm Oct 08 '12 at 11:52
  • @SilverLight how to do it against multiple columns like for compound `FULLTEXT` search index? – Rohit Khatri Dec 13 '17 at 11:32
  • @RohitKhatri you can build complex lookups with `Q` objects in Django: https://docs.djangoproject.com/en/2.2/topics/db/queries/#complex-lookups-with-q-objects. The main feature here would be that it allows to connect the query sets with "or". – tbrlpld Apr 24 '19 at 16:34
  • 1
    @Silver Light Maybe I am missing it, but I can't seem to find the referenced field lookup called `search`?! Was that removed maybe? – tbrlpld Apr 26 '19 at 13:17
  • This looks like Postgres only feature https://docs.djangoproject.com/en/4.1/ref/contrib/postgres/search/#the-search-lookup – Montaro Aug 20 '22 at 21:15
7

I don't know if it helps now but I've created a new Python Library for Django which supports MySQLs' and MariaDBs' native full-text search engine over one or multiple columns:

You can have a look at it on the GitHub repository

There's also a description how to install it, use it and how to create the FULLTEXT INDEX stuff via Django migrations (Django 1.7+).

If you've configured the indexes and set the SearchManager for your model you should be able to run something like:

Mymodel.objects.search('Something')
Mymodel.objects.search('Somet*')
Mymodel.objects.search('+Something -Awesome')

Just wanted to update this topic because I didn't find an acceptable solution so far and it might help someone out there as well :)

Cheers Domi

5

If you are looking for a beefy solution I recommend http://haystacksearch.org/

It is very well thought out.

michael
  • 11,667
  • 2
  • 26
  • 25
  • I suppose I will end up with 3rd party solution which I tried to avoid. – edkirin Feb 12 '10 at 09:16
  • Yeah you might need to clarify why that is the solution you want? this option will keep you database independent and it scales well as you add db models to the search criteria. For instance on a project I started using haystack for one table but the final product was querying ten. Don't forget though If you know exactly what you want in raw sql terms you can use it. http://docs.djangoproject.com/en/dev/topics/db/sql/ . Good luck – michael Feb 12 '10 at 12:10
2

Django provides full-text functionality for PostgreSQL's only.

Naseem
  • 119
  • 6
1

From django docs regarding full-text search:

Example:

Entry.objects.filter(headline__search="+Django -jazz Python")

SQL equivalent:

SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);

Note this is only available in MySQL and requires direct manipulation of the database to add the full-text index. By default Django uses BOOLEAN MODE for full text searches. See the MySQL documentation for additional details.

Now to the direct manipulation of the database. In MySQL you can create full-text index by following these steps (source article):

  • Open command prompt, and enter mysql -u root -p. On prompt enter the root password.
  • Enter use your_db_name to switch to your django database.
  • Enter CREATE FULLTEXT INDEX index_name ON table_name (column_names).

That's it! FTS indexing in enabled in your django database. Now you can use the django's rich QuerySet API to do full-text searches.

Edit: The above quote no longer exists in the django version >1.9.

Community
  • 1
  • 1
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
  • I cannot find your quote anywhere in the links provided. – run_the_race Jul 15 '19 at 18:29
  • @run_the_race That's because that part no longer exists in the django version greater than 1.9. I have updated the url so that it takes you to the version which is relevant to my answer at the time writing. – Sнаđошƒаӽ Jul 16 '19 at 07:48
  • See answer by `tbr` for a workaround for Django > 1.9 where `__search` was removed from mysql – gtalarico Apr 24 '20 at 22:17