Skip to main content

Django field implementation for PostgreSQL tsvector.

Project description

django-tsvector-field is a drop-in replacement for Django’s and manages the database triggers to keep your tsvector columns updated automatically.


Python 3+, Django 1.11+ and psycopg2 are the only requirements:

  1. Install django-tsvector-field with your favorite python tool, e.g. pip install django-tsvector-field.

  2. Add tsvector to your INSTALLED_APPS setting.


tsvector.SearchVectorField works like any other Django field: you add it to your model, run makemigrations to add the AddField operation to your migrations and when you migrate tsvector will take care to create the necessary postgres trigger and stored procedure.

Let’s create a TextDocument model with a search field holding our tsvector and having postgres automatically update it with title and body as inputs.

from django.db import models
import tsvector

class TextDocument(models.Model):
    title = models.CharField(max_length=128)
    body = models.TextField()
    search = tsvector.SearchVectorField([
        tsvector.WeightedColumn('title', 'A'),
        tsvector.WeightedColumn('body', 'D'),
    ], 'english')

After you’ve migrated you can create some TextDocument records and see that postgres keeps it synchronized in the background. Specifically, because the search column is set at the database level, you need to call refresh_from_db() to get the updated search vector.

>>> doc = TextDocument.objects.create(
...     title="My hovercraft is full of spam.",
...     body="It's what eels love!"
... )
>>> doc.refresh_from_db()
"'eel':10 'full':4A 'hovercraft':2A 'love':11 'spam':6A"

Note that spam is recorded with 6A, this will be important later. Let’s continue with the previous session and create another document.

>>> doc = TextDocument.objects.create(
...     title="What do eels eat?",
...     body="Spam, spam, spam, they love spam!"
... )
>>> doc.refresh_from_db()
"'eat':4A 'eel':3A 'love':9 'spam':5,6,7,10"

No we have two documents: first document has just one spam with weight A and the second document has 4 spam with lower weight. If we search for spam and apply a search rank then the A weight on the first document will cause that document to appear higher in the results.

>>> matches = TextDocument.objects\
...     .annotate(rank=SearchRank(F('search'), SearchQuery('spam')))\
...     .order_by('-rank')\
...     .values_list('rank', 'title', 'body')
>>> for match in matches:
...   print(match)
(0.607927, 'My hovercraft is full of spam.', "It's what eels love!")
(0.0865452, 'What do eels eat?', 'Spam, spam, spam, they love spam!')

If you are only interested in getting a list of possible matches without ranking you can filter directly on the search column like so:

>>> TextDocument.objects.filter(search='spam')
<QuerySet [<TextDocument: TextDocument object>, <TextDocument: TextDocument object>]>

For more information, see the Django documentation on Full Text Search:


  • Initial release.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-tsvector-field-0.9.0.tar.gz (7.0 kB view hashes)

Uploaded source

Built Distribution

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page