Recently I downloaded the django_messages app (a private user to user messaging django app) and added it to my django project.
settings.py
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'mydjangoapp.mydjangoappdb',
'tastypie',
'gunicorn',
'south',
'relationships',
'pyapns',
'django_messages',
The app works great and plays well with Django. However for features such as messaging, the database can get quite large. I decided to create a dedicated database to store all the django_messages data.
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'django_db',
'USER': 'django_login',
'PASSWORD': 'xxxx',
'HOST': '',
'PORT': '',
},
'message_db': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'django_messagedb',
'USER': 'django_login',
'PASSWORD': 'xxxx',
'HOST': 'XX.XXX.XX.XXX',
'PORT': '5432',
}
DATABASE_ROUTERS = ['mydjangoapp.messagerouter.MessageRouter']
And just for clarification, here is my messagerouter.py
class MessageRouter(object):
"""
A custom router written by Riegie to
control all database operations on models in the
django_messages application
"""
def db_for_read(self, model, **hints):
"""
Attempts to read django_messages models go to
message_db.
"""
if model._meta.app_label == 'django_messages':
return 'message_db'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write django_messages models to go to
message_db.
"""
if model._meta.app_label == 'django_messages':
return 'message_db'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the django_messages.
"""
if obj1._meta.app_label == 'django_messages' or \
obj2._meta.app_label == 'django_messages':
return True
return None
def allow_syncdb(self, db, model):
"""
Make sure the django_messages app only appears in the
'message_db" database.
"""
if db == 'message_db':
return model._meta.app_label == 'django_messages'
elif model._meta.app_label == 'django_messages':
return False
return None
As you can see, I have two databases, one on the local machine on which Django is running and another database on a remote machine. Out of the box, upon installation, django_messages naturally creates tables on the default database. However, I would like it to create tables only on the "message_db" database.
I've looked into the Multi-db Setup Django documentation, but it goes into specifics about Master/Slave configuration. I used the Auth Router example and created the messagerouter.py. Everything syncs up and I get no errors.
When I check the remote database however, the table isn't there! Why is that? Is it because it is not possible to have a remote foreign key table relationship to the Django User?
UPDATE
So I managed to sync the Django_messages app to the other database using the following command: ./manage.py syncdb --database=message_db. This is great. However when I access the app from the Django admin page, I am given the following error:
DatabaseError at /admin/django_messages/message/
relation "django_messages_message" does not exist
LINE 1: SELECT COUNT(*) FROM "django_messages_message"
I find this error odd because I can see the table on the other server through pgadmin III. So the syncing has worked correctly, but now it seems Django can't recognize that table. Am I doing something wrong with my messagerouter.py perhaps?
So after doing a lot of research, I finally came across this, I wish I had seen it earlier. Django doesn't support cross-database relations: https://docs.djangoproject.com/en/dev/topics/db/multi-db/#no-cross-database-relations
As it states: Django doesn’t currently provide any support for foreign key or many-to-many relationships spanning multiple databases. If you have used a router to partition models to different databases, any foreign key and many-to-many relationships defined by those models must be internal to a single database.
This is because of referential integrity. In order to maintain a relationship between two objects, Django needs to know that the primary key of the related object is valid. If the primary key is stored on a separate database, it’s not possible to easily evaluate the validity of a primary key.
If you’re using Postgres, Oracle, or MySQL with InnoDB, this is enforced at the database integrity level – database level key constraints prevent the creation of relations that can’t be validated.
However, if you’re using SQLite or MySQL with MyISAM tables, there is no enforced referential integrity; as a result, you may be able to ‘fake’ cross database foreign keys. However, this configuration is not officially supported by Django.
Hope this answer saves many of you the trouble.