I'm fairly new to Django.
How do I prevent staff users from logging into the Django admin panel? I still want them to be identified as staff, but do not want them to be able to log into the admin panel.
I am using the default Django admin panel.
Thanks
You can limit admin access to only superusers by overriding the default admin site and overriding the has_permission method in your custom admin site to only return True for superusers
myproject/admin.py
from django.contrib import admin
class MyAdminSite(admin.AdminSite):
def has_permission(request):
return request.user.is_active and request.user.is_superuser
myproject/apps.py
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'myproject.admin.MyAdminSite'
myproject/settings.py
INSTALLED_APPS = [
...
'myproject.apps.MyAdminConfig', # replaces 'django.contrib.admin'
...
]
Related
Is there anyway to delete django admin login page (mySite.com/admin) and use the user session which has logged in in main site (mySite.com)?
If any code is needed please tell me to add.
My middleware in settings.py is:
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
.
.
.
.
.
]
update:
the reason is I want the admin first logs in with his account in website then open admin page. Other users would see admin link, but after clicking that they would see a message you don't have permission to see or change anything and they see nothing else. I just want myWebsite.com/admin be redirected to admin:index if the user is logged in and to myWebsite.com if he is not.
You can easily do this using your main urls.py file. Just redirect the admin login URL to your custom log-in page on your website. In the below sample you will notice the normal admin.site.urls being used AFTER admin/login and admin/logout (I assume you'll also have a custom log-out page). With these custom views being first they will take precedence and be used instead of the ones in admin.site.urls.
urlpatterns = [
url(r'^admin/login', your_custom_login_view, name='custom_login_page_admin'),
url(r'^admin/logout', your_custom_logout_view, name='custom_logout_view_admin'),
url(r'^admin/', admin.site.urls),
]
Create a custom subclass of AdminSite and overwrite the login() method. Something like this:
class CustomAdminSite(admin.AdminSite):
def login(self, request, extra_context=None):
if not request.user.is_authenticated:
# not authenticated, redirect to main login page
login_path = reverse('login')
return HttpResponseRedirect(login_path)
if self.has_permission(request):
# Already logged-in, redirect to admin index
index_path = reverse('admin:index', current_app=self.name)
return HttpResponseRedirect(index_path)
else:
# Logged in, but doesn't have required permissions
return render(...) # render a template with your error message
Follow the Django documentation on how to customize the AdminSite class.
Why you want to do that? Admin Page is for admin purposes, just dont access /admin/ path anymore or just remove admin from your urls.py, doign that you will not be able to access admin pages anymore...
But if you want to make your users access your django admin native pages using your custom login page, just make sure to tag your users with is_staff so they can access native django pages...
models.py
from django.contrib.auth.models import User
class CustomUser(User):
... # Your new fields
views.py
def create_user(request):
...
user, created = CustomUser.objects.get_or_created(
... # Your Custom + User Django fields
is_staff = True # This will allow this user to access the admin page
)
If you want allow all your users to access your django admin pages without need to use Django Login Page you can override your CustomUser model to set all users with is_staff
class CustomUser(User):
... # Your new fields
def save(self, *args, **kwargs):
if not self.id: # This indentify if the registry is new...
self.is_staff = True
super(CustomUser, self).save(*args, **kwargs)
Obs.: Make sure your User models extends the Django User Auth, there 2... one more complex and one simple, check the docs
https://docs.djangoproject.com/en/2.0/ref/contrib/auth/
All mentioned solutions here might do a good job, but my solution would be a little different: If you want to redirect to your default login page and hide the django-admin, sth. simple like this is a good workaround:
urlpatterns = [
path('admin/login/', RedirectView.as_view(pattern_name='account_login', permanent=True)),
]
Of course the target route (here account_login) can be changed as desired.
I prefer this approach:
on urls.py
from .settings import LOGIN_URL
from django.views.generic import RedirectView,
from django.urls import path, include
from django.contrib import admin
urlpatterns = [
path('admin/login/', RedirectView.as_view(url=LOGIN_URL)),
path('admin/', admin.site.urls),
....
]
To disable admin just remove url(r'^admin/', admin.site.urls), from your main urls.py. Another things to clean are 'django.contrib.admin' from INSTALLED_APPS.
A real easy way to accomplish this is by doing 2 things:
Head to your settings.py file and add: ADMIN_ENABLED = False
Head to your main urls.py file which should have something that looks like:
from django.urls import path, include
urlpatterns = [
# path('admin/', admin.site.urls),
path('', include("landing.urls")),
]
and comment out the path to admin like in the above snippet.
Cheers!
When I am developing I constantly need to access data from the admin panel but I do not wish to add all models in admin.py since I do not want them to be accessed in production.
Is there a way to show all models in the admin panel in the development environment and hide (part of) them in production automatically?
I think that would be as simple as this:
# my_app/admin.py
from django.contrib import admin
from django.conf import settings
from .models import MyModel, AnotherModel
class MyModelAdmin(admin.ModelAdmin):
pass
class AnotherModelAdmin(admin.ModelAdmin):
pass
# conditional registration of models
if settings.DEBUG:
admin.register(MyModel, MyModelAdmin)
admin.register(AnotherModel, AnotherModelAdmin)
I use the admin account login to the /admin/:
Why there are only these field I can edit?
I have write tons models in my project. why do not show up?
Put following code in your django app's admin.py file
from django.apps import apps
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered
app_models = apps.get_app_config('my_app').get_models()
for model in app_models:
try:
admin.site.register(model)
except AlreadyRegistered:
pass
ref : https://docs.djangoproject.com/en/2.0/ref/contrib/admin/ and Register every table/class from an app in the Django admin page
I have a blog made with Django where I write posts in markdown. I would like to add a view in the bottom of the admin page for each instance of the class Entry (my blog post class) such that I can get a preview of what the markdown looks like, while I'm writing. Just as you get a preview here on Stack Overflow when you create a new post.
I already have an admin class extending ModelAdmin:
class EntryAdmin(admin.ModelAdmin):
list_display = ('title','created')
prepopulated_fields = {'slug': ('title',)}
Is it possible to modify ModelAdmin further, such that it loads a certain html file (blogpost.html) and shows it in the bottom of the admin page?
I made a picture to show exactly what I mean:
NB: I know there are various tools such as Django admin plus, that allows one to add views to the admin interface, but not for each instance of an object.
You can use markdownx for that:
pip install django-markdownx
project settings.py
INSTALLED_APPS =
#. . . .
'markdownx',
]
project urls.py
urlpatterns = [
#[...]
url(r'^markdownx/', include('markdownx.urls')),
]
and then collect static files.
python3 manage.py collectstatic
your models.py
from markdownx.models import MarkdownxField
class MyModel(models.Model):
myfield = MarkdownxField()
your app admin.py
from django.contrib import admin
from markdownx.admin import MarkdownxModelAdmin
from .models import MyModel
admin.site.register(MyModel, MarkdownxModelAdmin)
This should work.
I've tried to override AdminSite class with my own custom class. I followed tutorial from django's documentation: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#customizing-adminsite but it didn't work. To be specific, I'd like to override original AdminSite with my own class and not just add another admin site into my project.
I've created my custom class MyAdminSite which inherit from class
from django.contrib.admin import AdminSite
class MyAdminSite(AdminSite):
pass
Then in my app urls.py I've add:
from django.conf.urls import url, include
import django.contrib.admin as admin
from .admin_site import MyAdminSite
admin.site = MyAdminSite()
admin.autodiscover()
urlpatterns = [
url(r'^', admin.site.urls),
]
It seemed to work, but admin models are register to AdminSite insted of MyAdminSite.
I tried three ways of register models to my custom site:
#admin.register(Model)
class ModelAdmin(model.AdminModel):
...
This way models are registered to original AdminSite.
Second way:
#admin.site.register(Model):
class ModelAdmin(model.AdminModel):
...
That don't work and cause exception. The ModelAdmin class isn't passed to register method.
Last way:
class ModelAdmin(model.AdminModel):
...
admin.site.register(Model, ModelAdmin)
That works, but on admin site I can see only my models not models from Django admin (Users and Groups).
How can I permanently override admin.site and register all models to MyAdminSite?
From myapp/admin.py:
from django.contrib.auth.models import Group, User
from django.contrib.auth.admin import GroupAdmin, UserAdmin
from django.contrib.admin import AdminSite
from django.contrib import admin
from .models import MyModel #This is my app's model
# Custom admin site
class MyAdminSite(AdminSite):
site_header = 'My Project Title'
site_title = 'My Project Title Administration'
index_title = 'My Project Title Administration'
# You can add on more attributes if you need
# Check out https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#adminsite-objects
# Create admin_site object from MyAdminSite
admin_site = MyAdminSite(name='my_project_admin')
# Register the models
class MyModelAdmin(admin.ModelAdmin):
list_display = ('id', 'description')
admin_site.register(MyModel, MyModelAdmin)
# Create and register all of your models
# ....
# This is the default Django Contrib Admin user / group object
# Add this if you need to edit the users / groups in your custom admin
admin_site.register(Group, GroupAdmin)
admin_site.register(User, UserAdmin)
From myproject/urls.py
from django.conf.urls import url
from django.contrib import admin
from myapp.admin import admin_site ##! Important..Import your object (admin_site) instead of your class (MyAdminSite)
urlpatterns = [
url(r'^admin/', admin_site.urls), #Now all /admin/ will go to our custom admin
]
I didn't found the solution to my problem, but I have made a workaround.
First we need to create module in our app (e.g. admin.py) and then extend class AdminSite:
from django.contrib.admin import AdminSite
class MyAdminSite(AdminSite):
...
Then on bottom of module we need to create instance of our MyAdminSite and register built-in models from Django:
site = MyAdminSite()
site.register(Group, GroupAdmin)
site.register(User, UserAdmin)
Necessary imports:
from django.contrib.auth.models import Group, User
from django.contrib.auth.admin import GroupAdmin, UserAdmin
In our site url module we need to override original site object:
from .admin import site
admin.site = site
admin.autodiscover()
...
url(r'^admin/', admin.site.urls)
...
Last change we need to do is register our models. One thing we need to remeber is that we can't use register as decorator like that:
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
...
or:
#admin.site.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
...
We need to define our ModelAdmin class and then call register on our MyAdminSite object:
class MyModelAdmin(admin.ModelAdmin):
...
admin.site.register(MyModel, MyModelAdmin)
This is the only solution that is working for me.
I faced a similar problem. I used Django 2.1 and the hook from the comments above didn't work for me. And also I was not able to import GroupAdmin and UserAdmin, like so
from django.contrib.auth.models import Group, User
from django.contrib.auth.admin import GroupAdmin, UserAdmin
Importing GroupAdmin or UserAdmin broke the code for some reason. I was not able to define the exact reason.
So my workaround was (in project/urls.py):
from django.conf.urls import include, url
from django.contrib.admin import site
from project.admin import myadmin
myadmin._registry.update(site._registry)
urlpatterns = [
url(r'^admin/', myadmin.urls),
]
The idea here is to copy registered models from default admin site. Maybe it's not good to do so, but I could not find anything else working.