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
|
@ -27,22 +27,28 @@ MEDIA_ROOT = ''
|
|||
# Example: "http://media.lawrence.com"
|
||||
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.
|
||||
SECRET_KEY = ''
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
# 'django.core.template.loaders.app_directories.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',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.sessions.SessionMiddleware",
|
||||
"django.middleware.doc.XViewMiddleware",
|
||||
)
|
||||
|
||||
ROOT_URLCONF = '{{ project_name }}.settings.urls.main'
|
||||
ROOT_URLCONF = '{{ project_name }}.urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
# Put strings here, like "/home/html/django_templates".
|
|
@ -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/'
|
|
@ -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')),
|
||||
)
|
|
@ -3,4 +3,7 @@ from django.conf.urls.defaults import *
|
|||
urlpatterns = patterns('',
|
||||
# Example:
|
||||
# (r'^{{ project_name }}/', include('{{ project_name }}.apps.foo.urls.foo')),
|
||||
|
||||
# Uncomment this for admin:
|
||||
# (r'^admin/', include('django.contrib.admin.urls.admin')),
|
||||
)
|
Before Width: | Height: | Size: 80 B After Width: | Height: | Size: 80 B |
Before Width: | Height: | Size: 838 B After Width: | Height: | Size: 838 B |
Before Width: | Height: | Size: 58 B After Width: | Height: | Size: 58 B |
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
Before Width: | Height: | Size: 843 B After Width: | Height: | Size: 843 B |
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 844 B |
Before Width: | Height: | Size: 176 B After Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 299 B After Width: | Height: | Size: 299 B |
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 390 B |
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
Before Width: | Height: | Size: 319 B After Width: | Height: | Size: 319 B |
Before Width: | Height: | Size: 667 B After Width: | Height: | Size: 667 B |
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
Before Width: | Height: | Size: 116 B After Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 186 B After Width: | Height: | Size: 186 B |
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |
Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
Before Width: | Height: | Size: 612 B After Width: | Height: | Size: 612 B |
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 401 B |
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 200 B After Width: | Height: | Size: 200 B |
Before Width: | Height: | Size: 932 B After Width: | Height: | Size: 932 B |
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block title %}Page not found{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">Home</a> › Server error</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base" %}
|
||||
{% extends "admin/base" %}
|
||||
|
||||
{% block title %}{{ title }} | Django site admin{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block content %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block coltype %}colMS{% endblock %}
|
||||
{% block bodyclass %}dashboard{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs"><a href="../../../../">Home</a> › <a href="../../">{{ module_name }}</a> › <a href="../">{{ object|truncatewords:"18" }}</a> › History</div>
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block content %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Bookmarklets</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Documentation</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Documentation</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block extrahead %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block coltype %}colSM{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › Templates › {{ name }}</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block coltype %}colSM{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block coltype %}colSM{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Views</a> › {{ name }}</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block coltype %}colSM{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a></div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Password change</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Password change</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Password reset</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base_site" %}
|
||||
{% extends "admin/base_site" %}
|
||||
|
||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Password reset</div>{% endblock %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from django.models.auth import log
|
||||
from django.models.admin import log
|
||||
from django.core import template
|
||||
|
||||
class AdminLogNode(template.Node):
|
|
@ -6,7 +6,7 @@ from django.core.template import loader
|
|||
from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied
|
||||
from django.core.extensions import DjangoContext as Context
|
||||
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.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||
from django.utils.text import capfirst, get_text_list
|
||||
|
@ -49,7 +49,7 @@ def get_query_string(original_params, new_params={}, remove=[]):
|
|||
return '?' + '&'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
|
||||
|
||||
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)
|
||||
|
||||
def change_list(request, app_label, module_name):
|
||||
|
@ -266,7 +266,7 @@ def change_list(request, app_label, module_name):
|
|||
else:
|
||||
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')
|
||||
if not is_popup:
|
||||
raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> › %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)
|
||||
ordered_objects = opts.get_ordered_objects()[:]
|
||||
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 %}')
|
||||
|
||||
# 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)
|
||||
request.user.add_message('The %s "%s" was deleted successfully.' % (opts.verbose_name, obj_repr))
|
||||
return HttpResponseRedirect("../../")
|
||||
return render_to_response('delete_confirmation_generic', {
|
||||
return render_to_response('admin/delete_confirmation', {
|
||||
"title": "Are you sure?",
|
||||
"object_name": opts.verbose_name,
|
||||
"object": obj,
|
||||
|
@ -1102,7 +1102,7 @@ def history(request, app_label, module_name, object_id):
|
|||
order_by=("action_time",), select_related=True)
|
||||
# If no history was found, see whether this object even exists.
|
||||
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,
|
||||
'action_list': action_list,
|
||||
'module_name': capfirst(opts.verbose_name_plural),
|
||||
|
|
|
@ -23,7 +23,7 @@ def template_validator(request):
|
|||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
request.user.add_message('The template is valid.')
|
||||
return render_to_response('template_validator', {
|
||||
return render_to_response('admin/template_validator', {
|
||||
'title': 'Template validator',
|
||||
'form': formfields.FormWrapper(manipulator, new_data, errors),
|
||||
}, context_instance=DjangoContext(request))
|
||||
|
|
|
@ -17,7 +17,6 @@ APP_ARGS = '[modelmodule ...]'
|
|||
# Use django.__path__[0] because we don't know which directory django into
|
||||
# which has been installed.
|
||||
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):
|
||||
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:
|
||||
cursor.execute("SELECT id FROM content_types WHERE package = %s", [app_label])
|
||||
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
|
||||
# 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."
|
||||
from random import choice
|
||||
_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.
|
||||
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()
|
||||
fp = open(main_settings_file, 'w')
|
||||
secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
|
||||
|
|
|
@ -602,7 +602,7 @@ class AdminMediaHandler:
|
|||
from django.conf import settings
|
||||
import django
|
||||
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
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
|
|
|
@ -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)
|
|
@ -176,49 +176,3 @@ class Message(meta.Model):
|
|||
|
||||
def __repr__(self):
|
||||
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()
|
||||
|
|
|
@ -192,10 +192,10 @@ Available options
|
|||
|
||||
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
|
||||
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.
|
||||
|
||||
--pythonpath
|
||||
|
|
|
@ -348,8 +348,7 @@ things:
|
|||
* Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file
|
||||
to match your domain. For example, if you're going to
|
||||
"http://www.mysite.com/admin/" in your browser, in
|
||||
"myproject.settings.admin" you should set ``SESSION_COOKIE_DOMAIN =
|
||||
'www.mysite.com'``.
|
||||
"myproject.settings" you should set ``SESSION_COOKIE_DOMAIN = 'www.mysite.com'``.
|
||||
|
||||
* 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"
|
||||
|
|
|
@ -27,30 +27,15 @@ name. For example, here's the default ``MIDDLEWARE_CLASSES`` created by
|
|||
"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``.
|
||||
|
||||
For a regular (i.e., non-admin) Django installation, no middleware is required,
|
||||
but it's strongly suggested that you use ``CommonMiddleware``. For a Django
|
||||
admin site, ``SessionMiddleware`` and ``AdminUserRequired`` (in that order) are
|
||||
required.
|
||||
A Django installation doesn't require any middleware -- e.g.,
|
||||
``MIDDLEWARE_CLASSES`` can be empty, if you'd like -- but it's strongly
|
||||
suggested that you use ``CommonMiddleware``.
|
||||
|
||||
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
|
||||
---------------------------------------
|
||||
|
||||
|
|
|
@ -25,12 +25,11 @@ Then edit your ``httpd.conf`` file and add the following::
|
|||
<Location "/mysite/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
|
||||
PythonDebug On
|
||||
</Location>
|
||||
|
||||
...and replace ``myproject.settings.main`` with the Python path to your
|
||||
settings file.
|
||||
...and replace ``myproject.settings`` with the Python path to your settings file.
|
||||
|
||||
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``
|
||||
|
@ -55,17 +54,6 @@ full URL.
|
|||
When deploying Django sites on mod_python, you'll need to restart Apache each
|
||||
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
|
||||
================================================
|
||||
|
||||
|
@ -77,13 +65,13 @@ instance. Just use ``VirtualHost`` for that, like so::
|
|||
<VirtualHost *>
|
||||
ServerName www.example.com
|
||||
# ...
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
|
||||
</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>
|
||||
|
||||
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
|
||||
# ...
|
||||
<Location "/something">
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main
|
||||
PythonInterpreter myproject_main
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
|
||||
PythonInterpreter myproject
|
||||
</Location>
|
||||
|
||||
<Location "/admin">
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.admin
|
||||
PythonInterpreter myproject_admin
|
||||
<Location "/otherthing">
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.other_settings
|
||||
PythonInterpreter myproject_other
|
||||
</Location>
|
||||
</VirtualHost>
|
||||
|
||||
|
|
|
@ -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``.
|
||||
|
||||
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`_.
|
||||
|
||||
.. _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)::
|
||||
|
||||
export DJANGO_SETTINGS_MODULE=myproject.settings.main
|
||||
export DJANGO_SETTINGS_MODULE=myproject.settings
|
||||
django-admin.py runserver
|
||||
|
||||
Example (Windows shell)::
|
||||
|
||||
set DJANGO_SETTINGS_MODULE=myproject.settings.main
|
||||
set DJANGO_SETTINGS_MODULE=myproject.settings
|
||||
django-admin.py runserver
|
||||
|
||||
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/
|
||||
|
||||
|
@ -70,7 +70,7 @@ settings file to use. Do that with ``SetEnv``::
|
|||
<Location "/mysite/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings.main
|
||||
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
|
||||
</Location>
|
||||
|
||||
Read the `Django mod_python documentation`_ for more information.
|
||||
|
|
|
@ -40,16 +40,10 @@ settings. Let's look at what ``startproject`` created::
|
|||
__init__.py
|
||||
apps/
|
||||
__init__.py
|
||||
settings/
|
||||
__init__.py
|
||||
admin.py
|
||||
main.py
|
||||
urls/
|
||||
__init__.py
|
||||
admin.py
|
||||
main.py
|
||||
settings.py
|
||||
urls.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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -84,7 +73,7 @@ or you can do it by altering the ``PYTHONPATH`` environment variable. See the
|
|||
|
||||
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
|
||||
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
|
||||
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::
|
||||
|
||||
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
|
||||
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
|
||||
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::
|
||||
|
||||
INSTALLED_APPS = (
|
||||
|
|
|
@ -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
|
||||
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
|
||||
=====================
|
||||
|
||||
Run the following command to create a superuser account for your admin site::
|
||||
|
||||
django-admin.py createsuperuser --settings="myproject.settings.main"
|
||||
|
||||
(Note: You can use either "myproject.settings.main" or "myproject.settings.admin"
|
||||
here. They both reference the same database.)
|
||||
django-admin.py createsuperuser --settings=myproject.settings
|
||||
|
||||
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::
|
||||
|
||||
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
|
||||
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
|
||||
intended only for use while developing.
|
||||
|
||||
Now, open a Web browser and go to "/admin/" on your domain. You should see the
|
||||
admin's login screen:
|
||||
Now, open a Web browser and go to "/admin/" on your local domain -- e.g.,
|
||||
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
|
||||
: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
|
||||
====================
|
||||
|
||||
Now, try logging in.
|
||||
|
||||
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:
|
||||
Now, try logging in. You should see the Django admin index page:
|
||||
|
||||
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png
|
||||
:alt: Django admin index page
|
||||
|
@ -381,39 +382,47 @@ think they should.
|
|||
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.
|
||||
|
||||
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.
|
||||
``TEMPLATE_DIRS`` is a tuple of filesystem directories to check when loading
|
||||
Django templates. It's a search path.
|
||||
Open your settings file (``myproject/settings.py``, remember) and look at the
|
||||
``TEMPLATE_DIRS`` setting. ``TEMPLATE_DIRS`` is a tuple of filesystem
|
||||
directories to check when loading Django templates. It's a search path.
|
||||
|
||||
The ``django-admin.py startproject`` command automatically prepopulated
|
||||
this setting with the location of Django's default admin templates, according
|
||||
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::
|
||||
By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
|
||||
Django where our templates live.
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
"/home/mytemplates/admin",
|
||||
"/usr/lib/python2.3/site-packages/django/conf/admin_templates",
|
||||
"/home/mytemplates", # Change this to your own directory.
|
||||
)
|
||||
|
||||
Again, note that you should edit the admin settings file, not the main settings
|
||||
file. That's because we're dealing with admin-site templates.
|
||||
Now copy the template ``admin/base_site.html`` from within the default Django
|
||||
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
|
||||
template directory, into ``/home/mytemplates/admin`` (or wherever you're
|
||||
putting your custom admin templates). Edit the file and replace the generic
|
||||
Django stuff with your own site's name as you see fit.
|
||||
Then, just edit the file and replace the generic Django text with your own
|
||||
site's name and URL as you see fit.
|
||||
|
||||
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`` --
|
||||
copy it from the default directory into your custom directory, and make
|
||||
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
|
||||
==============================
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
``base_site.html`` in the previous section -- copy it from the default directory
|
||||
to your custom template directory.) Edit the file, and you'll see it uses a
|
||||
template tag called ``{% get_admin_app_list as app_list %}``. That's the magic
|
||||
that retrieves every installed Django app. Instead of using that, you can
|
||||
The template to customize is ``admin/index.html``. (Do the same as with
|
||||
``admin/base_site.html`` in the previous section -- copy it from the default
|
||||
directory to your custom template directory.) Edit the file, and you'll see it
|
||||
uses a template tag called ``{% get_admin_app_list as app_list %}``. That's the
|
||||
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
|
||||
best.
|
||||
|
||||
|
|