etianen / django-watson

Full-text multi-table search application for Django. Easy to install and use, with good performance.
BSD 3-Clause "New" or "Revised" License
1.2k stars 130 forks source link

Best way to search a model including related things #179

Closed loudfishmonger closed 7 years ago

loudfishmonger commented 7 years ago

I have a model that represents a page, and a model that represents reusable content blocks that are associated with one or more pages. Like this:

class Page(models.Model):
    name = models.CharField(...)
    ...

class Block(models.Model):
    content = models.TextArea(...)
    page = models.ManyToManyField(Page)
    publish = models.DateTimeField()
    expire = models.DateTimeField()
    ...

I started out using watson just to search the pages by their name.

watson.register(Page, fields=("name"))

That works great. Now I would like to search the content blocks that are associated with the page. But in the search results, I just want to point people to the page. Search results should not include blocks. The blocks themselves aren't stand alone things with URLs.

What's the best way to do this? Do I just add block_set to the fields tuple when I register Page? Or is it better for me to register the blocks as their own thing, search the two models separately, and then loop through both results to build a list of matching Page objects?

To complicate things a bit further, the blocks are only active at certain times. You can see they have publish and expire properties. So a user may create a block today that is associated with a handful of pages, but have that block set to not be published until next week and then expire after a few days. I have a manager on the blocks to figure this out, so that whenever I have a page object I can just do mypage.block_set.active() to get the blocks that should be displayed. If I register the blocks separetely with something like watson.register(Block.objects.active()), is it going to cache the current datetime when I call buildwatson, or will it be calculated everytime I perform a search?

etianen commented 7 years ago

Tricky. You can add block_set to fields, or event block_set__content, to have it index specific block fields.

However, this won't work with your publication rules. To do that, you'd need to register Block separately and build the composite search results yourself. You can handle the publication rules using this approach: https://github.com/etianen/django-watson/wiki/Searching-models#searching-for-a-subset-of-your-registered-models

Alternatively, if you're on postgres, consider ditching watson and using the postgres full text search integration from Django directly.