Modifying and creating sites in djangos admin app - python

I have to include multiple changes to djangos admin panel, so I decided to fork the django admin app into my own django project.
As I was working with this admin app I recognized, that the site registration and template handling differs from the apps, that are normally created in django.
For instance, I want to keep the old admin index.html template and view, for backup and safety reasons but the landing page should be replaced by a custom page.
For that of course I need to change admin/templates/index.html and /admin/sites.py respectively.
I copied the old index function in admin/sites.py to old_index.py and created a old_index.html in the template folder.
But if I try to reference to old_index.html in my new index.html with
old index
I got an NoReverseMatch-Exception thrown. Unfortunately I did not found more information about how the django admin app itself register new views and sites, so an example or description would be helpful.
Creating separate views for the admin app in the distinct other apps in my project is no real option, due the high amount of changes, that need to be done.
The main urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'django_project.views.home', name='home'),
url(r'^polls/', include('other_app.urls', namespace="other_app")),
url(r'^admin/', include(admin.site.urls)),
)
The admin app itself does not provide a urls.py file and the views.py is exactely the same as in django.contrib.admin I just copied the function index to a new function called old_index, referencing to a template old_index.html.
Maybe the point did not get so clear, as I expected. I copied the whole admin app in my project and want to add a custom defined site to it, regardless where. But I failed to understand how sites and views are registered in the admin app itself, because the way is different from the custom apps you create normally in django.
So, is it possible (and how) to add a custom site in the django.contrib.admin app?

I think you need to create your own AdminSite for custom purposes and keep default as it is. More about this you can find here: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#adminsite-objects and here https://docs.djangoproject.com/en/dev/ref/contrib/admin/#multiple-admin-sites-in-the-same-urlconf
Update:
You need to edit get_urls method of AdminSite class - add:
url(r'^$', wrap(self.old_index), name='old_index')
to urlpatterns variable. And rename old index method to old_index.

Related

blocking unwanted urls in django

I have added account app to installed_apps in my django project.
also I have added urls of account app as like below:
(r"^account/", include("account.urls"))
Its working fine.
Now I had to override SignupView class of account app. This is also working fine.
Now I have created a new class CreateUser(SignupView) and I want that only admin user will be able to create user. So I added a different url for CreateUser(SignupView) view.
Now I want that account/signup url with view SignupView will not be accessible anymore.
How can I block this particular url by keeping other urls active of account app as this is a library.
You can add a specific entry for the one URL that you wish to block before you include the packages urls.py. This will take precedence as Django loops over URLs in order looking for the first match
from django.views.generic.base import RedirectView
urlpatterns = [
path('account/signup', RedirectView.as_view(url='/')),
path('account', include('account.urls')),
]

Django project on two domains - limiting access to urls/views

I am working on django project.
It utilizes multiple small apps - where one of them is used for common things (common models, forms, etc).
I want to separate whole for project to two domains, i.g.:
corporatedomain.com and userportal.com
I want corporatedomain.com to use different urls, same for userportal.com.
Is that possible? If so, how can I do this? How should I configure my urls?
Maybe you can look at the Django Site Framework. From Django official documentation:
Django comes with an optional “sites” framework. It’s a hook for associating objects and functionality to particular Web sites, and it’s a holding place for the domain names and “verbose” names of your Django-powered sites.
You can use then this approach
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
if 'userportal' in current_site.domain:
urlpatterns = patterns('',
url(r'', include('userapp.urls')),
url(r'^admin/', include(admin.site.urls)),
)
else:
urlpatterns = patterns('',
url(r'', include('corporateapp.urls')),
url(r'^admin/', include(admin.site.urls)),
)
You should add as many entries as you need to Site Table and add django.contrib.sites app in your INSTALLED_APP and also a SITE_ID variable to your settings bound with the correct site ID. Use SITE_ID = 1 when no domain info are available (for example in your development session). More info about SITE_ID in this post).
In my settings I use the following approach:
SITE_ID = os.environ.get('SITE_ID', 1)
where I have set the right SITE_ID variable in each of my enrivorments.
You will have separate settings file anyway so define different ROOT_URLCONF for each domain.
UPDATE: If you don't want to use different settings then you have to write the middleware which will change the request.urlconf attribute using the HTTP_HOST header. Here is the example of such middleware.

Create a view in django

Very new to django. I'm using version 1.5.2 and I just did a fresh install. I'm using the django development server; I'll be moving to Apache down the road, but I want to understand the django's particular flavor of MVC methodology before doing taking that step.
So I start up the django server with `python manage.py runserver 0.0.0.0:8000' through the terminal in my project directory (django_books). I get this error:
ViewDoesNotExist at /
Could not import django_books.views.home. Parent module django_books.views does not exist.
So my view doesn't exist. My view.py file is empty because the tutorial I was following did not include one. I'm not sure if this is the problem. If it is, how do I create this file (what goes in it)?
Directory Structure:
django_books
beer (from the tutorial lol)
migrations
__init__.py
models.py
views.py
random_book
(same as beer above)
django_books (this is my actual django project, beer and random_book are apps)
__init__.py
settings.py
urls.py
wsgi.py
media
.gitignore
manage.py
requirements.txt (output from pip freeze command)
urls.py
from django.conf.urls import patterns, include, url
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
url(r'^$', 'django_books.views.home', name='home'),
# url(r'^django_books/', include('django_books.foo.urls')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
)
If you keep your urls.py the way it is, that means you need to create views.py within /django_books/django_books/
Within that file, create a new function called home.
Alternately, if you have any functions inside of /django_books/beer/, you could reference them from urls.py.
All urls.py does is expose a python path to a function and route a URL there. So you can see that you don't have a module or file called views within django_books/django_books, which is why you get the failure.
View is basically a python function that receives HTTP Request and returns HTTP Response.
Quote from docs:
A view function, or view for short, is simply a Python function that
takes a Web request and returns a Web response. This response can be
the HTML contents of a Web page, or a redirect, or a 404 error, or an
XML document, or an image . . . or anything, really. The view itself
contains whatever arbitrary logic is necessary to return that
response. This code can live anywhere you want, as long as it’s on
your Python path. There’s no other requirement–no “magic,” so to
speak. For the sake of putting the code somewhere, the convention is
to put views in a file called views.py, placed in your project or
application directory.
This line url(r'^$', 'django_books.views.home', name='home'), in urls.py points the index / of your site to the home view - you should create it.
Create a python function called home in views.py:
from django.http import HttpResponse
import datetime
def home(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
Restart your development server and visit http://127.0.0.1:8000.
FYI, read the tutorial more carefully, part 3 is about dealing with urls and views.

Why isn't admin.autodiscover() called automatically in Django when using the admin, why was it designed to be called explicitly?

Without putting admin.autodiscover() in urls.py the admin page shows You don't have permission to edit anything (See SO thread).
Why is this so? If you always need to add admin.autodiscover() to edit information using the admin even though you have a superuser name and password for security why didn't the Django developers trigger admin.autodiscover() automatically?.
Before Django 1.7, the recommendation was to put the admin.autodiscover() call in urls.py. That allowed it to be disabled if necessary. Requiring admin.autodiscover() instead of calling it automatically was an example of the Python philosophy 'Explicit is better than implicit' in action. Remember, the django.contrib.admin app is optional, it is not installed on every site, so it wouldn't make sense to always run autodiscover.
Most of the time autodiscover works well enough. However if you require more control, you can manually import specific apps' admin files instead. For example, you might want to register multiple admin sites with different apps in each.
App loading was refactored in Django 1.7. The autodiscover() was moved to the admin app's default app config. That means that autodiscover now runs when the admin app is loaded, and there's no need to add admin.autodiscover() to your urls.py. If you do not want autodiscovery, you can now disable it by using the SimpleAdminConfig instead.
(edit: Obsoleted after Django 1.7+, not necessary more, see Alasdair's answer)
I think it's about giving you finer control. Consider the code of contrib.admin.autodiscover:
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 it will automatically load the INSTALLED_APPS admin.py modules and fail silently when not found. Now, there are cases when you actually don't want that such as when using your own AdminSite:
# urls.py
from django.conf.urls import patterns, url, include
from myproject.admin import admin_site
urlpatterns = patterns('',
(r'^myadmin/', include(admin_site.urls)),
)
in this case, you don't need to call autodiscovery().
There are also other times when you only want to see or edit a subset of apps of your projects through admin, and calling autodiscovery() would not enable you to do that.
Django doesn't require you to use django.contrib.admin on every site - it's not a core module.

Customized views with django-registration

I need to make a very simple modification -- require that certain views only show up when a user is not authenticated -- to django-registration default views. For example, if I am logged in, I don't want users to be able to visit the /register page again.
So, I think the idea here is that I want to subclass the register view from django-registration. This is just where I'm not sure how to proceed. Is this the right direction? Should I test the user's authentication status here? Tips and advice welcomed!
Edit
I think this is the right track here: Django: Redirect logged in users from login page
Edit 2
Solution:
Create another app, for example, custom_registration, and write a view like this (mine uses a custom form as well):
from registration.views import register
from custom_registration.forms import EduRegistrationForm
def register_test(request, success_url=None,
form_class=EduRegistrationForm, profile_callback=None,
template_name='registration/registration_form.html',
extra_context=None):
if request.user.is_authenticated():
return HttpResponseRedirect('/')
else:
return register(request, success_url, form_class, profile_callback, template_name, extra_context)
I had to use the same function parameters, but otherwise just include the test, and if we pass it, continue to the main function.
Don't forget to put this in your URLConf either (again, this includes some stuff about my custom form as well):
top-level URLConf
(r'^accounts/', include('custom_registration.urls')),
(r'^accounts/', include('registration.urls')),
custom_registration.views
from django.conf.urls.defaults import *
from custom_registration.views import register_test
from custom_registration.forms import EduRegistrationForm
urlpatterns = patterns('',
url(r'^register/$', register_test, {'form_class': EduRegistrationForm}, name='registration.views.register'),
)
As far as I remember django-registration is using function-based views, so you can not really subclass them. The approach I usually follow is "overwriting" the original views (without modifying the django-registration app of course). This works like this:
Create another app (you could call it custom_registration or whatever you want)
This app need to contain another urls.py and in your case another views.py
Copy the original register view code to your new views.py and modify it, add a pattern to your urls.py to point to this view (use the same url pattern as in django-registration for this view)
Put an include to your projects urls.py of your new app urls.py before your are including the original django-registration app. This could look like this for example:
urlpatterns = patterns('',
...
url(r'^accounts/', include('custom_registration.urls')),
url(r'^accounts/', include('registration.backends.default.urls')),
...
)
This simply works since the first matching url pattern for /accounts/register will point to your new app, so it will never try to call the one from the original app.

Categories

Resources