How to have 2 different admin sites in a Django project? - django

I want to have 2 separate admin sites inside a Django project.
By separate I mean - they should have separate users authentication, they should administer different models, and have different looks and URLs.
The reason I want to do it is the customer wants separate section to administer the CMS part of the page, and separate to use as a 'back-office' solution.
I thought about just making a copy od django.contrib.auth appliaction in my project tree, naming it differently and using separate admin.site.register() calls for both of them. This way I can have other models available in each one of them, diffrent looks, etc. I don't know how to solve the user-authentication problem (I should have different user to be able to log into CMS then into the BackOffice).
Anyone happened to do this before and could give me some hint? Or what I plan to do is just wrong by design?

You can subclass Django's AdminSite (put it eg. in admin.py in your project root):
from django.contrib.admin.sites import AdminSite
class MyAdminSite(AdminSite):
pass
#or overwrite some methods for different functionality
myadmin = MyAdminSite(name="myadmin")
At least from 1.9 on you need to add the name parameter to make it work properly. This is used to create the revers urls so the name has to be the one from the urls.py.
Then you can use it in your app's admin.py the same way as you do with the normal AdminSite instance:
from myproject.admin import myadmin
myadmin.register(MyModel_A)
You also need to define some urls for it (in your project's urls.py):
from myproject.admin import admin, user_site
from myproject.admin import myadmin
urlpatterns = patterns('',
...
(r'^admin/', include(admin.site.urls)),
(r'^myadmin/', include(myadmin.urls)),
Also see this: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adminsite-objects

To register models in different AdminSites you just need to create different instances of django.contrib.admin.sites.AdminSite, see this.
You will be good to go with two different admin sites managing different models and having different templates.
For authentication and permissions you should be able to use the build-in django.contrib.auth as is with custom permissions (hope someone else will be able to help more here)

I'm not sure that my finding, reported here, would have been entirely helpful to kender because, among other things, I don't know if he was talking not only about two admin sites but also two databases, one for each. That's my situation. I got the bright idea that I wanted one of my apps, a new app, to have its own database and own admin pages.
But I ran into a problem with the AdminSite subclassing approach of Bernhard Vallant, though it seems to be the orthodox and essentially correct thing to do. I resolved the problem.
Here's the mod to Bernhard Vallant's code that I found to be utterly necessary:
from django.contrib.admin.sites import AdminSite
class MyAdminSite(AdminSite):
pass
#or overwrite some methods for different functionality
myadmin = MyAdminSite(name='anything')
Yes, I do really mean name='anything' that you choose (as long as it isn't 'admin'). And I've toggled in and out with it and it fails every time without the anything-but-admin name assignment.
The symptoms that I acquired were that when I added the second database and created a myadmin for it and then registered the model with myadmin.register(My_ModelA), and went to look at the two admin app pages, the one for my new app that used the second database and myadmin and the model My_ModelA looked fine, but my old admin page showed dead links for its models and when I clicked there on a non-dead link for an app (an old app that uses the old database) I got a 404 code to the effect that the page didn't exist.
Also, I don't know that it matters, but I did something different from what
Bernhard Vallant did in the project urlconf:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include('mynewapp.urls')),
url(r'^someword/admin/', include(admin.site.urls)),
)
OK, "someword" is irrelevant--- there for appearances with regard to the end user and not the name of an app or the project. But the associated admin is the one for my old app and old database. Note the autodiscover() inclusion. There's some murky language in the docs to which Bernhard Vallant linked regarding its use when the project urlconf is configured as Bernhard Vallant has it with the myadmin import but also with a reference to the default admin.
And for the urlconf for mynewapp I have:
from django.conf.urls import patterns, url, include
from myproject.admin import myadmin
urlpatterns = patterns('',
url(r'/', include(myadmin.urls) )
)
urlpatterns += patterns('mynewapp.views',"... url() stuff for mynewapp's views"),
)
Notwithstanding the utter necessity of naming your AdminSite instance internally to something other than 'admin', I must add that when it came time to jazz up the mynewapp's admin.py file with some admin.ModelAdmin subclassing, it was necessary to indeed use admin.ModelAdmin as the parent class. myadmin is after all an instance of a subclass of AdminSite. As such I gather that it's on a par with admin.site, not with admin.
This is all very confusing to a NOOB like me because admin, with the lower case, looks like an instance, and I am unfamiliar with subclassing instances. So I assume that it isn't.

Related

Django. One project. Separate auth systems and templates for different apps

I have a project with the following structure:
main_app
accounts_app (stores CustomUser model)
my_app1
users_app (inside my_app1)
my_app2
users_app (inside my_app2)
The reason behind separate users_app is that I want to reuse my_app1 and my_app2 in other projects. So I want them to be as separate as possible.
I want to have a separate auth system (custom user model, registration, templates, login/logout redirect, etc) for each app. So for example, let's say I have my-app1 at url localhost:8000/my-app1/. This means that registration will be at /my-app1/signup/, login at /my-app1/login/ and login redirect goes to /my-app1/
I also want to use allauth on some or all apps.
Questions:
Does this project structure even make sense? (yes/no)
Is it possible to have separate signup/sigin/etc templates for each app using allauth? (yes/no - link to doc?) I couldn't find the answer to this.
How do I avoid DB conflicts with migrations when creating custom user for each app? Right now I'm inheriting from AbstractUser in each app's model.py, like so: class MainCustomUser(AbstractUser), class AppOneUser(AbstractUser), class AppTwoUser(AbstractUser) But that doesn't seem to work.
Answers to these questions will serve me as guidance in the right direction, right now I sort of confused myself a bit.
settings.py:
...
# django-allauth config
SITE_ID = 1
LOGIN_REDIRECT_URL = 'main_app:index'
ACCOUNT_LOGOUT_REDIRECT = 'main_app:index'
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
)
...

Certain models not showing up in django 4 admin despite being registered

Using django 4.0.3 and the restframework.
I have serval models registered in django admin:
#admin.register(models.Drug)
class DrugAdmin(admin.ModelAdmin):
list_display = ('apl_label', 'name', 'drug_class', 'atc_code', )
#admin.register(models.Organism)
class OrganismAdmin(admin.ModelAdmin):
list_display = ('apl_label', 'long_name', 'short_name', 'genus', 'flagged', 'notes')
....
For some reason, some o fthe models are not showing up in the admin view. In this example, Organism shows up, but Drug is hidden. I can go to http://localhost:8000/admin/api/drug/ and access this admin page, but it is not listed under http://localhost:8000/admin/. There is no error message either. I did run makemigrations and migrate.
Permissions are only set globally in settings.py:
...
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
],
It is always the same models not showing up. I tried deleting the database and creating everything from scratch. No luck. Why does Django decide to not show certain models?
But when I go to http://localhost:8000/admin/api/organism/ all models show up in the side bar:
I tried registering the admin page with admin.site.register(Drug), but that did not change anything.
If this solves your problem you can use this. Or you can check this to understand is the problem because of your admin.py or not.
This will work properly:
from django.contrib import admin
from .models import (
Drug,
Organism,
)
admin.site.register(Drug)
admin.site.register(Organism)
That should not happen. Your code seems perfectly fine to me. Make sure your top imports contain the following lines too:-
from django.contrib import admin
from . import models
If your models don't have any extra customization like custom fieldsets and/or custom section-titles, you can try using the regular old admin.site.register(models.modelname). Maybe the decorator is malfunctioning for you for some reason, though I have never seen that happen before.

admin specific app in django

I'm using Django 1.11
I want to create an admin specific app which is only accessible by admin interface.
I want to create an app to add country and state records which can be added or edited only by Admin from /admin.
Also, these records can be used by any application to populate a select field in adding a record like address.
If I create country app in mydangoapp/country and add URL to mydangoapp/mydangoapp/urls.py then it can be accessed by other users too by www.example.com/country which I don't want.
Where to create a model for this? Is it possible to create an admin specific app only?
Every app can be used only as admin specific till the time you don't give a urlpatterns for that app to be accessed by users.
So, you just create an app, make models, register them. But don't write views, forms and urls for that app.
In your case you should do something like that in your mydjangoapp urls.py:-
from country import views as country_views
urlpatterns = [
url(r'^admin/custom_prefix/country/', include('country.urls')),
url(r'^admin/', admin.site.urls),
]
Make sure u enter it in this order(i.e. before the r'^admin/' regex) in urlpatterns list.
Hope this solves your issues :-)

Two different templates for django admin

I'd like to open up the django admin of a new project I'm working on to our users as well as our staff. The problem I'm having is that users and admins have different ways of using the software, and having the same interface be shared between the two groups would lead to inefficiencies.
Is it possible to have the django admin use a specific template if the user is or isn't staff? Or would I need to create two different admin sites?
You need to create different instances of django.contrib.admin.sites.AdminSite
Docs
Example usage,
# admin.py
from django.contrib.admin.sites import AdminSite
new_admin = AdminSite(name='My New Admin Panel')
new_admin.index_template = "new_admin/index.html"
# urls.py
from myproject.admin import new_admin
(r'^new_admin/(*.)', new_admin.urls)

New URL on django admin independent of the apps

I am using django 1.4 and Python 2.7.
I just have a simple requirement where I have to add a new URL to the django admin app. I know how to add URLs which are for the custom apps but am unable figure out how to add URLs which are of the admin app. Please guide me through this.
Basically the full URL should be something like admin/my_url.
UPDATE
I want a way after which I can as well reverse map the URL using admin.
+1 for Jingo's answer to your original question. With your clarifying comment to the answer in mind:
Such a URL is not "independent of the apps", it is a URL for the app "admin".
Adding a URL to the admin site is similar to ModelAdmin, by overriding get_urls():
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-views-to-admin-sites
EDIT:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.AdminSite
is an admin site, by default "the" admin site is instantiated as "django.contrib.admin.site" (and then e.g. your ModelAdmin's are registered against that). So you can subclass AdminSite for your own MyAdminSite and re-define get_urls() there:
from django.contrib.admin import AdminSite
class MyAdminSite(AdminSite):
def get_urls():
...
...
my_admin_site = MyAdminSite()
...
my_admin_site.register(MyModel, MyModelAdmin)
Make sure you use my_admin_site in urls.py instead now:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#hooking-adminsite-instances-into-your-urlconf
Regarding the actual contents of get_urls(),see
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls
(of course calling super() of MyAdminSite). Also note the convenient "admin_view" wrapper mentioned there.
P.S.: In theory, you could also just define get_urls() and then monkeypatch the default admin site so that it uses your get_urls() but I don't know if that would actually work - you'd probably have to monkeypatch right after its "first" import...
Just put your desired url mapping before the admin mapping in your root urls.py. The first match for the request will be taken, because django goes the url mappings from top to down. Just remember that you don't use an url the admin normally needs or provides because this will never match with a custom mapping in front of it. HTH!