admin specific app in django - 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 :-)

Related

Generic django admin per client

In my django project, i would like to use Django Admin for multiple organization. So in django urls system, i try to use a system like that :
urlpatterns = [
path('<organization>/admin', admin.site.urls)
]
With that syntax,on a simple example (default startproject+setup), i got an 'NoReverseMatch' :
Reverse for 'logout' with no arguments not found. 1 pattern(s) tried: ['(?P<client>[^/]+)\\/admin\\/logout\\/$']
At the end i try to implement a system like that:
Basic auth user (maybe change backend for email)
Organization:
Organization_User (inherit from basic auth or relationship)
Organization_Area (manyTomany with Organization_User)
and for urls i don't know if syntax bellow works:
www.example.com/admin => admin SuperUser only
www.example.com/organization1/admin => Admin for Organization 1
www.example.com/organization2/admin => Admin for Organization 2
I'm asking myself, is it possible to do that only with Django Admin system ?
For example, use one Admin and try URL filtering or use AdminSite inheritence
Best Regards,
Could you just assign users to groups depending on which organisation they belong to? Then alter the groups permissions so they can only see the parts you wish them to have access to.

rest api does not list all users

I followed the very first page in the tutorial - created UserSerializer and UserViewSet. So, when I go to 127.0.0.1/myapp/ I see a nicely looking Django Rest framework api page. But the problem is, I see an empty list of users:
{}
To solve this problem and to see users in the database I created two new users manually:
user = User(username='Bob',password='Bob')
user.save()
user = User(username='John',password='John')
user.save()
And if I connect to sqlite and select from auth_user table, I see two rows corresponding to Bob and John, but if I refresh 127.0.0.1/myapp/, I still see an empty list of users {}. I do not know how to solve this.
EDIT
I created a user another way:
User.objects.create_user(username='admin', password='admin')
and now I'm able to login, but still when I go to 127.0.0.1/myapp/ I see {}.
EDIT
I even visited admin page and created a new user. But {} still remains. It seems as if the very first "most simple" official example does not work. I can not list users and see them in my app.
Example uses users endpoint
router.register(r'users', UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
You are using myapp endpoint, and not telling us how you hooked it up in your urls.py.

Django 'Sites' Model - what is and why is 'SITE_ID = 1'?

I am trying to work with Sites Model of Django.
I dont quite understand why SITE_ID should be SITE_ID = 1.
in the docs:
The ID, as an integer, of the current site in the django_site database
table. This is used so that application data can hook into specific
sites and a single database can manage content for multiple sites.
why 1? what is the current site? this is not clearly explained in the docs.
lets say, I have www.coolsite.com and some other subdomains like www.wow.coolsite.com and www.awesome.coolsite.com
I want to render different content depending on domain name.
my question is, or better, are:
Do I have to add all those domains into Sites Table in DB?
if so, how should I set SITE_ID in settings? Do I have to set all ids like SITE_ID = 1, SITE_ID = 2.. etc?
what does current site has to do with SITE_ID = 1?
I am a bit confused here.
I thought, each Site (e.g. www.wow.coolsite.com) should be a separate django project so that they can have their own settings.py? and in each of those settings.py's, I will set the id of that page from Sites table? but then there are many django projects which also doesnot make sense to me.
Django was created from a set of scripts developed at a newspaper to publish content on multiple domains; using one single content base.
This is where the "sites" module comes in. Its purpose is to mark content to be displayed for different domains.
In previous versions of django, the startproject script automatically added the django.contrib.sites application to INSTALLED_APPS, and when you did syncdb, a default site with the URL example.com was added to your database, and since this was the first site, its ID was 1 and that's where the setting comes from.
Keep in mind that starting from 1.6, this framework is not enabled by default. So if you need it, you must enable it
The SITE_ID setting sets the default site for your project. So, if you don't specify a site, this is the one it will use.
So to configure your application for different domains:
Enable the sites framework
Change the default site from example.com to whatever your default domain is. You can do this from the django shell, or from the admin.
Add your other sites for which you want to publish content to the sites application. Again, you can do this from the django shell just like any other application or from the admin.
Add a foreign key to the Site model in your object site = models.ForeignKey(Site)
Add the site manager on_site = CurrentSiteManager()
Now, when you want to filter content for the default site, or a particular site:
foo = MyObj.on_site.all() # Filters site to whatever is `SITE_ID`
foo = MyObj.objects.all() # Get all objects, irrespective of what site
# they belong to
The documentation has a full set of examples.
Things would be much easier to understand if Django's default SiteAdmin included the id field in the list_display fields.
To do this, you can redefine SiteAdmin (anywhere in your app, but I'd recommend your admin.py or maybe your urls.py) like this:
from django.contrib import admin
from django.contrib.sites.models import Site
admin.site.unregister(Site)
class SiteAdmin(admin.ModelAdmin):
fields = ('id', 'name', 'domain')
readonly_fields = ('id',)
list_display = ('id', 'name', 'domain')
list_display_links = ('name',)
search_fields = ('name', 'domain')
admin.site.register(Site, SiteAdmin)
After including this code snippet, the ID for each "Site" will be shown in the first column of the admin list and inside the form as a read only field. These 'id' fields are what you need to use as SITE_ID:
The concept is that each different site runs in a different application server instance, launched using a different yourdomain_settings.py that then includes a base_settings.py with the rest of the common configuration.
Each of these yourdomain_settings.py will define its own SITE_ID and all other different settings.py parameters that they need to look and be different from each other (static resources, templates, etc.) then you'll define a DJANGO_SETTINGS_MODULE environment variable pointing to that specific yourdomain_settings.py file when launching the application server instance for that domain.
A further note: get_current_site(request) does need request to be available for it to work. If your code doesn't have one, you can use Site.objects.get_current() that however will need a SITE_ID properly defined in the running application server's settings.
This is a late answer but for anyone else having SITE_ID issues and Site problems.
Inside the database, django has a django_site table with(id, domain, name). This is where django stores the SITE_IDs. Mine was actually 5 in the database but i had it set to SITE_ID=1 in the settings.
Knowing that, i can now go back to the database and clear it to get back to zero or use the actual id in the database.
This is covered in the documentation for the Sites framework:
In order to serve different sites in production, you’d create a
separate settings file with each SITE_ID (perhaps importing from a
common settings file to avoid duplicating shared settings) and then
specify the appropriate DJANGO_SETTINGS_MODULE for each site.
But if you didn't want to do it that way, you can not set SITE_ID at all and just look up the current site based on the domain name in your views using get_current_site:
from django.contrib.sites.shortcuts import get_current_site
def my_view(request):
current_site = get_current_site(request)
if current_site.domain == 'foo.com':
# Do something
pass
else:
# Do something else.
pass
This link explains it:
You’ll want to create separate settings files for each domain you’re adding; each one will need its own MEDIA_URL and other settings. You’ll also want to do two things to make sure everything works out properly for administering the different sites:
Create a new Site object in your admin for each domain, and put the id of that Site into its settings file as SITE_ID so Django knows which site in the database corresponds to this settings file.
In the settings file for your original site (the one with id 1), add the other sites’ settings files to the ADMIN_FOR setting, to let Django know that this one instance of the admin application will handle all of the sites.
Also, if you wanna figure out how to modify models and set the views You may take a look at this link:
https://django.cowhite.com/blog/managing-multiple-websites-with-a-common-database-in-django-the-sites-framework/

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)

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

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.