Skip to content

Commit 0b5c67a

Browse files
committed
[soc2009/model-validation] Merged from trunk up to [12093].
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@12094 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 6e8d2dd commit 0b5c67a

File tree

24 files changed

+542
-71
lines changed

24 files changed

+542
-71
lines changed

django/conf/global_settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
# The default is to use the SMTP backend.
144144
# Third-party backends can be specified by providing a Python path
145145
# to a module that defines an EmailBackend class.
146-
EMAIL_BACKEND = 'django.core.mail.backends.smtp'
146+
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
147147

148148
# Host for sending e-mail.
149149
EMAIL_HOST = 'localhost'

django/contrib/admin/media/js/admin/DateTimeShortcuts.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ var DateTimeShortcuts = {
4444
var shortcuts_span = document.createElement('span');
4545
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
4646
var now_link = document.createElement('a');
47-
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
47+
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + get_format('TIME_INPUT_FORMATS')[0] + "'));");
4848
now_link.appendChild(document.createTextNode(gettext('Now')));
4949
var clock_link = document.createElement('a');
5050
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
@@ -80,10 +80,11 @@ var DateTimeShortcuts = {
8080
quickElement('h2', clock_box, gettext('Choose a time'));
8181
time_list = quickElement('ul', clock_box, '');
8282
time_list.className = 'timelist';
83-
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
84-
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
85-
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
86-
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
83+
time_format = get_format('TIME_INPUT_FORMATS')[0];
84+
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
85+
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
86+
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
87+
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");
8788

8889
cancel_p = quickElement('p', clock_box, '');
8990
cancel_p.className = 'calendar-cancel';
@@ -236,7 +237,7 @@ var DateTimeShortcuts = {
236237
DateTimeShortcuts.calendars[num].drawNextMonth();
237238
},
238239
handleCalendarCallback: function(num) {
239-
format = gettext('DATE_INPUT_FORMATS');
240+
format = get_format('DATE_INPUT_FORMATS')[0];
240241
// the format needs to be escaped a little
241242
format = format.replace('\\', '\\\\');
242243
format = format.replace('\r', '\\r');
@@ -248,7 +249,7 @@ var DateTimeShortcuts = {
248249
handleCalendarQuickLink: function(num, offset) {
249250
var d = new Date();
250251
d.setDate(d.getDate() + offset)
251-
DateTimeShortcuts.calendarInputs[num].value = d.strftime(gettext('DATE_INPUT_FORMATS'));
252+
DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
252253
DateTimeShortcuts.dismissCalendar(num);
253254
},
254255
cancelEventPropagation: function(e) {

django/contrib/admin/media/js/calendar.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function quickElement() {
2525
var CalendarNamespace = {
2626
monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
2727
daysOfWeek: gettext('S M T W T F S').split(' '),
28-
firstDayOfWeek: parseInt(gettext('FIRST_DAY_OF_WEEK')),
28+
firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
2929
isLeapYear: function(year) {
3030
return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
3131
},
@@ -46,6 +46,12 @@ var CalendarNamespace = {
4646
return days;
4747
},
4848
draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
49+
var today = new Date();
50+
var todayDay = today.getDate();
51+
var todayMonth = today.getMonth()+1;
52+
var todayYear = today.getFullYear();
53+
var todayClass = '';
54+
4955
month = parseInt(month);
5056
year = parseInt(year);
5157
var calDiv = document.getElementById(div_id);
@@ -76,7 +82,13 @@ var CalendarNamespace = {
7682
if (i%7 == 0 && currentDay != 1) {
7783
tableRow = quickElement('tr', tableBody);
7884
}
79-
var cell = quickElement('td', tableRow, '');
85+
if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) {
86+
todayClass='today';
87+
} else {
88+
todayClass='';
89+
}
90+
var cell = quickElement('td', tableRow, '', 'class', todayClass);
91+
8092
quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
8193
currentDay++;
8294
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<dl id="comments">
2+
{% for comment in comment_list %}
3+
<dt id="c{{ comment.id }}">
4+
{{ comment.submit_date }} - {{ comment.name }}
5+
</dt>
6+
<dd>
7+
<p>{{ comment.comment }}</p>
8+
</dd>
9+
{% endfor %}
10+
</dl>

django/contrib/comments/templatetags/comments.py

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ def get_query_set(self, context):
8181
object_pk = smart_unicode(object_pk),
8282
site__pk = settings.SITE_ID,
8383
)
84-
84+
8585
# The is_public and is_removed fields are implementation details of the
8686
# built-in comment model's spam filtering system, so they might not
87-
# be present on a custom comment model subclass. If they exist, we
87+
# be present on a custom comment model subclass. If they exist, we
8888
# should filter on them.
8989
field_names = [f.name for f in self.comment_model._meta.fields]
9090
if 'is_public' in field_names:
@@ -169,6 +169,46 @@ def render(self, context):
169169
else:
170170
return ''
171171

172+
class RenderCommentListNode(CommentListNode):
173+
"""Render the comment list directly"""
174+
175+
#@classmethod
176+
def handle_token(cls, parser, token):
177+
"""Class method to parse render_comment_list and return a Node."""
178+
tokens = token.contents.split()
179+
if tokens[1] != 'for':
180+
raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0])
181+
182+
# {% render_comment_list for obj %}
183+
if len(tokens) == 3:
184+
return cls(object_expr=parser.compile_filter(tokens[2]))
185+
186+
# {% render_comment_list for app.models pk %}
187+
elif len(tokens) == 4:
188+
return cls(
189+
ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
190+
object_pk_expr = parser.compile_filter(tokens[3])
191+
)
192+
handle_token = classmethod(handle_token)
193+
194+
def render(self, context):
195+
ctype, object_pk = self.get_target_ctype_pk(context)
196+
if object_pk:
197+
template_search_list = [
198+
"comments/%s/%s/list.html" % (ctype.app_label, ctype.model),
199+
"comments/%s/list.html" % ctype.app_label,
200+
"comments/list.html"
201+
]
202+
qs = self.get_query_set(context)
203+
context.push()
204+
liststr = render_to_string(template_search_list, {
205+
"comment_list" : self.get_context_value_from_queryset(context, qs)
206+
}, context)
207+
context.pop()
208+
return liststr
209+
else:
210+
return ''
211+
172212
# We could just register each classmethod directly, but then we'd lose out on
173213
# the automagic docstrings-into-admin-docs tricks. So each node gets a cute
174214
# wrapper function that just exists to hold the docstring.
@@ -216,6 +256,24 @@ def get_comment_list(parser, token):
216256
"""
217257
return CommentListNode.handle_token(parser, token)
218258

259+
#@register.tag
260+
def render_comment_list(parser, token):
261+
"""
262+
Render the comment list (as returned by ``{% get_comment_list %}``)
263+
through the ``comments/list.html`` template
264+
265+
Syntax::
266+
267+
{% render_comment_list for [object] %}
268+
{% render_comment_list for [app].[model] [object_id] %}
269+
270+
Example usage::
271+
272+
{% render_comment_list for event %}
273+
274+
"""
275+
return RenderCommentListNode.handle_token(parser, token)
276+
219277
#@register.tag
220278
def get_comment_form(parser, token):
221279
"""
@@ -248,12 +306,28 @@ def comment_form_target():
248306
249307
Example::
250308
251-
<form action="{% comment_form_target %}" method="POST">
309+
<form action="{% comment_form_target %}" method="post">
252310
"""
253311
return comments.get_form_target()
254312

313+
#@register.simple_tag
314+
def get_comment_permalink(comment, anchor_pattern=None):
315+
"""
316+
Get the permalink for a comment, optionally specifying the format of the
317+
named anchor to be appended to the end of the URL.
318+
319+
Example::
320+
{{ get_comment_permalink comment "#c%(id)s-by-%(user_name)s" }}
321+
"""
322+
323+
if anchor_pattern:
324+
return comment.get_absolute_url(anchor_pattern)
325+
return comment.get_absolute_url()
326+
255327
register.tag(get_comment_count)
256328
register.tag(get_comment_list)
257329
register.tag(get_comment_form)
258330
register.tag(render_comment_form)
259331
register.simple_tag(comment_form_target)
332+
register.simple_tag(get_comment_permalink)
333+
register.tag(render_comment_list)

django/contrib/gis/db/models/sql/compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ def get_columns(self, with_aliases=False):
5555
aliases.add(r)
5656
col_aliases.add(col[1])
5757
else:
58-
result.append(col.as_sql(qn=qn))
59-
58+
result.append(col.as_sql(qn, self.connection))
59+
6060
if hasattr(col, 'alias'):
6161
aliases.add(col.alias)
6262
col_aliases.add(col.alias)
@@ -70,7 +70,7 @@ def get_columns(self, with_aliases=False):
7070
max_name_length = self.connection.ops.max_name_length()
7171
result.extend([
7272
'%s%s' % (
73-
self.get_extra_select_format(alias) % aggregate.as_sql(qn=qn, connection=self.connection),
73+
self.get_extra_select_format(alias) % aggregate.as_sql(qn, self.connection),
7474
alias is not None
7575
and ' AS %s' % qn(truncate_name(alias, max_name_length))
7676
or ''

django/contrib/localflavor/us/forms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, *args, **kwargs):
2323

2424
class USPhoneNumberField(CharField):
2525
default_error_messages = {
26-
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
26+
'invalid': _('Phone numbers must be in XXX-XXX-XXXX format.'),
2727
}
2828

2929
def clean(self, value):
@@ -85,7 +85,7 @@ class USStateField(Field):
8585
abbreviation for the given state.
8686
"""
8787
default_error_messages = {
88-
'invalid': u'Enter a U.S. state or territory.',
88+
'invalid': _('Enter a U.S. state or territory.'),
8989
}
9090

9191
def clean(self, value):

django/core/mail/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ def get_connection(backend=None, fail_silently=False, **kwds):
2828
"""
2929
path = backend or settings.EMAIL_BACKEND
3030
try:
31-
mod = import_module(path)
31+
mod_name, klass_name = path.rsplit('.', 1)
32+
mod = import_module(mod_name)
3233
except ImportError, e:
33-
raise ImproperlyConfigured(('Error importing email backend %s: "%s"'
34-
% (path, e)))
34+
raise ImproperlyConfigured(('Error importing email backend module %s: "%s"'
35+
% (mod_name, e)))
3536
try:
36-
cls = getattr(mod, 'EmailBackend')
37+
klass = getattr(mod, klass_name)
3738
except AttributeError:
3839
raise ImproperlyConfigured(('Module "%s" does not define a '
39-
'"EmailBackend" class' % path))
40-
return cls(fail_silently=fail_silently, **kwds)
40+
'"%s" class' % (mod_name, klass_name)))
41+
return klass(fail_silently=fail_silently, **kwds)
4142

4243

4344
def send_mail(subject, message, from_email, recipient_list,

django/core/servers/basehttp.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import sys
1616
import urllib
1717

18+
from django.core.management.color import color_style
1819
from django.utils.http import http_date
1920
from django.utils._os import safe_join
2021

@@ -557,6 +558,7 @@ def __init__(self, *args, **kwargs):
557558
# We set self.path to avoid crashes in log_message() on unsupported
558559
# requests (like "OPTIONS").
559560
self.path = ''
561+
self.style = color_style()
560562
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
561563

562564
def get_environ(self):
@@ -608,7 +610,26 @@ def log_message(self, format, *args):
608610
# Don't bother logging requests for admin images or the favicon.
609611
if self.path.startswith(self.admin_media_prefix) or self.path == '/favicon.ico':
610612
return
611-
sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format % args))
613+
614+
msg = "[%s] %s\n" % (self.log_date_time_string(), format % args)
615+
616+
# Utilize terminal colors, if available
617+
if args[1][0] == '2':
618+
# Put 2XX first, since it should be the common case
619+
msg = self.style.HTTP_SUCCESS(msg)
620+
elif args[1][0] == '1':
621+
msg = self.style.HTTP_INFO(msg)
622+
elif args[1][0] == '3':
623+
msg = self.style.HTTP_REDIRECT(msg)
624+
elif args[1] == '404':
625+
msg = self.style.HTTP_NOT_FOUND(msg)
626+
elif args[1][0] == '4':
627+
msg = self.style.HTTP_BAD_REQUEST(msg)
628+
else:
629+
# Any 5XX, or any other response
630+
msg = self.style.HTTP_SERVER_ERROR(msg)
631+
632+
sys.stderr.write(msg)
612633

613634
class AdminMediaHandler(object):
614635
"""

django/test/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def setup_test_environment():
4343
mail.SMTPConnection = locmem.EmailBackend
4444

4545
mail.original_email_backend = settings.EMAIL_BACKEND
46-
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem'
46+
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
4747

4848
mail.outbox = []
4949

django/utils/termcolors.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ def make_style(opts=(), **kwargs):
7878
'SQL_COLTYPE': {},
7979
'SQL_KEYWORD': {},
8080
'SQL_TABLE': {},
81+
'HTTP_INFO': {},
82+
'HTTP_SUCCESS': {},
83+
'HTTP_REDIRECT': {},
84+
'HTTP_BAD_REQUEST': {},
85+
'HTTP_NOT_FOUND': {},
86+
'HTTP_SERVER_ERROR': {},
8187
},
8288
DARK_PALETTE: {
8389
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
@@ -86,6 +92,12 @@ def make_style(opts=(), **kwargs):
8692
'SQL_COLTYPE': { 'fg': 'green' },
8793
'SQL_KEYWORD': { 'fg': 'yellow' },
8894
'SQL_TABLE': { 'opts': ('bold',) },
95+
'HTTP_INFO': { 'opts': ('bold',) },
96+
'HTTP_SUCCESS': { },
97+
'HTTP_REDIRECT': { 'fg': 'green' },
98+
'HTTP_BAD_REQUEST': { 'fg': 'red', 'opts': ('bold',) },
99+
'HTTP_NOT_FOUND': { 'fg': 'yellow' },
100+
'HTTP_SERVER_ERROR': { 'fg': 'magenta', 'opts': ('bold',) },
89101
},
90102
LIGHT_PALETTE: {
91103
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
@@ -94,6 +106,12 @@ def make_style(opts=(), **kwargs):
94106
'SQL_COLTYPE': { 'fg': 'green' },
95107
'SQL_KEYWORD': { 'fg': 'blue' },
96108
'SQL_TABLE': { 'opts': ('bold',) },
109+
'HTTP_INFO': { 'opts': ('bold',) },
110+
'HTTP_SUCCESS': { },
111+
'HTTP_REDIRECT': { 'fg': 'green', 'opts': ('bold',) },
112+
'HTTP_BAD_REQUEST': { 'fg': 'red', 'opts': ('bold',) },
113+
'HTTP_NOT_FOUND': { 'fg': 'red' },
114+
'HTTP_SERVER_ERROR': { 'fg': 'magenta', 'opts': ('bold',) },
97115
}
98116
}
99117
DEFAULT_PALETTE = DARK_PALETTE
@@ -117,7 +135,9 @@ def parse_color_setting(config_string):
117135
definition will augment the base palette definition.
118136
119137
Valid roles:
120-
'error', 'notice', 'sql_field', 'sql_coltype', 'sql_keyword', 'sql_table'
138+
'error', 'notice', 'sql_field', 'sql_coltype', 'sql_keyword', 'sql_table',
139+
'http_info', 'http_success', 'http_redirect', 'http_bad_request',
140+
'http_not_found', 'http_server_error'
121141
122142
Valid colors:
123143
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'

0 commit comments

Comments
 (0)