Fixed #627 -- BACKWARDS-INCOMPATIBLE CHANGE. Admin is now an app, not a middleware. See BackwardsIncompatibleChanges for a full list of changes and information on how to update your code.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@948 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2005-10-19 01:09:05 +00:00
parent fd3d579179
commit f07e5d4f5d
101 changed files with 141 additions and 376 deletions

View File

@ -27,22 +27,28 @@ MEDIA_ROOT = ''
# Example: "http://media.lawrence.com" # Example: "http://media.lawrence.com"
MEDIA_URL = '' MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody. # Make this unique, and don't share it with anybody.
SECRET_KEY = '' SECRET_KEY = ''
# List of callables that know how to import templates from various sources. # List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = ( TEMPLATE_LOADERS = (
# 'django.core.template.loaders.app_directories.load_template_source',
'django.core.template.loaders.filesystem.load_template_source', 'django.core.template.loaders.filesystem.load_template_source',
'django.core.template.loaders.app_directories.load_template_source',
# 'django.core.template.loaders.eggs.load_template_source', # 'django.core.template.loaders.eggs.load_template_source',
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.sessions.SessionMiddleware",
"django.middleware.doc.XViewMiddleware", "django.middleware.doc.XViewMiddleware",
) )
ROOT_URLCONF = '{{ project_name }}.settings.urls.main' ROOT_URLCONF = '{{ project_name }}.urls'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates". # Put strings here, like "/home/html/django_templates".

View File

@ -1,18 +0,0 @@
# Django settings for {{ project_name }} project admin site.
from main import *
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates".
)
ROOT_URLCONF = '{{ project_name }}.settings.urls.admin'
MIDDLEWARE_CLASSES = (
'django.middleware.sessions.SessionMiddleware',
'django.middleware.admin.AdminUserRequired',
'django.middleware.common.CommonMiddleware',
)
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

View File

@ -1,6 +0,0 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.conf.urls.admin')),
(r'^r/', include('django.conf.urls.shortcut')),
)

View File

@ -3,4 +3,7 @@ from django.conf.urls.defaults import *
urlpatterns = patterns('', urlpatterns = patterns('',
# Example: # Example:
# (r'^{{ project_name }}/', include('{{ project_name }}.apps.foo.urls.foo')), # (r'^{{ project_name }}/', include('{{ project_name }}.apps.foo.urls.foo')),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls.admin')),
) )

View File

Before

Width:  |  Height:  |  Size: 80 B

After

Width:  |  Height:  |  Size: 80 B

View File

Before

Width:  |  Height:  |  Size: 838 B

After

Width:  |  Height:  |  Size: 838 B

View File

Before

Width:  |  Height:  |  Size: 58 B

After

Width:  |  Height:  |  Size: 58 B

View File

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 199 B

View File

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 212 B

View File

Before

Width:  |  Height:  |  Size: 843 B

After

Width:  |  Height:  |  Size: 843 B

View File

Before

Width:  |  Height:  |  Size: 844 B

After

Width:  |  Height:  |  Size: 844 B

View File

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 176 B

View File

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

View File

Before

Width:  |  Height:  |  Size: 119 B

After

Width:  |  Height:  |  Size: 119 B

View File

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

View File

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 192 B

View File

Before

Width:  |  Height:  |  Size: 119 B

After

Width:  |  Height:  |  Size: 119 B

View File

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 390 B

View File

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 181 B

View File

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 319 B

View File

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 667 B

View File

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 341 B

View File

Before

Width:  |  Height:  |  Size: 116 B

After

Width:  |  Height:  |  Size: 116 B

View File

Before

Width:  |  Height:  |  Size: 186 B

After

Width:  |  Height:  |  Size: 186 B

View File

Before

Width:  |  Height:  |  Size: 273 B

After

Width:  |  Height:  |  Size: 273 B

View File

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 606 B

View File

Before

Width:  |  Height:  |  Size: 358 B

After

Width:  |  Height:  |  Size: 358 B

View File

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 398 B

View File

Before

Width:  |  Height:  |  Size: 355 B

After

Width:  |  Height:  |  Size: 355 B

View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

View File

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 612 B

View File

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 401 B

View File

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 197 B

View File

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 203 B

View File

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View File

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 200 B

View File

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 932 B

View File

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 336 B

View File

Before

Width:  |  Height:  |  Size: 351 B

After

Width:  |  Height:  |  Size: 351 B

View File

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 354 B

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block title %}Page not found{% endblock %} {% block title %}Page not found{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">Home</a> &rsaquo; Server error</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">Home</a> &rsaquo; Server error</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base" %} {% extends "admin/base" %}
{% block title %}{{ title }} | Django site admin{% endblock %} {% block title %}{{ title }} | Django site admin{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block content %} {% block content %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block coltype %}colMS{% endblock %} {% block coltype %}colMS{% endblock %}
{% block bodyclass %}dashboard{% endblock %} {% block bodyclass %}dashboard{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}{% endblock %} {% block breadcrumbs %}{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"><a href="../../../../">Home</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; History</div> <div class="breadcrumbs"><a href="../../../../">Home</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; History</div>

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block content %} {% block content %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Bookmarklets</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Bookmarklets</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block extrahead %} {% block extrahead %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; Templates &rsaquo; {{ name }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; Templates &rsaquo; {{ name }}</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Views</a> &rsaquo; {{ name }}</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Views</a> &rsaquo; {{ name }}</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block coltype %}colSM{% endblock %} {% block coltype %}colSM{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a></div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a></div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password change</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password change</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password change</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password change</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password reset</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password reset</div>{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base_site" %} {% extends "admin/base_site" %}
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password reset</div>{% endblock %} {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Password reset</div>{% endblock %}

View File

@ -1,4 +1,4 @@
from django.models.auth import log from django.models.admin import log
from django.core import template from django.core import template
class AdminLogNode(template.Node): class AdminLogNode(template.Node):

View File

@ -6,7 +6,7 @@ from django.core.template import loader
from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied
from django.core.extensions import DjangoContext as Context from django.core.extensions import DjangoContext as Context
from django.core.extensions import get_object_or_404, render_to_response from django.core.extensions import get_object_or_404, render_to_response
from django.models.auth import log from django.models.admin import log
from django.utils.html import strip_tags from django.utils.html import strip_tags
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
from django.utils.text import capfirst, get_text_list from django.utils.text import capfirst, get_text_list
@ -49,7 +49,7 @@ def get_query_string(original_params, new_params={}, remove=[]):
return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20') return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
def index(request): def index(request):
return render_to_response('index', {'title': 'Site administration'}, context_instance=Context(request)) return render_to_response('admin/index', {'title': 'Site administration'}, context_instance=Context(request))
index = staff_member_required(index) index = staff_member_required(index)
def change_list(request, app_label, module_name): def change_list(request, app_label, module_name):
@ -266,7 +266,7 @@ def change_list(request, app_label, module_name):
else: else:
pass # Invalid argument to "list_filter" pass # Invalid argument to "list_filter"
raw_template = ['{% extends "base_site" %}\n'] raw_template = ['{% extends "admin/base_site" %}\n']
raw_template.append('{% block bodyclass %}change-list{% endblock %}\n') raw_template.append('{% block bodyclass %}change-list{% endblock %}\n')
if not is_popup: if not is_popup:
raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; %s</div>{%% endblock %%}\n' % capfirst(opts.verbose_name_plural)) raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; %s</div>{%% endblock %%}\n' % capfirst(opts.verbose_name_plural))
@ -538,7 +538,7 @@ def _get_template(opts, app_label, add=False, change=False, show_delete=False, f
admin_field_objs = opts.admin.get_field_objs(opts) admin_field_objs = opts.admin.get_field_objs(opts)
ordered_objects = opts.get_ordered_objects()[:] ordered_objects = opts.get_ordered_objects()[:]
auto_populated_fields = [f for f in opts.fields if f.prepopulate_from] auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
t = ['{% extends "base_site" %}\n'] t = ['{% extends "admin/base_site" %}\n']
t.append('{% block extrahead %}') t.append('{% block extrahead %}')
# Put in any necessary JavaScript imports. # Put in any necessary JavaScript imports.
@ -1087,7 +1087,7 @@ def delete_stage(request, app_label, module_name, object_id):
log.log_action(request.user.id, opts.get_content_type_id(), object_id, obj_repr, log.DELETION) log.log_action(request.user.id, opts.get_content_type_id(), object_id, obj_repr, log.DELETION)
request.user.add_message('The %s "%s" was deleted successfully.' % (opts.verbose_name, obj_repr)) request.user.add_message('The %s "%s" was deleted successfully.' % (opts.verbose_name, obj_repr))
return HttpResponseRedirect("../../") return HttpResponseRedirect("../../")
return render_to_response('delete_confirmation_generic', { return render_to_response('admin/delete_confirmation', {
"title": "Are you sure?", "title": "Are you sure?",
"object_name": opts.verbose_name, "object_name": opts.verbose_name,
"object": obj, "object": obj,
@ -1102,7 +1102,7 @@ def history(request, app_label, module_name, object_id):
order_by=("action_time",), select_related=True) order_by=("action_time",), select_related=True)
# If no history was found, see whether this object even exists. # If no history was found, see whether this object even exists.
obj = get_object_or_404(mod, pk=object_id) obj = get_object_or_404(mod, pk=object_id)
return render_to_response('admin_object_history', { return render_to_response('admin/object_history', {
'title': 'Change history: %r' % obj, 'title': 'Change history: %r' % obj,
'action_list': action_list, 'action_list': action_list,
'module_name': capfirst(opts.verbose_name_plural), 'module_name': capfirst(opts.verbose_name_plural),

View File

@ -23,7 +23,7 @@ def template_validator(request):
errors = manipulator.get_validation_errors(new_data) errors = manipulator.get_validation_errors(new_data)
if not errors: if not errors:
request.user.add_message('The template is valid.') request.user.add_message('The template is valid.')
return render_to_response('template_validator', { return render_to_response('admin/template_validator', {
'title': 'Template validator', 'title': 'Template validator',
'form': formfields.FormWrapper(manipulator, new_data, errors), 'form': formfields.FormWrapper(manipulator, new_data, errors),
}, context_instance=DjangoContext(request)) }, context_instance=DjangoContext(request))

View File

@ -17,7 +17,6 @@ APP_ARGS = '[modelmodule ...]'
# Use django.__path__[0] because we don't know which directory django into # Use django.__path__[0] because we don't know which directory django into
# which has been installed. # which has been installed.
PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template') PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
ADMIN_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', 'admin_templates')
def _get_packages_insert(app_label): def _get_packages_insert(app_label):
return "INSERT INTO packages (label, name) VALUES ('%s', '%s');" % (app_label, app_label) return "INSERT INTO packages (label, name) VALUES ('%s', '%s');" % (app_label, app_label)
@ -142,7 +141,7 @@ def get_sql_delete(mod):
if cursor is not None: if cursor is not None:
cursor.execute("SELECT id FROM content_types WHERE package = %s", [app_label]) cursor.execute("SELECT id FROM content_types WHERE package = %s", [app_label])
for row in cursor.fetchall(): for row in cursor.fetchall():
output.append("DELETE FROM auth_admin_log WHERE content_type_id = %s;" % row[0]) output.append("DELETE FROM django_admin_log WHERE content_type_id = %s;" % row[0])
# Close database connection explicitly, in case this output is being piped # Close database connection explicitly, in case this output is being piped
# directly into a database client, to avoid locking issues. # directly into a database client, to avoid locking issues.
@ -378,16 +377,8 @@ def startproject(project_name, directory):
"Creates a Django project for the given project_name in the given directory." "Creates a Django project for the given project_name in the given directory."
from random import choice from random import choice
_start_helper('project', project_name, directory) _start_helper('project', project_name, directory)
# Populate TEMPLATE_DIRS for the admin templates, based on where Django is
# installed.
admin_settings_file = os.path.join(directory, project_name, 'settings', 'admin.py')
settings_contents = open(admin_settings_file, 'r').read()
fp = open(admin_settings_file, 'w')
settings_contents = re.sub(r'(?s)\b(TEMPLATE_DIRS\s*=\s*\()(.*?)\)', "\\1\n r%r,\\2)" % ADMIN_TEMPLATE_DIR, settings_contents)
fp.write(settings_contents)
fp.close()
# Create a random SECRET_KEY hash, and put it in the main settings. # Create a random SECRET_KEY hash, and put it in the main settings.
main_settings_file = os.path.join(directory, project_name, 'settings', 'main.py') main_settings_file = os.path.join(directory, project_name, 'settings.py')
settings_contents = open(main_settings_file, 'r').read() settings_contents = open(main_settings_file, 'r').read()
fp = open(main_settings_file, 'w') fp = open(main_settings_file, 'w')
secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)]) secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])

View File

@ -602,7 +602,7 @@ class AdminMediaHandler:
from django.conf import settings from django.conf import settings
import django import django
self.application = application self.application = application
self.media_dir = django.__path__[0] + '/conf/admin_media' self.media_dir = django.__path__[0] + '/contrib/admin/media'
self.media_url = settings.ADMIN_MEDIA_PREFIX self.media_url = settings.ADMIN_MEDIA_PREFIX
def __call__(self, environ, start_response): def __call__(self, environ, start_response):

View File

@ -1,126 +0,0 @@
from django.utils import httpwrappers
from django.core.extensions import DjangoContext
from django.core.extensions import render_to_response
from django.models.auth import users
from django.views.registration import passwords
from django.views.auth.login import logout
import base64, md5
import cPickle as pickle
from django.conf.settings import SECRET_KEY
ERROR_MESSAGE = "Please enter a correct username and password. Note that both fields are case-sensitive."
class AdminUserRequired:
"""
Admin middleware. If this is enabled, access to the site will be granted only
to valid users with the "is_staff" flag set.
"""
def process_view(self, request, view_func, param_dict):
"""
Make sure the user is logged in and is a valid admin user before
allowing any access.
Done at the view point because we need to know if we're running the
password reset function.
"""
# If this is the password reset view, we don't want to require login
# Otherwise the password reset would need its own entry in the httpd
# conf, which is a little uglier than this. Same goes for the logout
# view.
if view_func in (passwords.password_reset, passwords.password_reset_done, logout):
return
assert hasattr(request, 'session'), "The admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.middleware.sessions.SessionMiddleware' before %r." % self.__class__.__name__
# Check for a logged in, valid user
if self.user_is_valid(request.user):
return
# If this isn't already the login page, display it
if not request.POST.has_key('this_is_the_login_form'):
if request.POST:
message = "Please log in again, because your session has expired. "\
"Don't worry: Your submission has been saved."
else:
message = ""
return self.display_login_form(request, message)
# Check that the user accepts cookies.
if not request.session.test_cookie_worked():
message = "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again."
return self.display_login_form(request, message)
# Check the password
username = request.POST.get('username', '')
try:
user = users.get_object(username__exact=username)
except users.UserDoesNotExist:
message = ERROR_MESSAGE
if '@' in username:
# Mistakenly entered e-mail address instead of username? Look it up.
try:
user = users.get_object(email__exact=username)
except users.UserDoesNotExist:
message = "Usernames cannot contain the '@' character."
else:
message = "Your e-mail address is not your username. Try '%s' instead." % user.username
return self.display_login_form(request, message)
# The user data is correct; log in the user in and continue
else:
if self.authenticate_user(user, request.POST.get('password', '')):
request.session[users.SESSION_KEY] = user.id
if request.POST.has_key('post_data'):
post_data = decode_post_data(request.POST['post_data'])
if post_data and not post_data.has_key('this_is_the_login_form'):
# overwrite request.POST with the saved post_data, and continue
request.POST = post_data
request.user = user
return
else:
request.session.delete_test_cookie()
return httpwrappers.HttpResponseRedirect(request.path)
else:
return self.display_login_form(request, ERROR_MESSAGE)
def display_login_form(self, request, error_message=''):
request.session.set_test_cookie()
if request.POST and request.POST.has_key('post_data'):
# User has failed login BUT has previously saved 'post_data'
post_data = request.POST['post_data']
elif request.POST:
# User's session must have expired; save their post data
post_data = encode_post_data(request.POST)
else:
post_data = encode_post_data({})
return render_to_response(self.get_login_template_name(), {
'title': 'Log in',
'app_path': request.path,
'post_data': post_data,
'error_message': error_message
}, context_instance=DjangoContext(request))
def authenticate_user(self, user, password):
return user.check_password(password) and user.is_staff
def user_is_valid(self, user):
return not user.is_anonymous() and user.is_staff
def get_login_template_name(self):
return "login"
def encode_post_data(post_data):
pickled = pickle.dumps(post_data)
pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def decode_post_data(encoded_data):
encoded_data = base64.decodestring(encoded_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
if md5.new(pickled + SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User may have tampered with session cookie."
return pickle.loads(pickled)

View File

@ -176,49 +176,3 @@ class Message(meta.Model):
def __repr__(self): def __repr__(self):
return self.message return self.message
class LogEntry(meta.Model):
action_time = meta.DateTimeField(auto_now=True)
user = meta.ForeignKey(User)
content_type = meta.ForeignKey(core.ContentType, blank=True, null=True)
object_id = meta.TextField(blank=True, null=True)
object_repr = meta.CharField(maxlength=200)
action_flag = meta.PositiveSmallIntegerField()
change_message = meta.TextField(blank=True)
class META:
module_name = 'log'
verbose_name_plural = 'log entries'
db_table = 'auth_admin_log'
ordering = ('-action_time',)
module_constants = {
'ADDITION': 1,
'CHANGE': 2,
'DELETION': 3,
}
def __repr__(self):
return str(self.action_time)
def is_addition(self):
return self.action_flag == ADDITION
def is_change(self):
return self.action_flag == CHANGE
def is_deletion(self):
return self.action_flag == DELETION
def get_edited_object(self):
"Returns the edited object represented by this log entry"
return self.get_content_type().get_object_for_this_type(pk=self.object_id)
def get_admin_url(self):
"""
Returns the admin URL to edit the object represented by this log entry.
This is relative to the Django admin index page.
"""
return "%s/%s/%s/" % (self.get_content_type().package, self.get_content_type().python_module_name, self.object_id)
def _module_log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
e.save()

View File

@ -192,10 +192,10 @@ Available options
Example usage:: Example usage::
django-admin.py init --settings='myproject.settings.main' django-admin.py init --settings=myproject.settings
Explicitly specifies the settings module to use. The settings module should be Explicitly specifies the settings module to use. The settings module should be
in Python path syntax, e.g. "myproject.settings.main". If this isn't provided, in Python path syntax, e.g. "myproject.settings". If this isn't provided,
``django-admin.py`` will use the DJANGO_SETTINGS_MODULE environment variable. ``django-admin.py`` will use the DJANGO_SETTINGS_MODULE environment variable.
--pythonpath --pythonpath

View File

@ -348,8 +348,7 @@ things:
* Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file * Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file
to match your domain. For example, if you're going to to match your domain. For example, if you're going to
"http://www.mysite.com/admin/" in your browser, in "http://www.mysite.com/admin/" in your browser, in
"myproject.settings.admin" you should set ``SESSION_COOKIE_DOMAIN = "myproject.settings" you should set ``SESSION_COOKIE_DOMAIN = 'www.mysite.com'``.
'www.mysite.com'``.
* Some browsers (Firefox?) don't like to accept cookies from domains that * Some browsers (Firefox?) don't like to accept cookies from domains that
don't have dots in them. If you're running the admin site on "localhost" don't have dots in them. If you're running the admin site on "localhost"

View File

@ -27,30 +27,15 @@ name. For example, here's the default ``MIDDLEWARE_CLASSES`` created by
"django.middleware.doc.XViewMiddleware", "django.middleware.doc.XViewMiddleware",
) )
The default admin site has the following ``MIDDLEWARE_CLASSES`` set::
MIDDLEWARE_CLASSES = (
"django.middleware.sessions.SessionMiddleware",
"django.middleware.admin.AdminUserRequired",
"django.middleware.common.CommonMiddleware",
)
Django applies middleware in the order it's defined in ``MIDDLEWARE_CLASSES``. Django applies middleware in the order it's defined in ``MIDDLEWARE_CLASSES``.
For a regular (i.e., non-admin) Django installation, no middleware is required, A Django installation doesn't require any middleware -- e.g.,
but it's strongly suggested that you use ``CommonMiddleware``. For a Django ``MIDDLEWARE_CLASSES`` can be empty, if you'd like -- but it's strongly
admin site, ``SessionMiddleware`` and ``AdminUserRequired`` (in that order) are suggested that you use ``CommonMiddleware``.
required.
Available middleware Available middleware
==================== ====================
django.middleware.admin.AdminUserRequired
-----------------------------------------
Limits site access to valid users with the ``is_staff`` flag set. This is
required by Django's admin, and this middleware requires ``SessionMiddleware``.
django.middleware.cache.CacheMiddleware django.middleware.cache.CacheMiddleware
--------------------------------------- ---------------------------------------

View File

@ -25,12 +25,11 @@ Then edit your ``httpd.conf`` file and add the following::
<Location "/mysite/"> <Location "/mysite/">
SetHandler python-program SetHandler python-program
PythonHandler django.core.handlers.modpython PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main SetEnv DJANGO_SETTINGS_MODULE myproject.settings
PythonDebug On PythonDebug On
</Location> </Location>
...and replace ``myproject.settings.main`` with the Python path to your ...and replace ``myproject.settings`` with the Python path to your settings file.
settings file.
This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE`` Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE``
@ -55,17 +54,6 @@ full URL.
When deploying Django sites on mod_python, you'll need to restart Apache each When deploying Django sites on mod_python, you'll need to restart Apache each
time you make changes to your Python code. time you make changes to your Python code.
Here's a template for an admin configuration::
<Location "/admin/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.admin
PythonDebug On
</Location>
The only thing different here is the ``DJANGO_SETTINGS_MODULE``.
Multiple Django installations on the same Apache Multiple Django installations on the same Apache
================================================ ================================================
@ -77,13 +65,13 @@ instance. Just use ``VirtualHost`` for that, like so::
<VirtualHost *> <VirtualHost *>
ServerName www.example.com ServerName www.example.com
# ... # ...
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main SetEnv DJANGO_SETTINGS_MODULE myproject.settings
</VirtualHost> </VirtualHost>
<VirtualHost *> <VirtualHost *>
ServerName admin.example.com ServerName www2.example.com
# ... # ...
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.admin SetEnv DJANGO_SETTINGS_MODULE myproject.other_settings
</VirtualHost> </VirtualHost>
If you need to put two Django installations within the same ``VirtualHost``, If you need to put two Django installations within the same ``VirtualHost``,
@ -95,13 +83,13 @@ mess things up. Use the ``PythonInterpreter`` directive to give different
ServerName www.example.com ServerName www.example.com
# ... # ...
<Location "/something"> <Location "/something">
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main SetEnv DJANGO_SETTINGS_MODULE myproject.settings
PythonInterpreter myproject_main PythonInterpreter myproject
</Location> </Location>
<Location "/admin"> <Location "/otherthing">
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.admin SetEnv DJANGO_SETTINGS_MODULE myproject.other_settings
PythonInterpreter myproject_admin PythonInterpreter myproject_other
</Location> </Location>
</VirtualHost> </VirtualHost>

View File

@ -34,7 +34,7 @@ When you use Django, you have to tell it which settings you're using. Do this
by using an environment variable, ``DJANGO_SETTINGS_MODULE``. by using an environment variable, ``DJANGO_SETTINGS_MODULE``.
The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g. The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g.
``"myproject.settings.main"``. Note that the settings module should be on the ``"myproject.settings"``. Note that the settings module should be on the
Python `import search path`_. Python `import search path`_.
.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html .. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html
@ -47,17 +47,17 @@ once, or explicitly pass in the settings module each time you run the utility.
Example (Unix Bash shell):: Example (Unix Bash shell)::
export DJANGO_SETTINGS_MODULE=myproject.settings.main export DJANGO_SETTINGS_MODULE=myproject.settings
django-admin.py runserver django-admin.py runserver
Example (Windows shell):: Example (Windows shell)::
set DJANGO_SETTINGS_MODULE=myproject.settings.main set DJANGO_SETTINGS_MODULE=myproject.settings
django-admin.py runserver django-admin.py runserver
Use the ``--settings`` command-line argument to specify the settings manually:: Use the ``--settings`` command-line argument to specify the settings manually::
django-admin.py runserver --settings=myproject.settings.main django-admin.py runserver --settings=myproject.settings
.. _django-admin.py: http://www.djangoproject.com/documentation/django_admin/ .. _django-admin.py: http://www.djangoproject.com/documentation/django_admin/
@ -70,7 +70,7 @@ settings file to use. Do that with ``SetEnv``::
<Location "/mysite/"> <Location "/mysite/">
SetHandler python-program SetHandler python-program
PythonHandler django.core.handlers.modpython PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main SetEnv DJANGO_SETTINGS_MODULE myproject.settings
</Location> </Location>
Read the `Django mod_python documentation`_ for more information. Read the `Django mod_python documentation`_ for more information.

View File

@ -40,16 +40,10 @@ settings. Let's look at what ``startproject`` created::
__init__.py __init__.py
apps/ apps/
__init__.py __init__.py
settings/ settings.py
__init__.py urls.py
admin.py
main.py
urls/
__init__.py
admin.py
main.py
First, edit ``myproject/settings/main.py``. It's a normal Python module with First, edit ``myproject/settings.py``. It's a normal Python module with
module-level variables representing Django settings. Edit the file and change module-level variables representing Django settings. Edit the file and change
these settings to match your database's connection parameters: these settings to match your database's connection parameters:
@ -69,11 +63,6 @@ these settings to match your database's connection parameters:
point. Do that with "``CREATE DATABASE database_name;``" within your point. Do that with "``CREATE DATABASE database_name;``" within your
database's interactive prompt. database's interactive prompt.
Also, note that MySQL and sqlite support is a recent development, and Django
hasn't been comprehensively tested with either database. If you find any
bugs in those bindings, please file them in `Django's ticket system`_ so we
can fix them immediately.
Now, take a second to make sure ``myproject`` is on your Python path. You Now, take a second to make sure ``myproject`` is on your Python path. You
can do this by copying ``myproject`` to Python's ``site-packages`` directory, can do this by copying ``myproject`` to Python's ``site-packages`` directory,
or you can do it by altering the ``PYTHONPATH`` environment variable. See the or you can do it by altering the ``PYTHONPATH`` environment variable. See the
@ -84,7 +73,7 @@ or you can do it by altering the ``PYTHONPATH`` environment variable. See the
Run the following command:: Run the following command::
django-admin.py init --settings=myproject.settings.main django-admin.py init --settings=myproject.settings
The ``django-admin.py`` utility generally needs to know which settings module The ``django-admin.py`` utility generally needs to know which settings module
you're using. Here, we're doing that by specifying ``settings=`` on the command you're using. Here, we're doing that by specifying ``settings=`` on the command
@ -92,11 +81,11 @@ line, but that can get tedious. If you don't want to type ``settings=`` each
time, you can set the ``DJANGO_SETTINGS_MODULE`` environment variable. Here's time, you can set the ``DJANGO_SETTINGS_MODULE`` environment variable. Here's
how you do that in the Bash shell on Unix:: how you do that in the Bash shell on Unix::
export DJANGO_SETTINGS_MODULE=myproject.settings.main export DJANGO_SETTINGS_MODULE=myproject.settings
On Windows, you'd use ``set`` instead:: On Windows, you'd use ``set`` instead::
set DJANGO_SETTINGS_MODULE=myproject.settings.main set DJANGO_SETTINGS_MODULE=myproject.settings
If you don't see any errors after running ``django-admin.py init``, you know it If you don't see any errors after running ``django-admin.py init``, you know it
worked. That command initialized your database with Django's core database worked. That command initialized your database with Django's core database
@ -221,7 +210,7 @@ But first we need to tell our project that the ``polls`` app is installed.
projects, and you can distribute apps, because they don't have to be tied to projects, and you can distribute apps, because they don't have to be tied to
a given Django installation. a given Django installation.
Edit the myproject/settings/main.py file again, and change the ``INSTALLED_APPS`` Edit the myproject/settings.py file again, and change the ``INSTALLED_APPS``
setting to include the string "myproject.apps.polls". So it'll look like this:: setting to include the string "myproject.apps.polls". So it'll look like this::
INSTALLED_APPS = ( INSTALLED_APPS = (

View File

@ -24,15 +24,26 @@ application and will focus on Django's automatically-generated admin site.
The admin isn't necessarily intended to be used by site visitors; it's for site The admin isn't necessarily intended to be used by site visitors; it's for site
managers. managers.
Activate the admin site
=======================
The Django admin site is not activated by default -- it's an opt-in thing. To
activate the admin site for your installation, do these three things:
* Add ``"django.contrib.admin"`` to your ``INSTALLED_APPS`` setting.
* Run the command ``django-admin.py install admin``. This will create an
extra database table that the admin needs.
* Edit your ``myproject.urls`` file and uncomment the line below
"Uncomment this for admin:". This file is a URLconf; we'll dig into
URLconfs in the next tutorial. For now, all you need to know is that it
maps URL roots to applications.
Create a user account Create a user account
===================== =====================
Run the following command to create a superuser account for your admin site:: Run the following command to create a superuser account for your admin site::
django-admin.py createsuperuser --settings="myproject.settings.main" django-admin.py createsuperuser --settings=myproject.settings
(Note: You can use either "myproject.settings.main" or "myproject.settings.admin"
here. They both reference the same database.)
The script will prompt you for a username, e-mail address and password (twice). The script will prompt you for a username, e-mail address and password (twice).
@ -45,36 +56,26 @@ server and explore the admin site.
Just run the following command to start the server:: Just run the following command to start the server::
django-admin.py runserver --settings="myproject.settings.admin" django-admin.py runserver --settings=myproject.settings
It'll start a Web server running locally -- on port 8000, by default. If you It'll start a Web server running locally -- on port 8000, by default. If you
want to change the server's port, pass it as a command-line argument:: want to change the server's port, pass it as a command-line argument::
django-admin.py runserver 8080 --settings="myproject.settings.admin" django-admin.py runserver 8080 --settings=myproject.settings
DON'T use this server in anything resembling a production environment. It's DON'T use this server in anything resembling a production environment. It's
intended only for use while developing. intended only for use while developing.
Now, open a Web browser and go to "/admin/" on your domain. You should see the Now, open a Web browser and go to "/admin/" on your local domain -- e.g.,
admin's login screen: http://127.0.0.1:8000/admin/. You should see the admin's login screen:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin01.png .. image:: http://media.djangoproject.com/img/doc/tutorial/admin01.png
:alt: Django admin login screen :alt: Django admin login screen
.. admonition:: Note
If you get an error telling you that the URL 'admin/' didn't match any of
your URLconf entries, you most likely used ``myproject.settings.main``
instead of ``myproject.settings.admin``.
Enter the admin site Enter the admin site
==================== ====================
Now, try logging in. Now, try logging in. You should see the Django admin index page:
If it didn't work, read the `"I can't log in" questions`_ in the FAQ.
If it worked, you should see the Django admin index page:
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png .. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png
:alt: Django admin index page :alt: Django admin index page
@ -381,39 +382,47 @@ think they should.
Customize the admin look and feel Customize the admin look and feel
================================= =================================
Clearly having "Django administration" and "example.com" at the top of each Clearly, having "Django administration" and "example.com" at the top of each
admin page is ridiculous. It's just placeholder text. admin page is ridiculous. It's just placeholder text.
That's easy to change, though, using Django's template system. That's easy to change, though, using Django's template system. The Django admin
is powered by Django itself, and its interfaces use Django's own template
system. (How meta!)
Open your admin settings file and look at the ``TEMPLATE_DIRS`` setting. Open your settings file (``myproject/settings.py``, remember) and look at the
``TEMPLATE_DIRS`` is a tuple of filesystem directories to check when loading ``TEMPLATE_DIRS`` setting. ``TEMPLATE_DIRS`` is a tuple of filesystem
Django templates. It's a search path. directories to check when loading Django templates. It's a search path.
The ``django-admin.py startproject`` command automatically prepopulated By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
this setting with the location of Django's default admin templates, according Django where our templates live.
to where you have Django installed. But let's add an extra line to
``TEMPLATE_DIRS`` so that it checks a custom directory first, before checking
the default admin template directory::
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
"/home/mytemplates/admin", "/home/mytemplates", # Change this to your own directory.
"/usr/lib/python2.3/site-packages/django/conf/admin_templates",
) )
Again, note that you should edit the admin settings file, not the main settings Now copy the template ``admin/base_site.html`` from within the default Django
file. That's because we're dealing with admin-site templates. admin template directory (``django/contrib/admin/templates``) into an ``admin``
subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For
example, if your ``TEMPLATE_DIRS`` includes ``"/home/mytemplates"``, as above,
then copy ``django/contrib/admin/templates/admin/base_site.html`` to
``/home/mytemplates/admin/base_site.html``.
Now copy the template ``base_site.html`` from within the default Django admin Then, just edit the file and replace the generic Django text with your own
template directory, into ``/home/mytemplates/admin`` (or wherever you're site's name and URL as you see fit.
putting your custom admin templates). Edit the file and replace the generic
Django stuff with your own site's name as you see fit.
Note that any of Django's default admin templates can be overridden. To Note that any of Django's default admin templates can be overridden. To
override a template, just do the same thing you did with ``base_site.html`` -- override a template, just do the same thing you did with ``base_site.html`` --
copy it from the default directory into your custom directory, and make copy it from the default directory into your custom directory, and make
changes. changes.
Astute readers will ask: But if ``TEMPLATE_DIRS`` was empty by default, how was
Django finding the default admin templates? The answer is that, by default,
Django automatically looks for a ``templates/`` subdirectory within each app
package, for use as a fallback. See the `loader types documentation`_ for full
information.
.. _loader types documentation: http://www.djangoproject.com/documentation/templates_python/#loader-types
Customize the admin index page Customize the admin index page
============================== ==============================
@ -425,11 +434,11 @@ setting. But the order in which it displays things is random, and you may want
to make significant changes to the layout. After all, the index is probably the to make significant changes to the layout. After all, the index is probably the
most important page of the admin, and it should be easy to use. most important page of the admin, and it should be easy to use.
The template to customize is ``index.html``. (Do the same as with The template to customize is ``admin/index.html``. (Do the same as with
``base_site.html`` in the previous section -- copy it from the default directory ``admin/base_site.html`` in the previous section -- copy it from the default
to your custom template directory.) Edit the file, and you'll see it uses a directory to your custom template directory.) Edit the file, and you'll see it
template tag called ``{% get_admin_app_list as app_list %}``. That's the magic uses a template tag called ``{% get_admin_app_list as app_list %}``. That's the
that retrieves every installed Django app. Instead of using that, you can magic that retrieves every installed Django app. Instead of using that, you can
hard-code links to object-specific admin pages in whatever way you think is hard-code links to object-specific admin pages in whatever way you think is
best. best.

Some files were not shown because too many files have changed in this diff Show More