diff options
| author | Georg Bauer <gb@hugo.westfalen.de> | 2005-10-18 10:50:15 +0000 |
|---|---|---|
| committer | Georg Bauer <gb@hugo.westfalen.de> | 2005-10-18 10:50:15 +0000 |
| commit | f99782e48eafbda4a25e1b2d7aeda59260e9e02b (patch) | |
| tree | 9f1dd974404a3ebb0f9e97823371941d18d109da | |
| parent | 6179bb6448d1e9768a2510cfe6c14e89ce10221d (diff) | |
| parent | d5f32aa008bf12affa134d8f1d872fbd35bf2b69 (diff) | |
i18n: merged to [931] from trunk
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@932 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | django/conf/admin_media/css/changelists.css | 82 | ||||
| -rw-r--r-- | django/conf/admin_media/css/global.css | 69 | ||||
| -rw-r--r-- | django/conf/urls/admin.py | 35 | ||||
| -rw-r--r-- | django/contrib/admin/__init__.py (renamed from django/views/admin/__init__.py) | 0 | ||||
| -rw-r--r-- | django/contrib/admin/urls/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/admin/views/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/admin/views/decorators.py | 100 | ||||
| -rw-r--r-- | django/contrib/admin/views/doc.py (renamed from django/views/admin/doc.py) | 16 | ||||
| -rw-r--r-- | django/contrib/admin/views/main.py (renamed from django/views/admin/main.py) | 16 | ||||
| -rw-r--r-- | django/contrib/admin/views/template.py (renamed from django/views/admin/template.py) | 2 | ||||
| -rw-r--r-- | docs/templates.txt | 8 |
11 files changed, 184 insertions, 144 deletions
diff --git a/django/conf/admin_media/css/changelists.css b/django/conf/admin_media/css/changelists.css index 966ca4a486..7ff59c5e6b 100644 --- a/django/conf/admin_media/css/changelists.css +++ b/django/conf/admin_media/css/changelists.css @@ -1,60 +1,44 @@ -/* - ______________________________ - DJANGO - Admin Changelist Styles - - Extends base.css - - by Wilson Miner - wilson@lawrence.com - - Copyright (c) 2005 - Lawrence Journal-World - - 645 New Hampshire - Lawrence, KS 66044 - +/* + DJANGO Admin Changelist Styles + by Wilson Miner wilson@lawrence.com + Copyright (c) 2005 Lawrence Journal-World */ -#changelist {position:relative; width:100%;} -#changelist table {width:100%;} -.change-list .filtered table { border-right:1px solid #ddd, width:100%; } -.change-list .filtered {min-height:400px; _height:400px;} -.change-list .filtered {background:white url(../img/admin/changelist-bg.gif) top right repeat-y !important;} -.change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull {margin-right:160px !important; width:auto !important; } -.change-list .filtered table tbody th {padding-right:10px;} -#changelist .toplinks {border-bottom:1px solid #ccc !important;} -#changelist .paginator { color:#666; border-top:1px solid #eee; border-bottom:1px solid #eee; background:white url(../img/admin/nav-bg.gif) 0 180% repeat-x; overflow:hidden;} +#changelist { position:relative; width:100%; } +#changelist table { width:100%; } +.change-list .filtered table { border-right:1px solid #ddd; } +.change-list .filtered { min-height:400px; _height:400px; } +.change-list .filtered { background:white url(../img/admin/changelist-bg.gif) top right repeat-y !important; } +.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right:160px !important; width:auto !important; } +.change-list .filtered table tbody th { padding-right:10px; } +#changelist .toplinks { border-bottom:1px solid #ccc !important; } +#changelist .paginator { color:#666; border-top:1px solid #eee; border-bottom:1px solid #eee; background:white url(../img/admin/nav-bg.gif) 0 180% repeat-x; overflow:hidden; } .change-list .filtered .paginator { border-right:1px solid #ddd; } /* CHANGELIST TABLES */ - -#changelist table thead th {white-space:nowrap;} -#changelist table tbody td {border-left: 1px solid #ddd;} -#changelist table tfoot {color: #666;} +#changelist table thead th { white-space:nowrap; } +#changelist table tbody td { border-left: 1px solid #ddd; } +#changelist table tfoot { color: #666; } /* TOOLBAR */ - -#changelist #toolbar {padding:3px; border-bottom:1px solid #ddd; background:#e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; color:#666;} -#changelist #toolbar form input {font-size:11px; padding:1px 2px;} -#changelist #toolbar form #searchbar {padding:2px;} -#changelist #changelist-search img {vertical-align:middle;} +#changelist #toolbar { padding:3px; border-bottom:1px solid #ddd; background:#e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; color:#666; } +#changelist #toolbar form input { font-size:11px; padding:1px 2px; } +#changelist #toolbar form #searchbar { padding:2px; } +#changelist #changelist-search img { vertical-align:middle; } /* FILTER COLUMN */ - -#changelist-filter {position:absolute; top:0; right:0; z-index:1000; width:160px; border-left:1px solid #ddd; background:#efefef; margin:0;} -#changelist-filter h2 {font-size:11px; padding:2px 5px; border-bottom:1px solid #ddd;} -#changelist-filter h3 {font-size:12px; margin-bottom:0;} -#changelist-filter ul {padding-left:0;margin-left:10px;_margin-right:-10px;} -#changelist-filter li {list-style-type:none; margin-left:0; padding-left:0;} -#changelist-filter a {color:#999;} -#changelist-filter a:hover {color:#036;} -#changelist-filter li.selected {border-left:5px solid #ccc; padding-left:5px;margin-left:-10px;} -#changelist-filter li.selected a {color:#5b80b2 !important;} +#changelist-filter { position:absolute; top:0; right:0; z-index:1000; width:160px; border-left:1px solid #ddd; background:#efefef; margin:0; } +#changelist-filter h2 { font-size:11px; padding:2px 5px; border-bottom:1px solid #ddd; } +#changelist-filter h3 { font-size:12px; margin-bottom:0; } +#changelist-filter ul { padding-left:0;margin-left:10px;_margin-right:-10px; } +#changelist-filter li { list-style-type:none; margin-left:0; padding-left:0; } +#changelist-filter a { color:#999; } +#changelist-filter a:hover { color:#036; } +#changelist-filter li.selected { border-left:5px solid #ccc; padding-left:5px;margin-left:-10px; } +#changelist-filter li.selected a { color:#5b80b2 !important; } /* DATE DRILLDOWN */ - -.change-list ul.toplinks {display:block; background:white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; border-top:1px solid white; float:left; padding:0 !important; margin:0 !important; width:100%;} -.change-list ul.toplinks li {float: left; width: 9em; padding:3px 6px; font-weight: bold; list-style-type:none;} -.change-list ul.toplinks .date-back a {color:#999;} -.change-list ul.toplinks .date-back a:hover {color:#036;} +.change-list ul.toplinks { display:block; background:white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; border-top:1px solid white; float:left; padding:0 !important; margin:0 !important; width:100%; } +.change-list ul.toplinks li { float: left; width: 9em; padding:3px 6px; font-weight: bold; list-style-type:none; } +.change-list ul.toplinks .date-back a { color:#999; } +.change-list ul.toplinks .date-back a:hover { color:#036; } diff --git a/django/conf/admin_media/css/global.css b/django/conf/admin_media/css/global.css index 7c60bf9755..453998c363 100644 --- a/django/conf/admin_media/css/global.css +++ b/django/conf/admin_media/css/global.css @@ -1,45 +1,17 @@ /* - ______________________________ - DJANGO - Admin Global Styles - - Extends base.css - - by Wilson Miner - wilson@lawrence.com - - Copyright (c) 2005 - Lawrence Journal-World - - 645 New Hampshire - Lawrence, KS 66044 - - ______________________________ - SITE DIMENSIONS - - Site Width: 768px - Content Width: 750px - Main Column: 580px - Sidebar: 220px - - ______________________________ - COLORS - - Blue #5b80b2 - Dark Blue #036 - + DJANGO Admin Global Styles + by Wilson Miner wilson@lawrence.com + Copyright (c) 2005 Lawrence Journal-World */ body { margin:0; padding:0; font-family:"Lucida Grande","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; } /* LINKS */ - a:link, a:visited { color: #5b80b2; text-decoration:none; } a:hover { color: #036; } a img { border:none; } /* GLOBAL DEFAULTS */ - p, ol, ul, dl { margin:.2em 0 .8em 0; font-size:12px; } p { padding:0; line-height:140%; } h1,h2,h3,h4,h5 { font-weight:bold; } @@ -67,7 +39,6 @@ div.system-message { background: #ffc; margin: 10px; padding: 6px 8px; font-size div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; color:red;background:#ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; } /* PAGE STRUCTURE */ - #container { position:relative; width:100%; min-width:720px; } #header { text-align:left; min-height:55px; _height:55px; } #content { margin:10px 15px; } @@ -76,13 +47,6 @@ div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; #footer { clear:both; padding:10px; } /* COLUMN TYPES */ -/* - colM = Main | M | - colMS = Main, Sidebar | M |S| - colSM = Sidebar, Main |S| M | - flex = single-column, liquid width - superwide = single-column, extra-wide fixed width -*/ .colMS, .colM, .colSM, .colM #content-main, .colM #content-main .xfull { width:758px; } /* master site width for fixed-width pages */ .colMS #content-main, .colSM #content-main, .colMS #content-main .xfull, .colSM #content-main .xfull { width:519px; } /* main column width for 2-column pages */ .colMS #content-related, .colSM #content-related, .colSMS #content-related { width:220px; } /* sidebar column width */ @@ -94,7 +58,6 @@ div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; .subcol { float:left; width:46%; margin-right:15px; } /* WIDTHS */ - .x50 { width:50px; } .x75 { width:75px; } .x100 { width:100px; } @@ -106,7 +69,6 @@ div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; .x500 { width:500px; } /* HEADER */ - #header { background:#417690; color:#ffc; } #header a:link, #header a:visited { color:white; } #header a:hover { text-decoration:underline; } @@ -117,12 +79,10 @@ div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; /* SIDEBAR */ - #content-related h3 { font-size:12px; color:#666; margin-bottom:3px; } #content-related h4 { font-size:11px; } /* TABLES */ - table { border-collapse:collapse; border-color:#ccc; } td, th { font-size:11px; line-height:13px; border-bottom:1px solid #eee; vertical-align:top; padding:5px; font-family:"Lucida Grande", Verdana, Arial, sans-serif; } th { text-align:left; font-size:12px; } @@ -141,7 +101,6 @@ table#change-history { width:100%; } table#change-history tbody th { width:16em; } /* TABLE SORTING */ - thead th a:link, thead th a:visited { color:#666; display:block; } table thead th.sorted { background-position:bottom left !important; } table thead th.sorted a { padding-right:13px; } @@ -149,7 +108,6 @@ table thead th.ascending a { background:url(../img/admin/arrow-down.gif) right . table thead th.descending a { background:url(../img/admin/arrow-up.gif) right .4em no-repeat; } /* MODULES */ - .module { border:1px solid #ccc; margin-bottom:5px; background:white; } .module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; } .module blockquote { margin-left:12px; } @@ -173,7 +131,6 @@ textarea { vertical-align:top !important; } input[type=checkbox], input[type=radio] { border:none; } /* FORM BUTTONS */ - input[type=submit], input[type=button], .submit-row input { background:white url(../img/admin/nav-bg.gif) bottom repeat-x; padding:3px; } input[type=submit]:active, input[type=button]:active { background-image:url(../img/admin/nav-bg-reverse.gif); background-position:top; } input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; } @@ -183,7 +140,6 @@ input[type=submit].default:active { background-image:url(../img/admin/default-bg .submit-row .float-left { padding-top:.1em; } /* FORM ROWS */ - .form-row { clear:both; padding:8px 12px; font-size:11px; } html>body .form-row { border-bottom:1px solid #eee; } .form-row:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } @@ -191,21 +147,18 @@ html>body .form-row { border-bottom:1px solid #eee; } form .form-row p { padding-left:0; font-size:11px; } /* FORM LABELS */ - form h4 { margin:0 !important; padding:0 !important; border:none !important; } label { font-weight:normal !important; color:#666; font-size:12px; } label.inline { margin-left:20px; } .required label, label.required { font-weight:bold !important; color:#333 !important; } /* RADIO BUTTONS */ - form ul.radiolist li { list-style-type:none; } form ul.radiolist label { float:none; display:inline; } form ul.inline { margin-left:0; padding:0; } form ul.inline li { float:left; padding-right:7px; } /* ALIGNED FIELDSETS */ - .aligned label { display:block; padding:0 1em 3px 0; float:left; text-align:left; width:8em; } .aligned label.inline { display:inline; float:none; } .colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { width:350px; } @@ -217,14 +170,12 @@ form .aligned p.help { padding-left:38px; } .checkbox-row p.help { margin-left:0; padding-left:0 !important; } /* WIDE FIELDSETS */ - .wide label { width:15em !important; } form .wide p { margin-left:15em; } form .wide p.help { padding-left:38px; } .colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { width:450px; } /* COLLAPSED FIELDSETS */ - fieldset.collapsed * { display:none; } fieldset.collapsed h2, fieldset.collapsed { display:block !important; } fieldset.collapsed .collapse-toggle { display: inline !important; } @@ -233,7 +184,6 @@ fieldset.collapse h2 a.collapse-toggle:hover { text-decoration:underline; } .hidden { display:none; } /* MESSAGES & ERRORS */ - ul.messagelist { padding:0 0 5px 0; margin:0; } ul.messagelist li { font-size:12px; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border-bottom:1px solid #ddd; color:#666; background:#ffc url(../img/admin/icon_success.gif) 5px .3em no-repeat; } .errornote { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:red;background:#ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; } @@ -245,7 +195,6 @@ td ul.errorlist li { margin:0 !important; } .error input, .error select { border:1px solid red; } /* ACTION ICONS */ - .addlink { padding-left:12px; background:url(../img/admin/icon_addlink.gif) 0 .2em no-repeat; } .changelink { padding-left:12px; background:url(../img/admin/icon_changelink.gif) 0 .2em no-repeat; } .deletelink { padding-left:12px; background:url(../img/admin/icon_deletelink.gif) 0 50% no-repeat; } @@ -253,7 +202,6 @@ a.deletelink:link, a.deletelink:visited { color:#CC3434; } a.deletelink:hover { color:#993333; } /* OBJECT TOOLS */ - .object-tools { font-size:10px; font-weight:bold; font-family:Arial,Helvetica,sans-serif; padding-left:0; margin-bottom:5px; float:right; position:relative; margin-top:-2.4em; margin-bottom:-2em; } .form-row .object-tools { margin-top:0; margin-bottom:0; } .object-tools li { display:block; float:left; background:url(../img/admin/tool-left.gif) 0 0 no-repeat; padding:0 0 0 8px; margin-left:2px; height:16px; } @@ -266,17 +214,14 @@ a.deletelink:hover { color:#993333; } .object-tools a.addlink:hover { background:#5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat; } /* INLINE CONTROLS */ - #inline-controls { font-weight:bold; font-size:12px; } #inline-specific-controls { margin-left:6px; padding:0 8px; border-left:6px solid #ccc; } /* BREADCRUMBS */ - p.breadcrumbs { font-size:11px; color:#ccc;text-align:left; } /* old breadcrumbs style */ div.breadcrumbs { background:white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; padding:2px 8px 3px 8px; font-size:11px; color:#999; border-top:1px solid white; border-bottom:1px solid #ccc; text-align:left; } /* SELECTOR (FILTER INTERFACE) */ - .selector { width:580px; float:left; } .selector select { width:270px; height:170px; } .selector-available, .selector-chosen { float:left; width:270px; text-align:center; margin-bottom:5px; } @@ -297,7 +242,6 @@ a.selector-chooseall { width:7em; background:url(../img/admin/selector-addall.gi a.selector-clearall { background:url(../img/admin/selector-removeall.gif) left center no-repeat; } /* Stacked selectors for long items */ - .stacked { float:left; width:500px; } .stacked select { width:480px; height:100px; } .stacked .selector-available, .stacked .selector-chosen { width:480px; } @@ -310,20 +254,17 @@ a.selector-clearall { background:url(../img/admin/selector-removeall.gif) left c .stacked .selector-remove { background-image:url(../img/admin/selector_stacked-remove.gif); } /* DATE AND TIME */ - p.datetime { line-height:20px; margin:0; padding:0; color:#666; font-size:11px; font-weight:bold; } .datetime span { font-size:11px; font-weight:normal; white-space:nowrap; } .vDateField { margin-left:4px; } table p.datetime { font-size:10px; margin-left:0; padding-left:0; } /* FILE UPLOADS */ - p.file-upload { line-height:20px; margin:0; padding:0; color:#666; font-size:11px; font-weight:bold; } .file-upload a { font-weight:normal; } .file-upload .deletelink { margin-left:5px; } /* CALENDARS & CLOCKS */ - .calendarbox, .clockbox { margin:5px auto; width: 10em; text-align: center; background:white; position:relative; } .clockbox { width:6em; } .calendar { margin:0; padding: 0; } @@ -350,14 +291,12 @@ ul.timelist, .timelist li { list-style-type:none; margin:0; padding:0; } .timelist a { padding:2px; } /* ORDERING WIDGET */ - ul#orderthese { padding:0; margin:0; list-style-type:none; } ul#orderthese li { list-style-type:none; display:block; padding:0; margin:6px 0; width:214px; background:#f6f6f6; white-space:nowrap; overflow:hidden; } ul#orderthese li span { display:block; border:1px solid #e7e7e7; background:transparent url(../img/admin/nav-bg-grabber.gif) top left repeat-y; font-size:10px !important; padding:4px 6px 4px 12px; } ul#orderthese span:hover { background-color:#efefef; } /* PAGINATOR */ - .paginator { font-size:11px; padding-top:10px; padding-bottom:10px; line-height:22px; margin:0; border-top:1px solid #ddd; } .paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; } .paginator a.showall { padding:0 !important; border:none !important; } @@ -367,7 +306,6 @@ ul#orderthese span:hover { background-color:#efefef; } .paginator a:hover { color:white; background:#5b80b2; border-color:#036; } /* TEXT STYLES & MODIFIERS */ - .small { font-size:11px; } .tiny { font-size:10px; } p.tiny { margin-top:-2px; } @@ -386,7 +324,6 @@ p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align:middle; } .nowrap { white-space:nowrap; } /* CUSTOM FORM FIELDS */ - .vSelectMultipleField { vertical-align:top !important; } .vCheckboxField { border:none; } .vDateField, .vTimeField { margin-right:2px; } diff --git a/django/conf/urls/admin.py b/django/conf/urls/admin.py index 841d50523e..d03b88ceb4 100644 --- a/django/conf/urls/admin.py +++ b/django/conf/urls/admin.py @@ -2,24 +2,24 @@ from django.conf.urls.defaults import * from django.conf.settings import INSTALLED_APPS urlpatterns = ( - ('^$', 'django.views.admin.main.index'), + ('^$', 'django.contrib.admin.views.main.index'), ('^logout/$', 'django.views.auth.login.logout'), ('^password_change/$', 'django.views.registration.passwords.password_change'), ('^password_change/done/$', 'django.views.registration.passwords.password_change_done'), - ('^template_validator/$', 'django.views.admin.template.template_validator'), + ('^template_validator/$', 'django.contrib.admin.views.template.template_validator'), # Documentation - ('^doc/$', 'django.views.admin.doc.doc_index'), - ('^doc/bookmarklets/$', 'django.views.admin.doc.bookmarklets'), - ('^doc/tags/$', 'django.views.admin.doc.template_tag_index'), - ('^doc/filters/$', 'django.views.admin.doc.template_filter_index'), - ('^doc/views/$', 'django.views.admin.doc.view_index'), - ('^doc/views/jump/$', 'django.views.admin.doc.jump_to_view'), - ('^doc/views/(?P<view>[^/]+)/$', 'django.views.admin.doc.view_detail'), - ('^doc/models/$', 'django.views.admin.doc.model_index'), - ('^doc/models/(?P<model>[^/]+)/$', 'django.views.admin.doc.model_detail'), + ('^doc/$', 'django.contrib.admin.views.doc.doc_index'), + ('^doc/bookmarklets/$', 'django.contrib.admin.views.doc.bookmarklets'), + ('^doc/tags/$', 'django.contrib.admin.views.doc.template_tag_index'), + ('^doc/filters/$', 'django.contrib.admin.views.doc.template_filter_index'), + ('^doc/views/$', 'django.contrib.admin.views.doc.view_index'), + ('^doc/views/jump/$', 'django.contrib.admin.views.doc.jump_to_view'), + ('^doc/views/(?P<view>[^/]+)/$', 'django.contrib.admin.views.doc.view_detail'), + ('^doc/models/$', 'django.contrib.admin.views.doc.model_index'), + ('^doc/models/(?P<model>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'), # ('^doc/templates/$', 'django.views.admin.doc.template_index'), - ('^doc/templates/(?P<template>.*)/$', 'django.views.admin.doc.template_detail'), + ('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'), ) if 'ellington.events' in INSTALLED_APPS: @@ -48,11 +48,10 @@ if 'ellington.media' in INSTALLED_APPS: urlpatterns += ( # Metasystem admin pages - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/$', 'django.views.admin.main.change_list'), - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/add/$', 'django.views.admin.main.add_stage'), - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/jsvalidation/$', 'django.views.admin.jsvalidation.jsvalidation'), - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/history/$', 'django.views.admin.main.history'), - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/delete/$', 'django.views.admin.main.delete_stage'), - ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/$', 'django.views.admin.main.change_stage'), + ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/$', 'django.contrib.admin.views.main.change_list'), + ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'), + ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/history/$', 'django.contrib.admin.views.main.history'), + ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/delete/$', 'django.contrib.admin.views.main.delete_stage'), + ('^(?P<app_label>[^/]+)/(?P<module_name>[^/]+)/(?P<object_id>.+)/$', 'django.contrib.admin.views.main.change_stage'), ) urlpatterns = patterns('', *urlpatterns) diff --git a/django/views/admin/__init__.py b/django/contrib/admin/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/django/views/admin/__init__.py +++ b/django/contrib/admin/__init__.py diff --git a/django/contrib/admin/urls/__init__.py b/django/contrib/admin/urls/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/django/contrib/admin/urls/__init__.py diff --git a/django/contrib/admin/views/__init__.py b/django/contrib/admin/views/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/django/contrib/admin/views/__init__.py diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py new file mode 100644 index 0000000000..44e1234ce4 --- /dev/null +++ b/django/contrib/admin/views/decorators.py @@ -0,0 +1,100 @@ +from django.core.extensions import DjangoContext, render_to_response +from django.conf.settings import SECRET_KEY +from django.models.auth import users +from django.utils import httpwrappers +import base64, md5 +import cPickle as pickle + +ERROR_MESSAGE = "Please enter a correct username and password. Note that both fields are case-sensitive." +LOGIN_FORM_KEY = 'this_is_the_login_form' + +def _display_login_form(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('admin/login', { + 'title': 'Log in', + 'app_path': request.path, + 'post_data': post_data, + 'error_message': error_message + }, context_instance=DjangoContext(request)) + +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) + +def staff_member_required(view_func): + """ + Decorator for views that checks that the user is logged in and is a staff + member, displaying the login page if necessary. + """ + def _checklogin(request, *args, **kwargs): + if not request.user.is_anonymous() and request.user.is_staff: + # The user is valid. Continue to the admin page. + return view_func(request, *args, **kwargs) + + assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.middleware.sessions.SessionMiddleware'." + + # If this isn't already the login page, display it. + if not request.POST.has_key(LOGIN_FORM_KEY): + if request.POST: + message = "Please log in again, because your session has expired. "\ + "Don't worry: Your submission has been saved." + else: + message = "" + return _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 _display_login_form(request, message) + + # Check the password. + username = request.POST.get('username', '') + try: + user = users.get_object(username__exact=username, is_staff__exact=True) + 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 _display_login_form(request, message) + + # The user data is correct; log in the user in and continue. + else: + if user.check_password(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(LOGIN_FORM_KEY): + # overwrite request.POST with the saved post_data, and continue + request.POST = post_data + request.user = user + return view_func(request, *args, **kwargs) + else: + request.session.delete_test_cookie() + return httpwrappers.HttpResponseRedirect(request.path) + else: + return _display_login_form(request, ERROR_MESSAGE) + + return _checklogin diff --git a/django/views/admin/doc.py b/django/contrib/admin/views/doc.py index 64785385c4..c56a02c45d 100644 --- a/django/views/admin/doc.py +++ b/django/contrib/admin/views/doc.py @@ -1,11 +1,12 @@ from django.core import meta from django import templatetags from django.conf import settings +from django.contrib.admin.views.decorators import staff_member_required from django.models.core import sites from django.core.extensions import DjangoContext, render_to_response from django.core.exceptions import Http404, ViewDoesNotExist -from django.core import template, template_loader, urlresolvers -from django.core.template import defaulttags, defaultfilters +from django.core import template, urlresolvers +from django.core.template import defaulttags, defaultfilters, loader try: from django.parts.admin import doc except ImportError: @@ -19,11 +20,13 @@ def doc_index(request): if not doc: return missing_docutils_page(request) return render_to_response('doc/index', context_instance=DjangoContext(request)) +doc_index = staff_member_required(doc_index) def bookmarklets(request): return render_to_response('doc/bookmarklets', { 'admin_url' : "%s://%s" % (os.environ.get('HTTPS') == 'on' and 'https' or 'http', request.META['HTTP_HOST']), }, context_instance=DjangoContext(request)) +bookmarklets = staff_member_required(bookmarklets) def template_tag_index(request): import sys @@ -61,6 +64,7 @@ def template_tag_index(request): template.registered_tags, template.registered_filters = saved_tagset return render_to_response('doc/template_tag_index', {'tags': tags}, context_instance=DjangoContext(request)) +template_tag_index = staff_member_required(template_tag_index) def template_filter_index(request): if not doc: @@ -93,6 +97,7 @@ def template_filter_index(request): template.registered_tags, template.registered_filters = saved_tagset return render_to_response('doc/template_filter_index', {'filters': filters}, context_instance=DjangoContext(request)) +template_filter_index = staff_member_required(template_filter_index) def view_index(request): if not doc: @@ -112,6 +117,7 @@ def view_index(request): 'url' : simplify_regex(regex), }) return render_to_response('doc/view_index', {'views': views}, context_instance=DjangoContext(request)) +view_index = staff_member_required(view_index) def view_detail(request, view): if not doc: @@ -135,6 +141,7 @@ def view_detail(request, view): 'body': body, 'meta': metadata, }, context_instance=DjangoContext(request)) +view_detail = staff_member_required(view_detail) def model_index(request): if not doc: @@ -150,6 +157,7 @@ def model_index(request): 'class' : opts.module_name, }) return render_to_response('doc/model_index', {'models': models}, context_instance=DjangoContext(request)) +model_index = staff_member_required(model_index) def model_detail(request, model): if not doc: @@ -191,6 +199,7 @@ def model_detail(request, model): 'summary': "Fields on %s objects" % opts.verbose_name, 'fields': fields, }, context_instance=DjangoContext(request)) +model_detail = staff_member_required(model_detail) def template_detail(request, template): templates = [] @@ -210,6 +219,7 @@ def template_detail(request, template): 'name': template, 'templates': templates, }, context_instance=DjangoContext(request)) +template_detail = staff_member_required(template_detail) #################### # Helper functions # @@ -223,7 +233,7 @@ def load_all_installed_template_libraries(): # Clear out and reload default tags template.registered_tags.clear() reload(defaulttags) - reload(template_loader) # template_loader defines the block/extends tags + reload(loader) # loader defines the block/extends tags # Load any template tag libraries from installed apps for e in templatetags.__path__: diff --git a/django/views/admin/main.py b/django/contrib/admin/views/main.py index 5379c8efb5..685f3b6cba 100644 --- a/django/views/admin/main.py +++ b/django/contrib/admin/views/main.py @@ -1,6 +1,8 @@ # Generic admin views, with admin templates created dynamically at runtime. -from django.core import formfields, meta, template_loader +from django.contrib.admin.views.decorators import staff_member_required +from django.core import formfields, meta +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 @@ -48,6 +50,7 @@ def get_query_string(original_params, new_params={}, remove=[]): def index(request): return render_to_response('index', {'title': 'Site administration'}, context_instance=Context(request)) +index = staff_member_required(index) def change_list(request, app_label, module_name): from django.core import paginator @@ -486,12 +489,13 @@ def change_list(request, app_label, module_name): raw_template.append('</div>\n</div>') raw_template.append('{% endblock %}\n') - t = template_loader.get_template_from_string(''.join(raw_template)) + t = loader.get_template_from_string(''.join(raw_template)) c = Context(request, { 'title': (is_popup and 'Select %s' % opts.verbose_name or 'Select %s to change' % opts.verbose_name), 'is_popup': is_popup, }) return HttpResponse(t.render(c)) +change_list = staff_member_required(change_list) def _get_flattened_data(field, val): """ @@ -850,8 +854,9 @@ def add_stage(request, app_label, module_name, show_delete=False, form_url='', p c['object_id'] = object_id_override raw_template = _get_template(opts, app_label, add=True, show_delete=show_delete, form_url=form_url) # return HttpResponse(raw_template, mimetype='text/plain') - t = template_loader.get_template_from_string(raw_template) + t = loader.get_template_from_string(raw_template) return HttpResponse(t.render(c)) +add_stage = staff_member_required(add_stage) def change_stage(request, app_label, module_name, object_id): mod, opts = _get_mod_opts(app_label, module_name) @@ -975,8 +980,9 @@ def change_stage(request, app_label, module_name, object_id): }) raw_template = _get_template(opts, app_label, change=True) # return HttpResponse(raw_template, mimetype='text/plain') - t = template_loader.get_template_from_string(raw_template) + t = loader.get_template_from_string(raw_template) return HttpResponse(t.render(c)) +change_stage = staff_member_required(change_stage) def _nest_help(obj, depth, val): current = obj @@ -1088,6 +1094,7 @@ def delete_stage(request, app_label, module_name, object_id): "deleted_objects": deleted_objects, "perms_lacking": perms_needed, }, context_instance=Context(request)) +delete_stage = staff_member_required(delete_stage) def history(request, app_label, module_name, object_id): mod, opts = _get_mod_opts(app_label, module_name) @@ -1101,3 +1108,4 @@ def history(request, app_label, module_name, object_id): 'module_name': capfirst(opts.verbose_name_plural), 'object': obj, }, context_instance=Context(request)) +history = staff_member_required(history) diff --git a/django/views/admin/template.py b/django/contrib/admin/views/template.py index c35770178e..97f67e04c1 100644 --- a/django/views/admin/template.py +++ b/django/contrib/admin/views/template.py @@ -1,3 +1,4 @@ +from django.contrib.admin.views.decorators import staff_member_required from django.core import formfields, validators from django.core import template from django.core.template import loader @@ -26,6 +27,7 @@ def template_validator(request): 'title': 'Template validator', 'form': formfields.FormWrapper(manipulator, new_data, errors), }, context_instance=DjangoContext(request)) +template_validator = staff_member_required(template_validator) class TemplateValidator(formfields.Manipulator): def __init__(self, settings_modules): diff --git a/docs/templates.txt b/docs/templates.txt index 215b663634..5c52371c8a 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -399,13 +399,13 @@ Built-in tag reference block are output:: {% if athlete_list %} - Number of athletes: {{ athlete_list|count }} + Number of athletes: {{ athlete_list|length }} {% else %} No athletes. {% endif %} In the above, if ``athlete_list`` is not empty, the number of athletes will be - displayed by the ``{{ athlete_list|count }}`` variable. + displayed by the ``{{ athlete_list|length }}`` variable. As you can see, the ``if`` tag can take an option ``{% else %}`` clause that will be displayed if the test fails. @@ -432,8 +432,8 @@ Built-in tag reference {% if athlete_list %} {% if coach_list %} - Number of athletes: {{ athlete_list|count }}. - Number of coaches: {{ coach_list|count }}. + Number of athletes: {{ athlete_list|length }}. + Number of coaches: {{ coach_list|length }}. {% endif %} {% endif %} |
