Question

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.

enter image description here

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?

Was it helpful?

Solution

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.

OTHER TIPS

I've also found this Django patch: https://code.djangoproject.com/attachment/ticket/17875/foreignkey-db-using.patch this might help for cross database relationships

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top