I am trying to add a custom/overridden AdminSite because I need a different template for the Admin. I did everything as the Docs said:
https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#overriding-the-default-admin-site
project/admin.py
from django.contrib.admin import AdminSite
class NewAdminSite(AdminSite):
index_template = 'admin/index.html'
site_header = 'Administration'
admin_site = NewAdminSite(name='newadmin')
project/apps.py
class NewAdminConfig(AdminConfig):
default_site = 'project.admin.NewAdminSite'
I don't have any other apps, project is my root directory
ofc I added admin_site.urls instead of admin.site.urls to urls.py, created a custom AdminConfig in apps.py, and added that new AdminConfig to installed Apps instead of django.contrib.admin.
The Problem is that I now receive this:
AdminSiteClass = import_string(apps.get_app_config('admin').default_site)
File "C:\Users\User.virtualenvs\ssccms-fGQRLLK4\lib\site-packages\django\utils\module_loading.py", line 24, in import_string
) from err
ImportError: Module "project.admin" does not define a "NewAdminSite" attribute/class
my folder structure:
manage.py
project
admin
settings
urls
apps
static
templates
migrations
workdir
sqlite
media
node_modules
locale
pipfile.lock
pipfile
wsgi
hope this is enough for folder structure, it is the django-shop cookiecutter project example structure
EDIT:
yes, it was definitely a circular import error. My workaround now is simply using the given admin.site by writing:
admin.site.index_template = 'admin/newadminindextemplate.html'
it works! Which is actually all that I wanted. But the Documentation says the following
https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#root-and-login-templates
If you wish to change the index, login or logout templates, you are better off creating your own AdminSite instance.
I tried that:
https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#customizing-the-adminsite-class
instead of the overriding part I pasted in the first link in the question but now there is
django.urls.exceptions.NoReverseMatch: Reverse for 'cascade_texteditor_config' not found. 'cascade_texteditor_config' is not a valid view function or pattern name.
now my new question is:
is it necessary to create your own instance of the index template ? the Documentation says no explanation so are there any problems that I might run into at a later time by doing admin.site.index_template?
I've just hit a similar error. It's a bit confusing, in my case it was due to a circular import.
In my case the following helped:
convert imports from top of the file containing NewAdminSite class to local imports (inside of the function where they're needed
move the instantiation of admin_site variable to a separate file
Neither of those problems is actually visible in the code you've pasted, but may give you an idea what to look for.
Related
Django 1.8
For no obvious reasons, global variable defined in package's module is replaced between its initial assignment and deferred function call.
Minimal Django project is created with django-admin startproject. New empty application added with django-admin startapp simplelib. New app simplelib added to INSTALLED_APPS of project's settings.py.
Bellow is the only added code:
# content of myproject.simplelib.__init__.py
from django.db import models
from django.db.models.signals import class_prepared
def myhandler(sender, **kwargs):
print 'models from myhandler: {}'.format(models)
def direct_call():
print 'models from direct_call: {}'.format(models)
class_prepared.connect(myhandler)
print 'models from top namespace: {}'.format(models)
direct_call()
When project is run with manage.py runserver, following output is produced:
models from top namespace: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'>
models from direct_all: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'>
models from myhandler: <module 'simplelib.models' from '/home/<snip>/Projects/Python/django-projects/myproject/simplelib/models.pyc'>
^^^^^^^^^^^^^^^^
See, when signal handler function is invoked, modules global variable is changed.
There is no other project's code. It has to be altered by Django itself.
Note: above described effect applies only when simplelib is placed at the start of INSTALLED_APPS tuple. When added at the end, models still points to django.db.models, as expected.
Any idea what's going here ?
This is normal Python behaviour.
When you import a submodule, that submodule is set as an attribute on the parent module. In this case, when simplelib.models is imported, the models submodule is set on the parent module simplelib. The parent module namespace is the same as that module's __init__.py global namespace. This will overwrite the old value.
If you put simplelib as the first entry in INSTALLED_APPS, its models submodule will be the first models module imported by Django. This will replace the simplelib.models attribute before any model fires the class_prepared signal. On the other hand, if you put simplelib at the end of INSTALLED_APPS, Django will load simpellib.models as the last models module. Any models that are imported before that will fire the class_prepared signal before simplelib.models is imported, and before the models attribute is replaced with the submodule.
If I want to subclass a module such as django.contrib.sessions.backends.db.SessionStore so that I can override a lot of its default behaviour, what is the standard way of doing this in Django?
Suppose I create a file called mydb.py:
from django.contrib.sessions.backends.db import SessionStore as DBSessionStore
class SessionStore(DBSessionStore):
...
If my project has this structure below, is it best practice to put, mydb.py in a backends directory under project's folder?
myproject
myproject/manage.py
myproject/myproject
myproject/myproject/wsgi.py
myproject/myproject/__init__.py
myproject/myproject/settings.py
myproject/myproject/urls.py
myproject/db.sqlite3
myproject/myapp
myproject/myapp/tests.py
myproject/myapp/admin.py
myproject/myapp/__init__.py
myproject/myapp/models.py
myproject/myapp/apps.py
myproject/myapp/migrations
myproject/myapp/migrations/__init__.py
myproject/myapp/views.py
myproject/myapp/urls.py
myproject/backends
myproject/backends/__init__.py
myproject/backends/mydb.py
myproject/__init__.py
Is settings.SESSION_ENGINE='backends.db' a reasonable standard to avoid namespace collisions? Is it a general rule of djamgo configurations that the current project is included in the python search path?
You should refer to it as to the file:
SESSION_ENGINE = 'python.path.mydb'
Django docs is missing this little detail. In
https://docs.djangoproject.com/en/2.2/_modules/django/contrib/sessions/middleware/ line 12 (django 1.9), you can find this:
self.SessionStore = engine.SessionStore
So it's literally taking the SessionStore class from engine you provided in settings. SESSION_ENGINE.
'I have a package called foo.package. And I also have a content item called mydocument.py. As a standard structure, inside foo/package I have browser, content, profiles, etc. What I want to achieve is to create a customized add template for my content item which is mydocument.
I have read the article from this link http://docs.plone.org/external/plone.app.dexterity/docs/advanced/custom-add-and-edit-forms.html
What I have done is that I created a file inside browser directory and named it as mydocumentaddform.py. Also, inside my browser directory I have templates directory.
The code inside mydocumentaddform.py:
from five import grok
from plone.directives import dexterity, form
from Products.CMFCore.utils import getToolByName
grok.templatedir('templates')
class mydocumentaddform(dexterity.AddForm):
grok.name('foo.package.mydocument')
form.wrap(False)
Inside browser/templates directory I created the template mydocumentaddform.pt. However, my customized mydocumentaddform template was not rendered as I add the mydocument content, since inside the template I added js script to detect whether the customized add template override the default add template. As I view my instance, there is a UserWarning that there is an unassociated template configuration which points to my add template: ~... /foo/package/browser/templates/mydocumentaddform.pt
Is there anyone who have encountered the same problem? Or is there any other way to do this? Thanks.
*Yes I forgot to include the quotes here on grok.name.
Update:
I found a temporary solution, inside the class ViewPageTemplateFile. Here's the updated code:
from five import grok
from plone.directives import dexterity, form
from Products.CMFCore.utils import getToolByName
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
grok.templatedir('templates')
class mydocumentaddform(dexterity.AddForm):
grok.name('foo.package.mydocument')
template = ViewPageTemplateFile('templates/mydocumentaddform.pt')
form.wrap(False)
The customized add template was read, however, still my instance always says that the template that I used is still unassociated. As I also observed, when I replace the base class into dexterity.DisplayForm, the instance error is gone. With this temporary solution, I am not sure of any possible effect in the future due to this persistent error.
I see some issues in your code: you're missing the quotes on the name:
grok.name('foo.package.mydocument')
you need to define the context:
grok.context(IMyDocument)
did you declare an add-on layer? then you need:
grok.layer(IMyLayer)
you can find a working example in collective.nitf.
In my views.py I have a piece of code that checks if a model inherits from an other model.
def inherits_from_animal(some_animal):
return Animal in inspect.getmro(some_animal)
Now in my views.py this works but in my tests it's failing because the name of the project gets added to the class name.
So if I have a project named zoo and an app named animals it looks like:
views.py:
<class 'animals.models.Animal'>
tests.py:
<class 'zoo.animals.models.Animal'>
Could anybody explain why this is happening and how I could fix it?
Update:
Seems to only be happening to an abstract model.
The problem is manage.py. If you put django apps inside other packages you should use their fully qualified module name for imports and as a corrolary in INSTALLED_APPS.
It still works if you omit the parent package name, because manage.py temporarily hacks sys.path to import the module that contains the settings module. Then nose does its own import magic and is unable to reproduce the manage.py hack.
I'd recommend to use django-admin.py instead of manage.py as it does not do any import tricks.
There is no concept of a project in django. Just treat everything as plain python packages and control your PYTHONPATH.
the inspect module is doing probably something hinky.
Python has the builtin function issubclass() for just this occasion!
def inherits_from_animal(some_animal):
return issubclass(some_animal, Animal)
although i dont see why you couldnt just use issubclass wherever you are using inherits_from_animal now ;)
Given a class C in Python, how can I determine which file the class was defined in? I need something that can work from either the class C, or from an instance off C.
The reason I am doing this, is because I am generally a fan off putting files that belong together in the same folder. I want to create a class that uses a Django template to render itself as HTML. The base implementation should infer the filename for the template based on the filename that the class is defined in.
Say I put a class LocationArtifact in the file "base/artifacts.py", then I want the default behaviour to be that the template name is "base/LocationArtifact.html".
You can use the inspect module, like this:
import inspect
inspect.getfile(C.__class__)
try:
import sys, os
os.path.abspath(sys.modules[LocationArtifact.__module__].__file__)
This is the wrong approach for Django and really forcing things.
The typical Django app pattern is:
/project
/appname
models.py
views.py
/templates
index.html
etc.