Code

Opened 3 years ago

Closed 17 months ago

Last modified 17 months ago

#16039 closed Bug (fixed)

syncdb with --database option fails

Reported by: yedpodtrzitko Owned by: aaugustin
Component: Database layer (models, ORM) Version: 1.4
Severity: Release blocker Keywords:
Cc: asandroq, charette.s@…, mhaligowski Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Let's presume we've more than one databases in settings:

DATABASES = {
    'default': {
        'NAME': '/home/yed/tmp/icentrum.sqlite',
        'ENGINE': 'django.db.backends.sqlite3',
    },
    'ysql': {
        'NAME': 'icentrum',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'yed',
        'PASSWORD': 'heslo',
        'HOST': 'localhost',
        'OPTIONS': {"charset":"utf8", "init_command":"SET storage_engine=InnoDB"},
    }
}

...and now try to sync non-default database database:

./manage.py syncdb --database=ysql

Expected result:

Non-default database is synced

Obtained result:

Creating tables ...
Running post-sync handlers for application auth
Traceback (most recent call last):
  File "./manage.py", line 28, in <module>
    execute_from_command_line()
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/__init__.py", line 429, in execute_from_command_line
    utility.execute()
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/base.py", line 351, in handle
    return self.handle_noargs(**options)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/commands/syncdb.py", line 109, in handle_noargs
    emit_post_sync_signal(created_models, verbosity, interactive, db)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/core/management/sql.py", line 190, in emit_post_sync_signal
    interactive=interactive, db=db)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/dispatch/dispatcher.py", line 172, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/contrib/auth/management/__init__.py", line 30, in create_permissions
    ctype = ContentType.objects.get_for_model(klass)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/contrib/contenttypes/models.py", line 38, in get_for_model
    defaults = {'name': smart_unicode(opts.verbose_name_raw)},
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/manager.py", line 135, in get_or_create
    return self.get_query_set().get_or_create(**kwargs)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/query.py", line 378, in get_or_create
    return self.get(**lookup), False
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/query.py", line 344, in get
    num = len(clone)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/query.py", line 82, in __len__
    self._result_cache = list(self.iterator())
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/query.py", line 273, in iterator
    for row in compiler.results_iter():
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/sql/compiler.py", line 680, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/backends/util.py", line 34, in execute
    return self.cursor.execute(sql, params)
  File "/home/yed/skript/centrum/mypage-all/lib/python2.5/site-packages/django/db/backends/sqlite3/base.py", line 234, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: no such table: django_content_type

Attachments (3)

django.diff (2.9 KB) - added by asandroq 23 months ago.
Patch for auth and contenttypes applications
issue-16039.diff (3.6 KB) - added by Allan Lei <allanlei@…> 20 months ago.
Changed db argument to keyword arg with default value. Missed a .using()
16039.patch (13.4 KB) - added by aaugustin 17 months ago.

Download all attachments as: .zip

Change History (37)

comment:1 Changed 3 years ago by aaugustin

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to needsinfo
  • Status changed from new to closed

It looks like you have written a database router that prevents syncdb from creating the django_content_type table on the 'ysql' databases, but still allows reads on that database.

Could you show us the definition of your database router?

Our procedure is to close the bug until you provide this information, then you can reopen it. Thanks!

comment:2 follow-up: Changed 23 months ago by asandroq

  • Resolution needsinfo deleted
  • Status changed from closed to reopened
  • UI/UX unset

I have exactly the same problem and I am not using database routers at all:

# Used to determine which models get loaded/saved/synced to which DB
DATABASE_ROUTERS = []

comment:3 in reply to: ↑ 2 Changed 23 months ago by ramiro

  • Resolution set to needsinfo
  • Status changed from reopened to closed

Replying to asandroq:

I have exactly the same problem and I am not using database routers at all:

# Used to determine which models get loaded/saved/synced to which DB
DATABASE_ROUTERS = []

Please tell us which version of Django are you using? , which DB backend? How many databases in SETTINGS, etc., etc.

comment:4 Changed 23 months ago by asandroq

  • Cc asandroq added
  • Resolution needsinfo deleted
  • Status changed from closed to reopened

This is Django 1.3.1. My setup uses two databases, an SQLite one and a PostgreSQL one. The application we deploy to customers was based on SQLite and the next version will use PostgreSQL. So I want to call syncdb on both DBs, and then use dumpdata/loaddata to move the data over. When calling syncdb --database=old_mdm --noinput in the instalation script, I get the error above.

DATABASES = {
        'default': {
                'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
                'NAME': 'mdm',                      # Or path to database file if using sqlite3.
                'USER': 'django',                      # Not used with sqlite3.
                'PASSWORD': 'abcabc',                  # Not used with sqlite3.
                'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
                'PORT': '5432',                      # Set to empty string for default. Not used with sqlite3.
        },
        'old_mdm': {
                'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
                'NAME': '/fwxserver/DB/django.sqlite',                      # Or path to database file if using sqlite3.
                'USER': '',                      # Not used with sqlite3.
                'PASSWORD': '',                  # Not used with sqlite3.
                'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
                'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        }
}

MIDDLEWARE_CLASSES = (
        'django.middleware.common.CommonMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
#    'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.transaction.TransactionMiddleware',
)

INSTALLED_APPS = (
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        'api',
        'ios',
        'django.contrib.admin',
        'south',
        # Uncomment the next line to enable admin documentation:
        # 'django.contrib.admindocs',

        # Sentry
        'indexer',
        'paging',
        'sentry',
        'sentry.client',
)

comment:5 follow-up: Changed 23 months ago by aaugustin

You're using south, and south overrides the syncdb command. So you're likely getting a different traceback. Could you post it in full?

comment:6 in reply to: ↑ 5 Changed 23 months ago by asandroq

Replying to aaugustin:

You're using south, and south overrides the syncdb command. So you're likely getting a different traceback. Could you post it in full?

The stack trace follows:

+ /usr/local/filewave/python/bin/python /usr/local/filewave/django/filewave/manage.pyc syncdb --database=old_mdm --noinput
Syncing...
Creating tables ...
ERROR:  relation "django_content_type" does not exist at character 136
STATEMENT:  SELECT "django_content_type"."id", "django_content_type"."name", "django_content_type"."app_label", "django_content_type"."model" FROM "django_content_type" WHERE ("django_content_type"."model" = 'permission'  AND "django_content_type"."app_label" = 'auth' )
Traceback (most recent call last):
  File "/usr/local/filewave/django/filewave/manage.py", line 11, in <module>
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 459, in execute_manager
    utility.execute()
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/South-0.7.5-py2.7.egg/south/management/commands/syncdb.py", line 90, in handle_noargs
    syncdb.Command().execute(**options)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 110, in handle_noargs
    emit_post_sync_signal(created_models, verbosity, interactive, db)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/core/management/sql.py", line 189, in emit_post_sync_signal
    interactive=interactive, db=db)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 172, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/contrib/auth/management/__init__.py", line 35, in create_permissions
    ctype = ContentType.objects.get_for_model(klass)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/contrib/contenttypes/models.py", line 42, in get_for_model
    defaults = {'name': smart_unicode(opts.verbose_name_raw)},
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/manager.py", line 134, in get_or_create
    return self.get_query_set().get_or_create(**kwargs)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/query.py", line 442, in get_or_create
    return self.get(**lookup), False
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/query.py", line 361, in get
    num = len(clone)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/query.py", line 85, in __len__
    self._result_cache = list(self.iterator())
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/query.py", line 291, in iterator
    for row in compiler.results_iter():
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 763, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 818, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/filewave/python/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 52, in execute
    return self.cursor.execute(query, args)
django.db.utils.DatabaseError: relation "django_content_type" does not exist
LINE 1: ..."."app_label", "django_content_type"."model" FROM "django_co...
Version 0, edited 23 months ago by asandroq (next)

Changed 23 months ago by asandroq

Patch for auth and contenttypes applications

comment:7 Changed 23 months ago by asandroq

Ok, I came up with a patch that seems to solve my problem. The "auth" and "contenttypes" applications were not taking multiple DBs into consideration. The patch is for Django 1.4.

Last edited 23 months ago by asandroq (previous) (diff)

comment:8 Changed 23 months ago by charettes

  • Cc charette.s@… added

@asandroq Does that work with a router returning False for allow_syncdb('specified_db', ContentType) and/or allow_syncdb('specified_db', Permission)? Maybe an initial router.allow_syncdb(db, ContentType) and/or router.allow_syncdb(db, Permission) should be added to short-circuit methods?

Last edited 23 months ago by charettes (previous) (diff)

comment:9 Changed 23 months ago by edward.dsouza@…

@asandroq, could you post your patch?

comment:10 Changed 23 months ago by aaugustin

  • Triage Stage changed from Unreviewed to Accepted

I haven't verified if the patch is correct, but there's definitely something wrong here.

comment:11 Changed 22 months ago by jonnyhatch

  • Version changed from 1.3 to 1.4

I'm still encountering this error, and I'm updated to version 1.4. Not using an allow_sync method on my database router either.

Changed 20 months ago by Allan Lei <allanlei@…>

Changed db argument to keyword arg with default value. Missed a .using()

comment:12 Changed 20 months ago by Allan Lei <allanlei@…>

  • Has patch set

Change asandroq's patch so that the db argument has a default value of DEFAULT_DB_ALIAS since that is what it would have been using with this patch.

In django/contrib/contenttypes/management.py

ContentType.objects.bulk_create() in update_contenttypes() was missing this fix.

comment:13 Changed 20 months ago by aaugustin

  • Severity changed from Normal to Release blocker

#18878 was a duplicate.

I'm increasing severity because it's a crashing bug in syncdb and it was reported again.

comment:14 Changed 19 months ago by mhaligowski

  • Cc mhaligowski added
  • Needs tests set
  • Owner changed from nobody to mhaligowski
  • Patch needs improvement set
  • Status changed from reopened to new

No tests at all. At the current stage of development.

comment:15 Changed 19 months ago by mhaligowski

  • Needs tests unset
  • Patch needs improvement unset

Patch provided here https://github.com/mhaligowski/django/compare/ticket_16039, along with the test.

I'll be grateful for a review, as I am unsure about the solution. It fixes the bug, but I believe there may be a better way to do that.

comment:16 Changed 19 months ago by mhaligowski

  • Triage Stage changed from Accepted to Design decision needed

Not sure about the design decision, as discussed in IRC.

The provided patch will be fine when ContentType should be synchronized in all databases. This could lead to discrepancies in IDs, though, as pointed out by @freakyboy3742.

comment:17 Changed 19 months ago by mhaligowski

  • Owner changed from mhaligowski to nobody

comment:18 Changed 19 months ago by ptone

refs: #15610, #19068

comment:19 follow-up: Changed 19 months ago by akaariai

It seems the only common multi-db setups for contenttypes are "in single database" and "one DB contains master data, others mirror it".

We could work a solution based on the following:

  • Document that it is suggested that one syncs the contenttypes/permissions table only into one DB (do we need an easier way than routers here? Could we somehow have this default to "default" database in global_settings.py?)
  • If there is need for master-slave like setup for contenttypes, if we know which DB is the master, which slaves (again, do we need something else than routers?) then we can have syncdb handle the syncing of data. Read from master, copy to slave, ensure PK values match.
  • If users create contenttypes and/or permissions manually by the ORM in master-slave setup, then there will be no automatic replication. This is a documentation issue. Most users having a master-slave setup will need to deal with this possibility anyways.

The hardest question is how to make it easy to define which DB is the master, and which (if any) are the slaves. We could take an approach where the "default" database is the master for contenttypes/permissions unless there are routers, in which case we inspect the router's for_write and allow_sync for the master/slaves.

comment:20 follow-up: Changed 19 months ago by mhaligowski

Personally, I think that introducing master/slave idea is too complex for just one bug and I don't think that it will introduce any more functionality. Having said that, I would go for the solution contenttypes/permissions go to 'default' unless stated differently in the routers. I hope I understood the idea of the routers correctly.

Would someone please confirm the idea for the solution is right? If so, I would write the solution.

comment:21 follow-up: Changed 18 months ago by akaariai

Yes, leaving master/slave out of this ticket seems like a good idea.

So, currently even if ContentTypes and Permissions are installed to each database by default, the data isn't created by syncdb to 'other'. Actually, the default is populated by doing a manage.py syncdb --database=other. This seems wrong - the default DB should not be touched at all if syncing 'other'.

So, here is a simplified suggestion for this ticket:

  1. Make sure the default database isn't accessed at all by syncdb --database='other' (If there are more errors than contenttypes and permissions, then deal with them in separate tickets).
  2. Sync the contenttypes and permissions only to one database.
  3. The database is 'default' if the contenttypes _and_ permissions are installed to the 'default' database. If they are not synced to 'default' database, don't do anything at all.

The above solution is very limited, if you want the models in some other DB than default or you want the models mirrored to other databases you are on your own. In short, this is the simplest fix to the current situation I can think of. It works mostly as currently, except that 'default' isn't touched at all by syncdb --database=other.

I wonder what to do with documenting this... Maybe something along the lines that we currently do not handle syncing the contenttypes and permissions data to other databases than default, but we might change this later on.

This means we will intentionally leave two use-cases open:

  • installing the data in 'other' only
  • no syncing between databases

To solve the above issues we need a notion of "master" database for contenttypes and permissions.

comment:22 in reply to: ↑ 20 Changed 18 months ago by russellm

Replying to mhaligowski:

Personally, I think that introducing master/slave idea is too complex for just one bug and I don't think that it will introduce any more functionality. Having said that, I would go for the solution contenttypes/permissions go to 'default' unless stated differently in the routers. I hope I understood the idea of the routers correctly.

Would someone please confirm the idea for the solution is right? If so, I would write the solution.

I can confirm that this is almost certainly *not* the right solution. Putting special cases into routing behaviour is something we want to avoid. "Special cases aren't special enough to break the rules."

comment:23 in reply to: ↑ 21 Changed 18 months ago by russellm

Replying to akaariai:

Yes, leaving master/slave out of this ticket seems like a good idea.

So, currently even if ContentTypes and Permissions are installed to each database by default, the data isn't created by syncdb to 'other'. Actually, the default is populated by doing a manage.py syncdb --database=other. This seems wrong - the default DB should not be touched at all if syncing 'other'.

So, here is a simplified suggestion for this ticket:

There is another option, which I raised on IRC over the weekend but didn't fully endorse at the time; however, I've had a bit of a chance to think about it now, and I think it's work looking into some more.

Don't make any special cases here, don't worry about master/slaving contenttypes, and so on; treat each database as a completely separate concern. If contenttypes is marked to be synchronized onto a database, then you populate that database with the contenttypes values for models synchronized onto that database.

The default routing strategy is "everything synchronizes everywhere", so this means that a content type for every model will be created on every database.

A more subtle routing strategy might allow the model Foo to only be synchronized on 'other'. This would mean no content type for Foo on 'default', but there would be one on 'other'.

The upshot of this approach is that all the Generic FK issues that have been reported with multi-db get resolved. It also means the patch that has been provided is pretty much ready to go,

The complication is that any given content type won't have a unique PK across all databases. Contenttypes would be guaranteed complete and accurate on any given database, but a content type would only be available if the model was synchronized on that database. However, you can't join across databases anyway; all this means is that if you want to simulate a cross-database join, you need to do a lookup on the remote database for the comparable foreign key.

You'll also need to be careful when doing queries against the contenttype table to make sure you're getting the "right" contenttype from the "right" database. A default ContentType.objects.get() call won't hit the right database without providing context. However, any attempt to use a contenttype from the wrong database should raise a cross-database error, so while this will be an annoying detail to get right all the time, it is something that should be easy to debug.

comment:24 Changed 18 months ago by akaariai

I think the latest patch is doing what Russell is asking. However, there are no docs and I think we want some in syncdb and/or ContentTypes and Permissions docs.

Also, we might need to go through the uses of ContentType and check for potential problems: for example "fetch Comment from DB A, save to DB B - check that this throws an error (or the ContentType ID gets updated/verified).

I wonder if we want to have different treatment for Permissions. It seems there is less potential in having permissions for synced models per database. Instead, one database which has all the permissions and their associations to users and groups seems like the right way to go.

comment:25 Changed 18 months ago by akaariai

I am beginning to think that if you get any contenttypes to a DB, then you might want them all. For example users will likely want to store all permissions in one database (the database which contains the Users and Groups data). Even permissions for models which are not synced to the default database, so that there is one DB to ask for all permissions. But, if we install all permissions to a database, then we need all ContentTypes there too.

The "sync only those contenttypes whose model is in the DB" seems useful for one use case - GenericForeignKeys. But that isn't the only use case. And, installing additional ContetTypes into a DB seems safe to me.

This ticket has potential for endless amounts of complexity. MultiDB is complex. In addition we don't have information about the use case, nor do we know essential information: for example in master-slave setup we don't know which DB is the master...

So, another proposal for solution:

  • Sync _all_ contenttypes and permissions to default database (this is essentially what is happening now)
  • No sync at all for other databases

The proposal isn't the ultimate right solution. But it is simple and safe. With the information at hand at sync time doing anything smarter might be hard, too.

I am not a multidb expert at all. But, if this ticket doesn't get a solution from others for 1.5, then I am going to go with the simple solution.

comment:26 in reply to: ↑ 19 Changed 17 months ago by aaugustin

After discussing with Anssi on IRC and reviewing the history of this ticket, I have two concrete proposals:

(1) All content types and permissions are synced to the target database (with or without the --database option) unless the routers prevent it. That is, if allow_syncdb returns True or None, they're sync'd, if it returns False, they aren't.

(2) Use the same rule as 1) for the default database; for non-default databases sync all content types and permissions only if the routers mandate it. That is, if allow_syncdb returns True, they're sync'd, if it returns False or None, they aren't.

Both rules are compatible with the philosophy of the routers.

Option (2) biases Django towards having a single copy of the content types and permissions in the default table, reducing the likelyhood of the id mismatch problem. But it's harder to implement, document and to explain, and I don't have any strong arguments supporting it. Also, I suspect it won't solve the reporter's problem: without any routers, syncing django.contrib.auth to a non-default database will still fail. So I have a weak preference for option (1).

In addition, for users who wish to run syncdb on more than one database, we should recommend to define routers that allow syncing the contenttypes and permissions tables only to one database, to avoid the pk mismatch problem. I don't expect many people to attempt this anyway. Most multi-db users will:

  • have a master / slave setup: they run syncdb once to master, and the replication takes care of the rest;
  • have a master database for Django itself, and interact with existing external databases, most likely with unmanaged models;
  • or a combination of both.

It seems to me that Russell's proposal to split content types across databases doesn't work as is. The admin's permissions have a foreign key to content types; therefore all content types need to be available in a table in the same database that holds the admin's permissions table. (Actually that's what Anssi says in the comment just above, which I read after writing this.) If we want to investigate this option further, let's split it to another ticket, because it isn't a release blocker.

comment:27 follow-up: Changed 17 months ago by akaariai

OK for me for contenttypes. I am still a bit worried about the id mismatch. But, as said, it is likely users who have this setup will need to know how to tackle the ID problem anyways. Permissions are a bigger problem. To me it seems that some core parts of Django aren't ready to handle situations where different databases give different permissions to a user (auth/backends.py).

This ticket is out of my domain, I just don't have experience of the use cases needing contenttypes and/or permissions in different databases so I don't know what behavior we should be looking after.

Maybe one approach could be checking if there is any core-supported use case for having the contenttypes/permissions in multiple databases: for contenttypes, sure, generic foreign keys for example. For permissions - I don't think so, auth/backends.py doesn't work and thus default user.has_perm() doesn't work. So, what is the use case for having permissions in more than one DB?

comment:28 Changed 17 months ago by charettes

In the case of multi-tenancy it can be quite useful to have both tables on another database or schema.

Given a postgresql setup you can have a middleware that SET search_path TO specific_client_schema on a specific connection to a database with some specific ContentType and Permission.

However I think that it's a really specific use case and both aaugustin's proposals make sense. I slightly prefer the first proposal since it doesn't introduce special cases that one might not expect.

comment:29 in reply to: ↑ 27 Changed 17 months ago by aaugustin

Replying to akaariai:

To me it seems that some core parts of Django aren't ready to handle situations where different databases give different permissions to a user (auth/backends.py).

Yes, you almost certainly have to put all auth-related tables on the same database. But it doesn't have to be the default database.

This ticket is out of my domain, I just don't have experience of the use cases needing contenttypes and/or permissions in different databases so I don't know what behavior we should be looking after.

A legitimate use case would be to use a default database with some business data, and a separate database just for Django's apps (auth, admin, etc.) This is easy to achieve with a router. (But I never tried so I'm not sure to what extent it works.)

Maybe one approach could be checking if there is any core-supported use case for having the contenttypes/permissions in multiple databases: for contenttypes, sure, generic foreign keys for example. For permissions - I don't think so, auth/backends.py doesn't work and thus default user.has_perm() doesn't work. So, what is the use case for having permissions in more than one DB?

In my opinion, in this ticket, the use case is to put permissions and content types in a non-default database. It isn't to put them in more that one database; this is too far from being usable right now.

comment:30 Changed 17 months ago by aaugustin

  • Owner changed from nobody to aaugustin

Changed 17 months ago by aaugustin

comment:31 Changed 17 months ago by Aymeric Augustin <aymeric.augustin@…>

  • Resolution set to fixed
  • Status changed from new to closed

In 9bd67f056c6d1697d81841e3e21661069f57b14e:

[1.5.x] Fixed #16039 -- Made post_syncdb handlers multi-db aware.

Also reverted 8fb7a9002669fb7ba7bec7df90b465b92e1ed3c2. Refs #17055.

Backport of a026e48 from master.

comment:32 Changed 17 months ago by Aymeric Augustin <aymeric.augustin@…>

In a026e480da89cb99c9dc6c954fb5a37ded0f9315:

Fixed #16039 -- Made post_syncdb handlers multi-db aware.

Also reverted 8fb7a9002669fb7ba7bec7df90b465b92e1ed3c2. Refs #17055.

comment:33 Changed 17 months ago by Aymeric Augustin <aymeric.augustin@…>

In a892cd3191cd2e0d98756764ed7be3ad59b95850:

[1.5.x] Tweak a test to avoid hitting a limit with SQLite.

Django cannot delete more than 999 objects at a time with SQLite.

Refs #16426, #16039.

Backport of 2875b5d from master.

comment:34 Changed 17 months ago by Aymeric Augustin <aymeric.augustin@…>

In 2875b5dcab23c027d019656b08da8b911bc60711:

Tweak a test to avoid hitting a limit with SQLite.

Django cannot delete more than 999 objects at a time with SQLite.

Refs #16426, #16039.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.