[Fixed]-Django proxy model to different database

7πŸ‘

βœ…

As @hynekcer said if kayakodb is an existing database, you need to set managed = False for all its models.
However, that still leaves the problem of the migration for the proxy model created inside the wrong app (kayakodb).

The hacky fix that might work is changing the app_label of the proxy model to whatever app is okay to put the migration to (sidebar in this case), and making a router that will point this proxy model to read and write from kayakodb.

E.g. the proxy model:

# in sidebar/models.py

class SidebarTicket(KayakoTicket):
    class Meta:
        proxy = True
        app_label = 'sidebar'

and the router inside the project that uses it:

from django.conf import settings
from kayakodb.models import Ticket

class ProxyDatabaseRouter(object):
    def allow_proxy_to_different_db(self, obj_):
        # check if this is a sidebar proxy to the Ticket model in kayakodb
        return isinstance(obj_, Ticket) and obj_._meta.proxy and obj_._meta.app_label == 'sidebar'

    def db_for_read(self, model, **hints):
        if issubclass(model, Ticket) and model._meta.proxy and model._meta.app_label == 'sidebar':
            return 'kayakodb'
        # the rest of the method goes here

    def db_for_write(self, model, **hints):
        if issubclass(model, Ticket) and model._meta.proxy and model._meta.app_label == 'sidebar':
            return 'kayakodb'
        return None
        # the rest of the method goes here

    def allow_relation(self, obj1, obj2, **hints):
        if self.allow_proxy_to_different_db(obj1) or self.allow_proxy_to_different_db(obj2):
            return True
        # the rest of the method goes here
πŸ‘€railla

4πŸ‘

tl;dr but I grepped your question for a word router which is not mentioned, so I’d think the thing you are looking for are Database Routers

πŸ‘€yedpodtrzitko

4πŸ‘

tl;dr Use

class Meta:
    managed = False

for all models in the db that should not be controlled by Django. (i.e. kayakodb)


It should be noted that PyPI Kayako is a Python API (without Djago) to some Kayako app written in another language.

It is usefull to know from you that Kayako and WOW are in different databases but it is not a fundamantal information. Django allows e.g. that one model is present in two databases: a primary and a secondary db. The most important are meta options, the option managed = False in this case. It is for the case Integrating Django with a legacy database. That does not mean only exactly a very old project, but a project that is not written in Python+Django or does not support migrations and does not share information which migrations are not applied yet. Maybe if a new version of Kayako would add a new fields to database, you don need to read that field or if you add it to the model, Django is not responsible to add the field to database because it is controlled by Kayako upgrade.

You can alternatively use database routers to create no tables for kayakodb app (nowhere) and also no tables in kayakodb database e.g. for Django users and groups:

file myrouter.py or similar

class MyRouter(object):
    allow_migrate(db, app_label, model_name=None, **hints):
        if app_label == 'kayakodb' or db == 'kayakodb':
            return False

file settings.py

DATABASE_ROUTERS = ['path.to.myrouter.MyRouter',...]
# ... if another router has been defined previously

The advantage is that this disables migration for any current or future model, but I recommend to add a text class Meta: managed = False also somewhere to comments in kayakodb/models.py in order to make it clear to any later developer, because he can easily forget to read the routers first.

You can write a dependency of your project versions on a minimal and maximal version of Kayako API, but it can not be in form of migration.


Your another problem is that β€œA proxy model must inherit from exactly one non-abstract model class….”, but your proxy model TicketWrapper inherits fromContact and SidebarTicket. It looks like a nonsense and I’m wondering that you don’t see an error TypeError: Proxy model 'TicketWrapper' has more than one non-abstract model base class. The same Contact can be shared by more tickets. (Is not it a registered user? Can not he change anything in his user profile during the history of issue?) It should be probably a foreign key to Contact, not a multiple inheritance.

πŸ‘€hynekcer

Leave a comment