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

Multi-Tenant Website and Django-Watson #166

Closed darkicex3 closed 7 years ago

darkicex3 commented 8 years ago

Hi,

Can I use your app with a multi-tenant website in other words build watson index depending on my subdomains ? I am using django-tenants-schemas and PostgreSQL

etianen commented 8 years ago

From what I can tell by reading django-tenants-schemas, each tennant gets their own table via a standalone postgres schema. Assuming that this isolation is handled well, it should presumably have a per-tenant django-watson table too. So I'd expect it to work.

Only way to know for sure is to try.

On Mon, 13 Jun 2016 at 02:55 darkicex3 notifications@github.com wrote:

Hi,

Can I use your app with a multi-tenant website in other words build watson index depending on my subdomains ? I am using django-tenants-schemas and PostgreSQL

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/etianen/django-watson/issues/166, or mute the thread https://github.com/notifications/unsubscribe/AAJFCA5-AqMTKrhnckYDa_J42c3m6zGeks5qLLiqgaJpZM4Iz8Ss .

jamesbynd commented 7 years ago

I've just tried on a project using django-tenants (v1.1.1), with 2 additional schema's (lets call them tenant1 and tenant2) on top of the public schema

when running ./manage migrate_schemas, the watson.0001_initial migration runs fine on public and tenant1 but fails on tenant2 with the follow error.

[tenant2]   Applying watson.0001_initial...
Traceback (most recent call last):
  File "./manage.py", line 19, in <module>
    execute_from_command_line(sys.argv)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django_tenants/management/commands/migrate_schemas.py", line 60, in handle
    executor.run_migrations(tenants=tenants)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django_tenants/migration_executors/standard.py", line 15, in run_migrations
    run_migrations(self.args, self.options, schema_name)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django_tenants/migration_executors/base.py", line 27, in run_migrations
    MigrateCommand(stdout=stdout, stderr=stderr).execute(*args, **options)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 222, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 110, in migrate
    self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 148, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/migrations/migration.py", line 115, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/migrations/operations/special.py", line 183, in database_forwards
    self.code(from_state.apps, schema_editor)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/watson/migrations/0001_initial.py", line 9, in install_watson
    call_command("installwatson", verbosity=0)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 120, in call_command
    return command.execute(*args, **defaults)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/watson/management/commands/installwatson.py", line 21, in handle
    elif backend.is_installed():
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/watson/backends.py", line 194, in is_installed
    """)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/utils.py", line 98, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/vagrant/.virtualenvs/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression
jamesbynd commented 7 years ago

Quick follow up after some investigation.

It looks like the problem is here in is_installed: https://github.com/etianen/django-watson/blob/master/watson/backends.py#L190

cursor.execute("""
    SELECT attname FROM pg_attribute
    WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'watson_searchentry') AND attname = 'search_tsv';
""")

My psql knowledge is a little lacking, but to me it looks like the subquery which sets attrelid will return one row for every schema that contains a watson_searchentry table.

jamesbynd commented 7 years ago

Ok, obviously this isn't production quality code. But here is a fix which worked for my use case:

https://github.com/jamesbynd/django-watson/commit/336dd94715cc019a073351da4843414e04f37a8c

etianen commented 7 years ago

I'm happy to take a pull request for adding this feature, if it can be done in a way that doesn't impact normal usage. If you get your current solution production quality to your satisfaction, I'll be happy to pull.

jamesbynd commented 7 years ago

@etianen

I actually just ended up adding multi-tenant/schema support to my project like this:

I think this is kind of an edge case that doesn't really warrant support in the code base.

That said, if anyone else turns up looking for multi-tenant support, I'm might pick this back up and work on a PR

etianen commented 7 years ago

You're probably right, and it sounds like your solution is a good one. This issue will be a good starting point for anyone else with the same use-case.

On Fri, 2 Jun 2017 at 10:25 James notifications@github.com wrote:

@etianen https://github.com/etianen

I actually just ended up adding multi-tenant/schema support to my project like this:

  • sub-classed PostgresSearchBackend, over-riding is_installed like it did in my post above
  • set my new backend with the WATSON_BACKEND settings attribute.
  • added custom installwatson/uninstallwatson to management commands which work with django-tenants tenant_command to my application.

I think this is kind of an edge case that doesn't really warrant support in the code base.

That said, if anyone else turns up looking for multi-tenant support, I'm might pick this back up and work on a PR

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-watson/issues/166#issuecomment-305736897, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCJAMg9Xulh70UniF2W3GEMeheLTUks5r_9UWgaJpZM4Iz8Ss .

jonperron commented 6 years ago

I am in the same situation as you @jamesbynd and getting multi-tenant support would be a big plus for watson. Maybe what would miss from what you originally did would be to add public as default schema name.

Since my company is already using watson in production, I made my own fork and depending of how it turns out, I could provide you and @etianen our feedback thus allowing for a PR in this very nice project :+1:

etianen commented 6 years ago

If you manage to make anything of pull-request quality, I'd love to see it :)

On 28 September 2017 at 09:55, Jonathan Perron notifications@github.com wrote:

I am in the same situation as you @jamesbynd https://github.com/jamesbynd and getting multi-tenant support would be a big plus for watson. Maybe what would miss from what you originally did would be to add public as default schema name.

Since my company is already using watson in production, I made my own fork and depending of how it turns out, I could provide you and @etianen https://github.com/etianen our feedback thus allowing for a PR in this very nice project 👍

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/etianen/django-watson/issues/166#issuecomment-332773412, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCGbEAHGVZpksoRbNFteqTH5rLTzMks5sm18agaJpZM4Iz8Ss .