Module does not define class error while replacing default admin site - python

I'm following a tutorial for the Django admin app and I'm trying a step in which the default admin site is replaced with a custom subclass of AdminSite from django.contrib.admin.
My project structure is:
MyAdminTutorial
|- MyAdminTutorial
|- MyActualApp
|- JustAUserApp
MyActualApp.admin.py:
[...other imports]
from django.contrib.auth.admin import UserAdmin, GroupAdmin
class MyAdminSite(admin.AdminSite):
pass
admin.site = MyAdminSite()
admin.site.register(User, UserAdmin)
admin.site.register(Group, GroupAdmin)
MyActualApp.apps.py:
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'MyActualApp.admin.MyAdminSite'
MyAdminTutorial.settings.py
INSTALLED_APPS = [
"MyActualApp.apps.MyAdminConfig",
# 'django.contrib.admin',
....
"JustAUserApp",
]
If I try to run the development server I get this error:
ImportError: Module "MyActualApp.admin" does not define a "MyAdminSite" attribute/class
Messing around in the debugger i found the error stems from a call to getattr() inside import_string() in django.utils.module_loading.py.
For the current call to import_string() the module name and path are set to MyActualApp.admin, getting the current location in the debug console yields the main MyActualApp directory (the project's), but calling getattr(module, "MyAdminSite") triggers the error above.
I expect the MyAdminSite class to be found, but that's not the case, what is going on in this project, what further checks am I not considering?

It turns out that the line which imports UserAdmin and GroupAdmin from django.contrib.auth.admin must be placed after the declaration of whatever classes I want to declare in admin.py. So that the code looks like this:
[...other imports]
class MyAdminSite(admin.AdminSite):
pass
admin.site = MyAdminSite()
from django.contrib.auth.admin import UserAdmin, GroupAdmin
admin.site.register(User, UserAdmin)
admin.site.register(Group, GroupAdmin)
The code works if modified like this, but I'll leave the question unanswered because I have no idea of what is actually going on.

Related

Facing troubles on bringing the Django admin user tools like welcome, view site, log out on the custom template

I have to override the blocks like branding,site_title, and index title to a custom template. But the user tools are not displaying.
How I get.
How I want.
You can update the Site Header from your main urls.py. Just add in:
from django.contrib import admin
....
admin.site.site_header = "the title you want"
If you want to customise the admin site alot, you will likely want to subclass/override the default admin site. The documentation has most the info you need.
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#customizing-the-adminsite-class
If you’d like to set up your own admin site with custom behavior, you’re free to subclass AdminSite and override or add anything you like. Then, create an instance of your AdminSite subclass (the same way you’d instantiate any other Python class) and register your models and ModelAdmin subclasses with it instead of with the default site. Finally, update myproject/urls.py to reference your AdminSite subclass.
app/admin.py
from django.contrib.admin import AdminSite
from .models import MyModel
class MyAdminSite(AdminSite):
site_header = 'Monty Python administration'
admin_site = MyAdminSite(name='myadmin')
admin_site.register(MyModel)
project/urls.py
from django.urls import path
from myapp.admin import admin_site
urlpatterns = [
path('myadmin/', admin_site.urls),
]

Signals.py file not being recognized in django

I am working on follow/unfollow system and I need to add a signals.py file to make the follower count workl, but after I started investigating, I realized that the signals.py file was not being called because it is not on the pycache folder of the app. What can I do to make this file be recognized by django??
apps.py (this is what I tried)
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
def ready(self):
import accounts.signals
If you need to see more code or have any questions please let me know in the comments;)
You need to load the module. For example in the AppConfig. In the apps.py you can specify an AppConfig [Django-doc], and load the signals with:
# accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
# …
def ready(self):
from accounts import signals # noqa
In the __init__.py you also should set this as the default AppConfig:
# accounts/__init__.py
default_app_config = 'accounts.apps.AccountsConfig'

Django custom AdminSite and ModelAdmin

I have overridden standard AdminSite with my own one:
project/admin/base.py:
from django.contrib import admin
class MyAdmin(admin.AdminSite):
...
my_admin = MyAdmin()
and registered some application's model with it:
fact/admin.py:
from django.contrib import admin
from project.admin.base import my_admin
from models import Fact
class FactAdmin(admin.ModelAdmin):
fields = ('section', 'description')
my_admin.register(Fact, FactAdmin)
How can I get this model displayed on an index page? I can't use autodiscover as stated here: How to use custom AdminSite class?
The workaround suggested in that question also doesn't work for me and I'd like to make it it a more clean way.
The documentation only states that
There is really no need to use autodiscover when using your own AdminSite instance since you will likely be importing all the per-app admin.py modules in your myproject.admin module.
I don't import per app modules in project.admin module though.
So is there any way to tell custom AdminSite about the registered model and show it on the index?
Edit: I have hooked URLs and I see my_admin, not admin. With standard admin everything works correctly. Here is the code of project/urls.py:
from django.conf.urls import patterns, include, url
from admin.base import my_admin
urlpatterns = patterns('',
...
url(r'^admin/', include(my_admin.urls, app_name='admin')),
)
I think you need to do:
from django.contrib import admin
class MyAdmin(admin.AdminSite):
...
admin.site = MyAdmin()

admin.py for project, not app

How can I specify a project level admin.py?
I asked this question some time ago and was just awarded the Tumbleweed award because of the lack of activity on the question! >_<
Project:
settings.py
admin.py (This is what I am trying to get to work)
...
App
admin.py (I know how to do this)
For example, admin.autodiscover() is typically put in the project level urls.py (yes, it will be automatically included in 1.7)
I would like to move this, and the following, into their own admin.py file:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
UserAdmin.list_display = ('email', 'first_name', 'last_name', 'is_active')
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.autodiscover()
I tried doing just that, making an admin.py file and adding the code into it. Didn't work.
I tried adding a project level folder called admin, added an __init__.py and threw admin.py into the admin folder. Didn't work
Further I tried adding this admin folder to INSTALLED_APPS in settings.py. No luck.
From the admin.autodiscover doc string:
Auto-discover INSTALLED_APPS admin.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
may want.
And here is the complete function very well documented:
def autodiscover():
"""
Auto-discover INSTALLED_APPS admin.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
may want.
"""
import copy
from django.conf import settings
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule
for app in settings.INSTALLED_APPS:
mod = import_module(app)
# Attempt to import the app's admin module.
try:
before_import_registry = copy.copy(site._registry)
import_module('%s.admin' % app)
except:
# Reset the model registry to the state before the last import as
# this import will have to reoccur on the next request and this
# could raise NotRegistered and AlreadyRegistered exceptions
# (see #8245).
site._registry = before_import_registry
# Decide whether to bubble up this error. If the app just
# doesn't have an admin module, we can ignore the error
# attempting to import it, otherwise we want it to bubble up.
if module_has_submodule(mod, 'admin'):
raise
So the only thing autodiscover does for you is look for some module called admin.py inside installed app directories, hence you can put your admin.py where you want just make sure you import it, this make the code in it (registration of models ect..) get executed.
IMPORTANT: I'm not sure the correct moment for importing your custom-path admin.py. But it's sure you have to import it after load all the related apps.
All admin.autodiscover() is import all the admin files it finds. There is no point putting the line itself in an admin files.
To understand why it's not working, you need to realise how it works. What it does is import the admin.py files inside registered apps. A registered app is a package included in INSTALLED_APPS that has a models.py. That's worth repeating: an app isn't considered if it doesn't have a models.py - even a blank one will work, but without it the package isn't an app.
So if you create a blank models.py in your directory, ensure that that directory is in INSTALLED_APPS, and move admin.autodisover back to urls.py, everything will work.
Edit
I'm not exactly sure what you do want, and why. As I mentioned, autodiscover depends on apps; but as I also mentioned, all autodiscover does is import all the admin files. If you really don't want to follow best practices, all you need to do is import your admin file manually: you can do that in the same place that you normally call autodiscover from, ie in the main urls.py.
Sooner or later, a heavily customized admin class will most likely need a project wide admin.py, as it is the place to register all per-app admins that are not being auto-discovered anymore. The documentation mentions this, but there is no extensive example to illustrate it:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#customizing-the-adminsite-class
Note that you may not want autodiscovery of admin modules when using your own AdminSite instance since you will likely be importing all the per-app admin modules in your myproject.admin module. This means you need to put 'django.contrib.admin.apps.SimpleAdminConfig' instead of 'django.contrib.admin' in your INSTALLED_APPS setting.
There is a bit outdated but more or less valid example in the wiki as well for multiple admin sites:
https://code.djangoproject.com/wiki/NewformsAdminBranch
# project-level admin.py
from django.contrib import admin
from myproject.myapp.models import Book, Author
from myproject.anotherapp.models import Musician, Instrument
site1 = admin.AdminSite()
site1.register(Book)
site1.register(Author)
site2 = admin.AdminSite()
site2.register(Musician)
site2.register(Instrument)
I'm curious to see if this gets downvoted. It seems to work, but it feels wrong. ;-)
The question is how to override the UserAdmin settings.
Put an admin.py in your project folder (alongside settings.py)
from django.contrib.auth import admin
from django.contrib.auth.admin import UserAdmin
UserAdmin.list_display = ('email', 'first_name', 'last_name',
'is_active', 'date_joined', 'last_login',
'is_staff')
UserAdmin.ordering = ['-date_joined']
add your project to installed_apps (this seems wrong, but I don't know why)
And now you should see the new columns and sort order on /admin/auth/user/
This is working for me with Django 1.11. So far no issues that I can find. What say you StackOverflow?

Django admin.site.register doesn't add my app admin

as a django newbie (I have some exprience with other python webframework like turbogears and bottle but exploring django) I'm trying to auto create the admin management for my app model
in tha main URLS.py I have:
edit:
from django.contrib import admin
admin.autodiscover()
and after that:
urlpatterns = patterns('',
url(r'^appname/',include('appname.urls')),
url(r'^admin/',include(admin.site.urls))
notice this is in the main urls.py and not in the app urls.py
following the tutorial (which did work for me in the tutorial..) I created an 'admin.py' file in the appname folder and there:
from appname.models import Appname
from django.contrib import admin
class appnameAdmin(admin.ModelAdmin):
fieldsets = [various field sets and fields etc ]
admin.site.register(Appname,AppnameAdmin)
and in setting.py I have uncommented
'django.contrib.admin'
I don't get any error in the commandline window and the basic admin screen does appear (auth and sites)
I checked the imports in admin.py in the manage.py shell and everything seemed to work allright, I also tried commenting AppnameAdmin class out and registring just:
admin.site.register(Appname)
but that didn't work eith
I'm guessing I'm missing something obvious - I'll be glad to help with that
using django 1.4 + python 2.72
Check all of these:
There are seven steps in activating the Django admin site:
Add 'django.contrib.admin' to your INSTALLED_APPS setting.
The admin has four dependencies - django.contrib.auth, django.contrib.contenttypes, django.contrib.messages and
django.contrib.sessions. If these applications are not in your
INSTALLED_APPS list, add them.
Add django.contrib.messages.context_processors.messages to TEMPLATE_CONTEXT_PROCESSORS and MessageMiddleware to
MIDDLEWARE_CLASSES. (These are both active by default, so you only
need to do this if you’ve manually tweaked the settings.)
Determine which of your application’s models should be editable in the admin interface.
For each of those models, optionally create a ModelAdmin class that encapsulates the customized admin functionality and options for
that particular model.
Instantiate an AdminSite and tell it about each of your models and ModelAdmin classes.
Hook the AdminSite instance into your URLconf.
Do you have all the other admin dependencies in your installed apps?
Do you have admin.autodiscover() in your URLS.py?
Also, I think your code should look something more like this:
from projectname.appname.models import Appname
from django.contrib import admin
class AppnameAdmin(admin.ModelAdmin):
fieldsets = [various field sets and fields etc ]
admin.site.register(Appname,AppnameAdmin)
Have you restarted the server process?
Maybe this helps someone: in my case the problem was solved by stopping and starting the server process, because when you add a new admin.py file it does not reload automatically.
aaargghhh - I found the problem. I saved admin.py in the template/appname/ folder instead of the appname/ folder. so stupid of me. so sorry for the interruption.
Set this in your model admin:
def has_add_permission(self, request, obj=None):
return True
def has_change_permission(self, request, obj=None):
return True
def has_delete_permission(self, request, obj=None):
return True
Check all these:
Restart the server and check again
Add 'models.Model' as a parameter in your class in models.py file
class Classname(models.Model):
Add your app in the 'INSTALLED_APPS' in settings.py, In my case it's 'travello.apps.TravelloConfig'
INSTALLED_APPS = [
'travello.apps.TravelloConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Add 'admin.autodiscover()' in main urls.py
from django.contrib import admin
from django.urls import path, include
admin.autodiscover()
urlpatterns = [
path('', include('travello.urls')),
path('admin/', admin.site.urls),
]
it worked for me!
Nothing above worked for me.
Then I went to Settings, and under Project:MyApp Project Interpreter
I switched the Project Interpreter from Python 3.8(venv) to Python 3.8(MyApp)
And then all my models where registered (could list them in http://localhost:8000/admin/)
Strangely enough, still in admin.py, after "admin.site." the method registered will not be listed as available. But it works anyway.
Go to models.py file and add 'models.Model' as a parameter in your class .
Example:
class className(models.Model)
In your case use below as class name and it will 100% work for you.
class AppnameAdmin(models.Model):
from django.contrib import admin
from .models import modelname
admin.site.register(modelname)
import models in this way
Please consider that some models can be seen only from a superuser.
Try to create one and log-in the admin with that user.
python3 manage.py createsuperuser

Categories