简体   繁体   中英

Using multiple Django admin sites for multiple databases

I need to manage multiple databases within Django Admin. My two databases named 'local' and 'server' are defined in the settings file. Since Django doesn't allow to add several times the same model with different ModelAdmin , I am creating two instances of admin.AdminSite .

Here is the code of the admin.py file:

from core.models import MyModel

from django.contrib import admin

server_site = admin.AdminSite('server')
local_site = admin.AdminSite('local')


class MultiDBModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        # Tell Django to save objects to the 'other' database.
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        # Tell Django to delete objects from the 'other' database
        obj.delete(using=self.using)

    def get_queryset(self, request):
        # Tell Django to look for objects on the 'other' database.
        return super(MultiDBModelAdmin1, self).get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super(MultiDBModelAdmin1, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super(MultiDBModelAdmin1, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs)


class MultiDBModelAdmin1(MultiDBModelAdmin):
    # A handy constant for the name of the alternate database.
    using = 'server'


class MultiDBModelAdmin2(MultiDBModelAdmin):
    # A handy constant for the name of the alternate database.
    using = 'local'


local_site.register(MyModel, MultiDBModelAdmin1)

server_site.register(MyModel, MultiDBModelAdmin2)

and here is the urls.py file:

from django.conf.urls import patterns, include, url

from core.admin import local_site, server_site


urlpatterns = patterns('',
    url(r'^admin/', include(local_site.urls)),
    url(r'^serveradmin/', include(server_site.urls)),
            [...]
)

I can access the admin panel using both the admin/ and serveradmin/ URLs, however the content is the very same: the administration panel is using the 'local' database, regardless of the admin panel I access. How come Django doesn't discriminate the two?

You can override the get_queryset method and use a filter to allow switching the model list page on the admin from one db to the other:

class MultiDBListFilter(admin.SimpleListFilter):
    title = 'database'
    parameter_name = 'db'

    def lookups(self, request, model_admin):
        return tuple((db, db) for db in ['default'])

    def value(self):
        return super(MultiDBListFilter, self).value() or 'default'

    def queryset(self, request, queryset):
        return queryset

    def choices(self, cl):
        choices = super(MultiDBListFilter, self).choices(cl)
        choices.next()  # Skip `All` choice.
        for choice in choices:
            yield choice

class MyModelAdmin(admin.ModelAdmin):
    model = MyModel
    list_filter = (MultiDBListFilter, )

    def get_queryset(self, request):
        db = request.GET.get('db', 'default')
        return super(MyModelAdmin, self).get_queryset(request).using(db)

@Zack4 I now have almost exactly the same code as you, but mine works.

One questionable thing that I see is that--- whereas it will be deprecated in 1.7, I recall having read--- in 1.6.5 which I'm using it's still necessary to include the following in the url config:

admin.autodiscover()

When I omit that I get a notice that I don't have permission to change anything... not the problem identified in the question but maybe something else is being done that avoids that problem and leaves the one that you have.

And what is "core.admin" in your url config? There is no Django module of that name, according to the error message that I get when I try it. Is "core" the name of your project root directory? Maybe there is a conflict with Django's use of the word "core".

Finally, in my struggles to learn about multiple databases in the Django docs I have seen that there is a special significance to the first database in DATABASES in setting.py--- this is if you're not using database routers (you and I aren't).

I give my first database the name "subscriber" but in settings.py it's:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': os.path.join(BASE_DIR, 'subscriber.db'),   
        ....

Now if I try to change "default" to "subscriber" Django objects and says that I must have a "default" database. That I have learned, while arguing a ticket on the documentation with a core developer, is because default is there to receive the auth model stuff and other admin-related models.

That is, if you "python manage.py dbshell --database=default", and then type ".tables", you should see not only your tables for local (or maybe default is server in your case) but also various authentication and admin stuff. (Type ".quit" to quit.)

Now what happens if you do the same to the other database, --database=server (if that's the other database's key of DATABASES in settings.py)? The first time I set up my two databases I had simply run syncdb, but that put auth and adminstrative models in both databases. I simply deleted those models from my second database.

Finally, it smells like a simple url routing problem. Did you by any chance simplify your urls for the sake of appearance for this post, changing them in the process? What you show looks right.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM