mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
[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
This commit is contained in:
parent
6e8d2dd4fb
commit
0b5c67a746
@ -143,7 +143,7 @@ DATABASES = {
|
|||||||
# The default is to use the SMTP backend.
|
# The default is to use the SMTP backend.
|
||||||
# Third-party backends can be specified by providing a Python path
|
# Third-party backends can be specified by providing a Python path
|
||||||
# to a module that defines an EmailBackend class.
|
# to a module that defines an EmailBackend class.
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
|
||||||
# Host for sending e-mail.
|
# Host for sending e-mail.
|
||||||
EMAIL_HOST = 'localhost'
|
EMAIL_HOST = 'localhost'
|
||||||
|
@ -44,7 +44,7 @@ var DateTimeShortcuts = {
|
|||||||
var shortcuts_span = document.createElement('span');
|
var shortcuts_span = document.createElement('span');
|
||||||
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
|
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
|
||||||
var now_link = document.createElement('a');
|
var now_link = document.createElement('a');
|
||||||
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + get_format('TIME_INPUT_FORMATS')[0] + "'));");
|
||||||
now_link.appendChild(document.createTextNode(gettext('Now')));
|
now_link.appendChild(document.createTextNode(gettext('Now')));
|
||||||
var clock_link = document.createElement('a');
|
var clock_link = document.createElement('a');
|
||||||
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
|
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
|
||||||
@ -80,10 +80,11 @@ var DateTimeShortcuts = {
|
|||||||
quickElement('h2', clock_box, gettext('Choose a time'));
|
quickElement('h2', clock_box, gettext('Choose a time'));
|
||||||
time_list = quickElement('ul', clock_box, '');
|
time_list = quickElement('ul', clock_box, '');
|
||||||
time_list.className = 'timelist';
|
time_list.className = 'timelist';
|
||||||
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + gettext('TIME_INPUT_FORMATS') + "'));");
|
time_format = get_format('TIME_INPUT_FORMATS')[0];
|
||||||
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') + "'));");
|
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
|
||||||
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') + "'));");
|
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 + "'));");
|
||||||
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') + "'));");
|
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 + "'));");
|
||||||
|
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 + "'));");
|
||||||
|
|
||||||
cancel_p = quickElement('p', clock_box, '');
|
cancel_p = quickElement('p', clock_box, '');
|
||||||
cancel_p.className = 'calendar-cancel';
|
cancel_p.className = 'calendar-cancel';
|
||||||
@ -236,7 +237,7 @@ var DateTimeShortcuts = {
|
|||||||
DateTimeShortcuts.calendars[num].drawNextMonth();
|
DateTimeShortcuts.calendars[num].drawNextMonth();
|
||||||
},
|
},
|
||||||
handleCalendarCallback: function(num) {
|
handleCalendarCallback: function(num) {
|
||||||
format = gettext('DATE_INPUT_FORMATS');
|
format = get_format('DATE_INPUT_FORMATS')[0];
|
||||||
// the format needs to be escaped a little
|
// the format needs to be escaped a little
|
||||||
format = format.replace('\\', '\\\\');
|
format = format.replace('\\', '\\\\');
|
||||||
format = format.replace('\r', '\\r');
|
format = format.replace('\r', '\\r');
|
||||||
@ -248,7 +249,7 @@ var DateTimeShortcuts = {
|
|||||||
handleCalendarQuickLink: function(num, offset) {
|
handleCalendarQuickLink: function(num, offset) {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
d.setDate(d.getDate() + offset)
|
d.setDate(d.getDate() + offset)
|
||||||
DateTimeShortcuts.calendarInputs[num].value = d.strftime(gettext('DATE_INPUT_FORMATS'));
|
DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
|
||||||
DateTimeShortcuts.dismissCalendar(num);
|
DateTimeShortcuts.dismissCalendar(num);
|
||||||
},
|
},
|
||||||
cancelEventPropagation: function(e) {
|
cancelEventPropagation: function(e) {
|
||||||
|
@ -25,7 +25,7 @@ function quickElement() {
|
|||||||
var CalendarNamespace = {
|
var CalendarNamespace = {
|
||||||
monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
|
monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
|
||||||
daysOfWeek: gettext('S M T W T F S').split(' '),
|
daysOfWeek: gettext('S M T W T F S').split(' '),
|
||||||
firstDayOfWeek: parseInt(gettext('FIRST_DAY_OF_WEEK')),
|
firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
|
||||||
isLeapYear: function(year) {
|
isLeapYear: function(year) {
|
||||||
return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
|
return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
|
||||||
},
|
},
|
||||||
@ -46,6 +46,12 @@ var CalendarNamespace = {
|
|||||||
return days;
|
return days;
|
||||||
},
|
},
|
||||||
draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
|
draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
|
||||||
|
var today = new Date();
|
||||||
|
var todayDay = today.getDate();
|
||||||
|
var todayMonth = today.getMonth()+1;
|
||||||
|
var todayYear = today.getFullYear();
|
||||||
|
var todayClass = '';
|
||||||
|
|
||||||
month = parseInt(month);
|
month = parseInt(month);
|
||||||
year = parseInt(year);
|
year = parseInt(year);
|
||||||
var calDiv = document.getElementById(div_id);
|
var calDiv = document.getElementById(div_id);
|
||||||
@ -76,7 +82,13 @@ var CalendarNamespace = {
|
|||||||
if (i%7 == 0 && currentDay != 1) {
|
if (i%7 == 0 && currentDay != 1) {
|
||||||
tableRow = quickElement('tr', tableBody);
|
tableRow = quickElement('tr', tableBody);
|
||||||
}
|
}
|
||||||
var cell = quickElement('td', tableRow, '');
|
if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) {
|
||||||
|
todayClass='today';
|
||||||
|
} else {
|
||||||
|
todayClass='';
|
||||||
|
}
|
||||||
|
var cell = quickElement('td', tableRow, '', 'class', todayClass);
|
||||||
|
|
||||||
quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
|
quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
|
||||||
currentDay++;
|
currentDay++;
|
||||||
}
|
}
|
||||||
|
10
django/contrib/comments/templates/comments/list.html
Normal file
10
django/contrib/comments/templates/comments/list.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<dl id="comments">
|
||||||
|
{% for comment in comment_list %}
|
||||||
|
<dt id="c{{ comment.id }}">
|
||||||
|
{{ comment.submit_date }} - {{ comment.name }}
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<p>{{ comment.comment }}</p>
|
||||||
|
</dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
@ -169,6 +169,46 @@ class RenderCommentFormNode(CommentFormNode):
|
|||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
class RenderCommentListNode(CommentListNode):
|
||||||
|
"""Render the comment list directly"""
|
||||||
|
|
||||||
|
#@classmethod
|
||||||
|
def handle_token(cls, parser, token):
|
||||||
|
"""Class method to parse render_comment_list and return a Node."""
|
||||||
|
tokens = token.contents.split()
|
||||||
|
if tokens[1] != 'for':
|
||||||
|
raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0])
|
||||||
|
|
||||||
|
# {% render_comment_list for obj %}
|
||||||
|
if len(tokens) == 3:
|
||||||
|
return cls(object_expr=parser.compile_filter(tokens[2]))
|
||||||
|
|
||||||
|
# {% render_comment_list for app.models pk %}
|
||||||
|
elif len(tokens) == 4:
|
||||||
|
return cls(
|
||||||
|
ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
|
||||||
|
object_pk_expr = parser.compile_filter(tokens[3])
|
||||||
|
)
|
||||||
|
handle_token = classmethod(handle_token)
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
ctype, object_pk = self.get_target_ctype_pk(context)
|
||||||
|
if object_pk:
|
||||||
|
template_search_list = [
|
||||||
|
"comments/%s/%s/list.html" % (ctype.app_label, ctype.model),
|
||||||
|
"comments/%s/list.html" % ctype.app_label,
|
||||||
|
"comments/list.html"
|
||||||
|
]
|
||||||
|
qs = self.get_query_set(context)
|
||||||
|
context.push()
|
||||||
|
liststr = render_to_string(template_search_list, {
|
||||||
|
"comment_list" : self.get_context_value_from_queryset(context, qs)
|
||||||
|
}, context)
|
||||||
|
context.pop()
|
||||||
|
return liststr
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
# We could just register each classmethod directly, but then we'd lose out on
|
# We could just register each classmethod directly, but then we'd lose out on
|
||||||
# the automagic docstrings-into-admin-docs tricks. So each node gets a cute
|
# the automagic docstrings-into-admin-docs tricks. So each node gets a cute
|
||||||
# wrapper function that just exists to hold the docstring.
|
# wrapper function that just exists to hold the docstring.
|
||||||
@ -216,6 +256,24 @@ def get_comment_list(parser, token):
|
|||||||
"""
|
"""
|
||||||
return CommentListNode.handle_token(parser, token)
|
return CommentListNode.handle_token(parser, token)
|
||||||
|
|
||||||
|
#@register.tag
|
||||||
|
def render_comment_list(parser, token):
|
||||||
|
"""
|
||||||
|
Render the comment list (as returned by ``{% get_comment_list %}``)
|
||||||
|
through the ``comments/list.html`` template
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
{% render_comment_list for [object] %}
|
||||||
|
{% render_comment_list for [app].[model] [object_id] %}
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
{% render_comment_list for event %}
|
||||||
|
|
||||||
|
"""
|
||||||
|
return RenderCommentListNode.handle_token(parser, token)
|
||||||
|
|
||||||
#@register.tag
|
#@register.tag
|
||||||
def get_comment_form(parser, token):
|
def get_comment_form(parser, token):
|
||||||
"""
|
"""
|
||||||
@ -248,12 +306,28 @@ def comment_form_target():
|
|||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
<form action="{% comment_form_target %}" method="POST">
|
<form action="{% comment_form_target %}" method="post">
|
||||||
"""
|
"""
|
||||||
return comments.get_form_target()
|
return comments.get_form_target()
|
||||||
|
|
||||||
|
#@register.simple_tag
|
||||||
|
def get_comment_permalink(comment, anchor_pattern=None):
|
||||||
|
"""
|
||||||
|
Get the permalink for a comment, optionally specifying the format of the
|
||||||
|
named anchor to be appended to the end of the URL.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
{{ get_comment_permalink comment "#c%(id)s-by-%(user_name)s" }}
|
||||||
|
"""
|
||||||
|
|
||||||
|
if anchor_pattern:
|
||||||
|
return comment.get_absolute_url(anchor_pattern)
|
||||||
|
return comment.get_absolute_url()
|
||||||
|
|
||||||
register.tag(get_comment_count)
|
register.tag(get_comment_count)
|
||||||
register.tag(get_comment_list)
|
register.tag(get_comment_list)
|
||||||
register.tag(get_comment_form)
|
register.tag(get_comment_form)
|
||||||
register.tag(render_comment_form)
|
register.tag(render_comment_form)
|
||||||
register.simple_tag(comment_form_target)
|
register.simple_tag(comment_form_target)
|
||||||
|
register.simple_tag(get_comment_permalink)
|
||||||
|
register.tag(render_comment_list)
|
||||||
|
@ -55,7 +55,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
|||||||
aliases.add(r)
|
aliases.add(r)
|
||||||
col_aliases.add(col[1])
|
col_aliases.add(col[1])
|
||||||
else:
|
else:
|
||||||
result.append(col.as_sql(qn=qn))
|
result.append(col.as_sql(qn, self.connection))
|
||||||
|
|
||||||
if hasattr(col, 'alias'):
|
if hasattr(col, 'alias'):
|
||||||
aliases.add(col.alias)
|
aliases.add(col.alias)
|
||||||
@ -70,7 +70,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
|||||||
max_name_length = self.connection.ops.max_name_length()
|
max_name_length = self.connection.ops.max_name_length()
|
||||||
result.extend([
|
result.extend([
|
||||||
'%s%s' % (
|
'%s%s' % (
|
||||||
self.get_extra_select_format(alias) % aggregate.as_sql(qn=qn, connection=self.connection),
|
self.get_extra_select_format(alias) % aggregate.as_sql(qn, self.connection),
|
||||||
alias is not None
|
alias is not None
|
||||||
and ' AS %s' % qn(truncate_name(alias, max_name_length))
|
and ' AS %s' % qn(truncate_name(alias, max_name_length))
|
||||||
or ''
|
or ''
|
||||||
|
@ -23,7 +23,7 @@ class USZipCodeField(RegexField):
|
|||||||
|
|
||||||
class USPhoneNumberField(CharField):
|
class USPhoneNumberField(CharField):
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid': u'Phone numbers must be in XXX-XXX-XXXX format.',
|
'invalid': _('Phone numbers must be in XXX-XXX-XXXX format.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
@ -85,7 +85,7 @@ class USStateField(Field):
|
|||||||
abbreviation for the given state.
|
abbreviation for the given state.
|
||||||
"""
|
"""
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid': u'Enter a U.S. state or territory.',
|
'invalid': _('Enter a U.S. state or territory.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
|
@ -28,16 +28,17 @@ def get_connection(backend=None, fail_silently=False, **kwds):
|
|||||||
"""
|
"""
|
||||||
path = backend or settings.EMAIL_BACKEND
|
path = backend or settings.EMAIL_BACKEND
|
||||||
try:
|
try:
|
||||||
mod = import_module(path)
|
mod_name, klass_name = path.rsplit('.', 1)
|
||||||
|
mod = import_module(mod_name)
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
raise ImproperlyConfigured(('Error importing email backend %s: "%s"'
|
raise ImproperlyConfigured(('Error importing email backend module %s: "%s"'
|
||||||
% (path, e)))
|
% (mod_name, e)))
|
||||||
try:
|
try:
|
||||||
cls = getattr(mod, 'EmailBackend')
|
klass = getattr(mod, klass_name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ImproperlyConfigured(('Module "%s" does not define a '
|
raise ImproperlyConfigured(('Module "%s" does not define a '
|
||||||
'"EmailBackend" class' % path))
|
'"%s" class' % (mod_name, klass_name)))
|
||||||
return cls(fail_silently=fail_silently, **kwds)
|
return klass(fail_silently=fail_silently, **kwds)
|
||||||
|
|
||||||
|
|
||||||
def send_mail(subject, message, from_email, recipient_list,
|
def send_mail(subject, message, from_email, recipient_list,
|
||||||
|
@ -15,6 +15,7 @@ import stat
|
|||||||
import sys
|
import sys
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
from django.core.management.color import color_style
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
from django.utils._os import safe_join
|
from django.utils._os import safe_join
|
||||||
|
|
||||||
@ -557,6 +558,7 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
|
|||||||
# We set self.path to avoid crashes in log_message() on unsupported
|
# We set self.path to avoid crashes in log_message() on unsupported
|
||||||
# requests (like "OPTIONS").
|
# requests (like "OPTIONS").
|
||||||
self.path = ''
|
self.path = ''
|
||||||
|
self.style = color_style()
|
||||||
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
|
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def get_environ(self):
|
def get_environ(self):
|
||||||
@ -608,7 +610,26 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
|
|||||||
# Don't bother logging requests for admin images or the favicon.
|
# Don't bother logging requests for admin images or the favicon.
|
||||||
if self.path.startswith(self.admin_media_prefix) or self.path == '/favicon.ico':
|
if self.path.startswith(self.admin_media_prefix) or self.path == '/favicon.ico':
|
||||||
return
|
return
|
||||||
sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format % args))
|
|
||||||
|
msg = "[%s] %s\n" % (self.log_date_time_string(), format % args)
|
||||||
|
|
||||||
|
# Utilize terminal colors, if available
|
||||||
|
if args[1][0] == '2':
|
||||||
|
# Put 2XX first, since it should be the common case
|
||||||
|
msg = self.style.HTTP_SUCCESS(msg)
|
||||||
|
elif args[1][0] == '1':
|
||||||
|
msg = self.style.HTTP_INFO(msg)
|
||||||
|
elif args[1][0] == '3':
|
||||||
|
msg = self.style.HTTP_REDIRECT(msg)
|
||||||
|
elif args[1] == '404':
|
||||||
|
msg = self.style.HTTP_NOT_FOUND(msg)
|
||||||
|
elif args[1][0] == '4':
|
||||||
|
msg = self.style.HTTP_BAD_REQUEST(msg)
|
||||||
|
else:
|
||||||
|
# Any 5XX, or any other response
|
||||||
|
msg = self.style.HTTP_SERVER_ERROR(msg)
|
||||||
|
|
||||||
|
sys.stderr.write(msg)
|
||||||
|
|
||||||
class AdminMediaHandler(object):
|
class AdminMediaHandler(object):
|
||||||
"""
|
"""
|
||||||
|
@ -43,7 +43,7 @@ def setup_test_environment():
|
|||||||
mail.SMTPConnection = locmem.EmailBackend
|
mail.SMTPConnection = locmem.EmailBackend
|
||||||
|
|
||||||
mail.original_email_backend = settings.EMAIL_BACKEND
|
mail.original_email_backend = settings.EMAIL_BACKEND
|
||||||
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem'
|
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
|
||||||
|
|
||||||
mail.outbox = []
|
mail.outbox = []
|
||||||
|
|
||||||
|
@ -78,6 +78,12 @@ PALETTES = {
|
|||||||
'SQL_COLTYPE': {},
|
'SQL_COLTYPE': {},
|
||||||
'SQL_KEYWORD': {},
|
'SQL_KEYWORD': {},
|
||||||
'SQL_TABLE': {},
|
'SQL_TABLE': {},
|
||||||
|
'HTTP_INFO': {},
|
||||||
|
'HTTP_SUCCESS': {},
|
||||||
|
'HTTP_REDIRECT': {},
|
||||||
|
'HTTP_BAD_REQUEST': {},
|
||||||
|
'HTTP_NOT_FOUND': {},
|
||||||
|
'HTTP_SERVER_ERROR': {},
|
||||||
},
|
},
|
||||||
DARK_PALETTE: {
|
DARK_PALETTE: {
|
||||||
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
|
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
|
||||||
@ -86,6 +92,12 @@ PALETTES = {
|
|||||||
'SQL_COLTYPE': { 'fg': 'green' },
|
'SQL_COLTYPE': { 'fg': 'green' },
|
||||||
'SQL_KEYWORD': { 'fg': 'yellow' },
|
'SQL_KEYWORD': { 'fg': 'yellow' },
|
||||||
'SQL_TABLE': { 'opts': ('bold',) },
|
'SQL_TABLE': { 'opts': ('bold',) },
|
||||||
|
'HTTP_INFO': { 'opts': ('bold',) },
|
||||||
|
'HTTP_SUCCESS': { },
|
||||||
|
'HTTP_REDIRECT': { 'fg': 'green' },
|
||||||
|
'HTTP_BAD_REQUEST': { 'fg': 'red', 'opts': ('bold',) },
|
||||||
|
'HTTP_NOT_FOUND': { 'fg': 'yellow' },
|
||||||
|
'HTTP_SERVER_ERROR': { 'fg': 'magenta', 'opts': ('bold',) },
|
||||||
},
|
},
|
||||||
LIGHT_PALETTE: {
|
LIGHT_PALETTE: {
|
||||||
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
|
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
|
||||||
@ -94,6 +106,12 @@ PALETTES = {
|
|||||||
'SQL_COLTYPE': { 'fg': 'green' },
|
'SQL_COLTYPE': { 'fg': 'green' },
|
||||||
'SQL_KEYWORD': { 'fg': 'blue' },
|
'SQL_KEYWORD': { 'fg': 'blue' },
|
||||||
'SQL_TABLE': { 'opts': ('bold',) },
|
'SQL_TABLE': { 'opts': ('bold',) },
|
||||||
|
'HTTP_INFO': { 'opts': ('bold',) },
|
||||||
|
'HTTP_SUCCESS': { },
|
||||||
|
'HTTP_REDIRECT': { 'fg': 'green', 'opts': ('bold',) },
|
||||||
|
'HTTP_BAD_REQUEST': { 'fg': 'red', 'opts': ('bold',) },
|
||||||
|
'HTTP_NOT_FOUND': { 'fg': 'red' },
|
||||||
|
'HTTP_SERVER_ERROR': { 'fg': 'magenta', 'opts': ('bold',) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEFAULT_PALETTE = DARK_PALETTE
|
DEFAULT_PALETTE = DARK_PALETTE
|
||||||
@ -117,7 +135,9 @@ def parse_color_setting(config_string):
|
|||||||
definition will augment the base palette definition.
|
definition will augment the base palette definition.
|
||||||
|
|
||||||
Valid roles:
|
Valid roles:
|
||||||
'error', 'notice', 'sql_field', 'sql_coltype', 'sql_keyword', 'sql_table'
|
'error', 'notice', 'sql_field', 'sql_coltype', 'sql_keyword', 'sql_table',
|
||||||
|
'http_info', 'http_success', 'http_redirect', 'http_bad_request',
|
||||||
|
'http_not_found', 'http_server_error'
|
||||||
|
|
||||||
Valid colors:
|
Valid colors:
|
||||||
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
||||||
|
@ -53,7 +53,14 @@ def get_formats():
|
|||||||
result[attr] = getattr(module, attr)
|
result[attr] = getattr(module, attr)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
return result
|
src = []
|
||||||
|
for k, v in result.items():
|
||||||
|
if isinstance(v, (basestring, int)):
|
||||||
|
src.append("formats['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(smart_unicode(v))))
|
||||||
|
elif isinstance(v, (tuple, list)):
|
||||||
|
v = [javascript_quote(smart_unicode(value)) for value in v]
|
||||||
|
src.append("formats['%s'] = ['%s'];\n" % (javascript_quote(k), "', '".join(v)))
|
||||||
|
return ''.join(src)
|
||||||
|
|
||||||
NullSource = """
|
NullSource = """
|
||||||
/* gettext identity library */
|
/* gettext identity library */
|
||||||
@ -90,6 +97,25 @@ function ngettext(singular, plural, count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gettext_noop(msgid) { return msgid; }
|
function gettext_noop(msgid) { return msgid; }
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
LibFormatHead = """
|
||||||
|
/* formatting library */
|
||||||
|
|
||||||
|
var formats = new Array();
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
LibFormatFoot = """
|
||||||
|
function get_format(format_type) {
|
||||||
|
var value = formats[format_type];
|
||||||
|
if (typeof(value) == 'undefined') {
|
||||||
|
return msgid;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SimplePlural = """
|
SimplePlural = """
|
||||||
@ -122,7 +148,8 @@ def null_javascript_catalog(request, domain=None, packages=None):
|
|||||||
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
|
||||||
versions that don't actually do anything.
|
versions that don't actually do anything.
|
||||||
"""
|
"""
|
||||||
return http.HttpResponse(NullSource + InterPolate, 'text/javascript')
|
src = [NullSource, InterPolate, LibFormatHead, get_formats(), LibFormatFoot]
|
||||||
|
return http.HttpResponse(''.join(src), 'text/javascript')
|
||||||
|
|
||||||
def javascript_catalog(request, domain='djangojs', packages=None):
|
def javascript_catalog(request, domain='djangojs', packages=None):
|
||||||
"""
|
"""
|
||||||
@ -210,15 +237,12 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||||||
csrc.sort()
|
csrc.sort()
|
||||||
for k, v in pdict.items():
|
for k, v in pdict.items():
|
||||||
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
||||||
for k, v in get_formats().items():
|
|
||||||
if isinstance(v, (basestring, int)):
|
|
||||||
src.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(smart_unicode(v))))
|
|
||||||
elif isinstance(v, (tuple, list)):
|
|
||||||
v = [javascript_quote(smart_unicode(value)) for value in v]
|
|
||||||
src.append("catalog['%s'] = ['%s'];\n" % (javascript_quote(k), "', '".join(v)))
|
|
||||||
src.extend(csrc)
|
src.extend(csrc)
|
||||||
src.append(LibFoot)
|
src.append(LibFoot)
|
||||||
src.append(InterPolate)
|
src.append(InterPolate)
|
||||||
|
src.append(LibFormatHead)
|
||||||
|
src.append(get_formats())
|
||||||
|
src.append(LibFormatFoot)
|
||||||
src = ''.join(src)
|
src = ''.join(src)
|
||||||
return http.HttpResponse(src, 'text/javascript')
|
return http.HttpResponse(src, 'text/javascript')
|
||||||
|
|
||||||
|
208
docs/ref/contrib/comments/example.txt
Normal file
208
docs/ref/contrib/comments/example.txt
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
.. _ref-contrib-comments-example:
|
||||||
|
|
||||||
|
.. highlightlang:: html+django
|
||||||
|
|
||||||
|
===========================================
|
||||||
|
Example of using the in-built comments app
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Follow the first three steps of the quick start guide in the
|
||||||
|
:ref:`documentation <ref-contrib-comments-index>`.
|
||||||
|
|
||||||
|
Now suppose, you have an app (``blog``) with a model (``Post``)
|
||||||
|
to which you want to attach comments. Let us also suppose that
|
||||||
|
you have a template called ``blog_detail.html`` where you want
|
||||||
|
to display the comments list and comment form.
|
||||||
|
|
||||||
|
Template
|
||||||
|
========
|
||||||
|
|
||||||
|
First, we should load the ``comment`` template tags in the
|
||||||
|
``blog_detail.html`` so that we can use it's functionality. So
|
||||||
|
just like all other custom template tag libraries::
|
||||||
|
|
||||||
|
{% load comments %}
|
||||||
|
|
||||||
|
Next, let us add the number of comments attached to the particular
|
||||||
|
model instance of ``Post``. For this we assume that a context
|
||||||
|
variable ``object_pk`` is present which gives the ``id`` of the
|
||||||
|
instance of ``Post``.
|
||||||
|
|
||||||
|
The usage of the :ttag:`get_comment_count` tag is like below::
|
||||||
|
|
||||||
|
{% get_comment_count for blog.post object_pk as comment_count %}
|
||||||
|
<p>{{ comment_count }} comments have been posted.</p>
|
||||||
|
|
||||||
|
If you have the instance (say ``entry``) of the model (``Post``)
|
||||||
|
available in the context, then you can refer to it directly::
|
||||||
|
|
||||||
|
{% get_comment_count for entry as comment_count %}
|
||||||
|
<p>{{ comment_count }} comments have been posted.</p>
|
||||||
|
|
||||||
|
Next, we can use the :ttag:`render_comment_list` tag, to render all comments
|
||||||
|
to the given instance (``entry``) by using the ``comments/list.html`` template.
|
||||||
|
|
||||||
|
{% render_comment_list for entry %}
|
||||||
|
|
||||||
|
Django will will look for the ``list.html`` under the following directories
|
||||||
|
(for our example)::
|
||||||
|
|
||||||
|
comments/blog/post/list.html
|
||||||
|
comments/blog/list.html
|
||||||
|
comments/list.html
|
||||||
|
|
||||||
|
To get a list of comments, we make use of the :ttag:`get_comment_list` tag.
|
||||||
|
This tag's usage is very similar to the :ttag:`get_comment_count` tag. We
|
||||||
|
need to remember that the :ttag:`get_comment_list` returns a list of comments
|
||||||
|
and hence we will have to iterate through them to display them::
|
||||||
|
|
||||||
|
{% get_comment_list for blog.post object_pk as comment_list %}
|
||||||
|
{% for comment in comment_list %}
|
||||||
|
<p>Posted by: {{ comment.user_name }} on {{ comment.submit_date }}</p>
|
||||||
|
...
|
||||||
|
<p>Comment: {{ comment.comment }}</p>
|
||||||
|
...
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Finally, we display the comment form, enabling users to enter their
|
||||||
|
comments. There are two ways of doing so. The first is when you want to
|
||||||
|
display the comments template available under your ``comments/form.html``.
|
||||||
|
The other method gives you a chance to customize the form.
|
||||||
|
|
||||||
|
The first method makes use of the :ttag:`render_comment_form` tag. It's usage
|
||||||
|
too is similar to the other three tags we have discussed above::
|
||||||
|
|
||||||
|
{% render_comment_form for entry %}
|
||||||
|
|
||||||
|
It looks for the ``form.html`` under the following directories
|
||||||
|
(for our example)::
|
||||||
|
|
||||||
|
comments/blog/post/form.html
|
||||||
|
comments/blog/form.html
|
||||||
|
comments/form.html
|
||||||
|
|
||||||
|
Since we customize the form in the second method, we make use of another
|
||||||
|
tag called :ttag:`comment_form_target`. This tag on rendering gives the URL
|
||||||
|
where the comment form is posted. Without any :ref:`customization
|
||||||
|
<ref-contrib-comments-custom>`, :ttag:`comment_form_target` evaluates to
|
||||||
|
``/comments/post/``. We use this tag in the form's ``action`` attribute.
|
||||||
|
|
||||||
|
The :ttag:`get_comment_form` tag renders a ``form`` for a model instance by
|
||||||
|
creating a context variable. One can iterate over the ``form`` object to
|
||||||
|
get individual fields. This gives you fine-grain control over the form::
|
||||||
|
|
||||||
|
{% for field in form %}
|
||||||
|
{% ifequal field.name "comment" %}
|
||||||
|
<!-- Customize the "comment" field, say, make CSS changes -->
|
||||||
|
...
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
But let's look at a simple example::
|
||||||
|
|
||||||
|
{% get_comment_form for entry as form %}
|
||||||
|
<!-- A context variable called form is created with the necessary hidden
|
||||||
|
fields, timestamps and security hashes -->
|
||||||
|
<table>
|
||||||
|
<form action="{% comment_form_target %}" method="post">
|
||||||
|
{{ form }}
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td><input type="submit" name="preview" class="submit-post" value="Preview"></td>
|
||||||
|
</tr>
|
||||||
|
</form>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Flagging
|
||||||
|
========
|
||||||
|
|
||||||
|
If you want your users to be able to flag comments (say for profanity), you
|
||||||
|
can just direct them (by placing a link in your comment list) to ``/flag/{{
|
||||||
|
comment.id }}/``. Similarly, a user with requisite permissions (``"Can
|
||||||
|
moderate comments"``) can approve and delete comments. This can also be
|
||||||
|
done through the ``admin`` as you'll see later. You might also want to
|
||||||
|
customize the following templates:
|
||||||
|
|
||||||
|
* ``flag.html``
|
||||||
|
* ``flagged.html``
|
||||||
|
* ``approve.html``
|
||||||
|
* ``approved.html``
|
||||||
|
* ``delete.html``
|
||||||
|
* ``deleted.html``
|
||||||
|
|
||||||
|
found under the directory structure we saw for ``form.html``.
|
||||||
|
|
||||||
|
Feeds
|
||||||
|
=====
|
||||||
|
|
||||||
|
Suppose you want to export a :ref:`feed <ref-contrib-syndication>` of the
|
||||||
|
latest comments, you can use the in-built :class:`LatestCommentFeed`. Just
|
||||||
|
enable it in your project's ``urls.py``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from django.contrib.comments.feeds import LatestCommentFeed
|
||||||
|
|
||||||
|
feeds = {
|
||||||
|
'latest': LatestCommentFeed,
|
||||||
|
}
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
# ...
|
||||||
|
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
|
||||||
|
{'feed_dict': feeds}),
|
||||||
|
# ...
|
||||||
|
)
|
||||||
|
|
||||||
|
Now you should have the latest comment feeds being served off ``/feeds/latest/``.
|
||||||
|
|
||||||
|
Moderation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Now that we have the comments framework working, we might want to have some
|
||||||
|
moderation setup to administer the comments. The comments framework comes
|
||||||
|
in-built with :ref:`generic comment moderation
|
||||||
|
<ref-contrib-comments-moderation>`. The comment moderation has the following
|
||||||
|
features (all of which or only certain can be enabled):
|
||||||
|
|
||||||
|
* Enable comments for a particular model instance.
|
||||||
|
* Close comments after a particular (user-defined) number of days.
|
||||||
|
* Email new comments to the site-staff.
|
||||||
|
|
||||||
|
To enable comment moderation, we subclass the :class:`CommentModerator` and
|
||||||
|
register it with the moderation features we want. Let us suppose we want to
|
||||||
|
close comments after 7 days of posting and also send out an email to the
|
||||||
|
site staff. In ``blog/models.py``, we register a comment moderator in the
|
||||||
|
following way:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.contrib.comments.moderation import CommentModerator, moderator
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class Post(models.Model):
|
||||||
|
title = models.CharField(max_length = 255)
|
||||||
|
content = models.TextField()
|
||||||
|
posted_date = models.DateTimeField()
|
||||||
|
|
||||||
|
class PostModerator(CommentModerator):
|
||||||
|
email_notification = True
|
||||||
|
auto_close_field = 'posted_date'
|
||||||
|
# Close the comments after 7 days.
|
||||||
|
close_after = 7
|
||||||
|
|
||||||
|
moderator.register(Post, PostModerator)
|
||||||
|
|
||||||
|
The generic comment moderation also has the facility to remove comments.
|
||||||
|
These comments can then be moderated by any user who has access to the
|
||||||
|
``admin`` site and the ``Can moderate comments`` permission (can be set
|
||||||
|
under the ``Users`` page in the ``admin``).
|
||||||
|
|
||||||
|
The moderator can ``Flag``, ``Approve`` or ``Remove`` comments using the
|
||||||
|
``Action`` drop-down in the ``admin`` under the ``Comments`` page.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Only a super-user will be able to delete comments from the database.
|
||||||
|
``Remove Comments`` only sets the ``is_public`` attribute to
|
||||||
|
``False``.
|
@ -84,11 +84,34 @@ different ways you can specify which object to attach to:
|
|||||||
In the above, ``blog.entry`` is the app label and (lower-cased) model
|
In the above, ``blog.entry`` is the app label and (lower-cased) model
|
||||||
name of the model class.
|
name of the model class.
|
||||||
|
|
||||||
.. templatetag:: get_comment_list
|
|
||||||
|
|
||||||
Displaying comments
|
Displaying comments
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
To display a list of comments, you can use the template tags
|
||||||
|
:ttag:`render_comment_list` or :ttag:`get_comment_list`.
|
||||||
|
|
||||||
|
.. templatetag:: render_comment_list
|
||||||
|
|
||||||
|
Quickly rendering a comment list
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The easiest way to display a list of comments for some object is by using
|
||||||
|
:ttag:`render_comment_list`::
|
||||||
|
|
||||||
|
{% render_comment_list for [object] %}
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
{% render_comment_list for event %}
|
||||||
|
|
||||||
|
This will render comments using a template named ``comments/list.html``, a
|
||||||
|
default version of which is included with Django.
|
||||||
|
|
||||||
|
.. templatetag:: get_comment_list
|
||||||
|
|
||||||
|
Rendering a custom comment list
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
To get the list of comments for some object, use :ttag:`get_comment_list`::
|
To get the list of comments for some object, use :ttag:`get_comment_list`::
|
||||||
|
|
||||||
{% get_comment_list for [object] as [varname] %}
|
{% get_comment_list for [object] as [varname] %}
|
||||||
@ -104,6 +127,44 @@ This returns a list of :class:`~django.contrib.comments.models.Comment` objects;
|
|||||||
see :ref:`the comment model documentation <ref-contrib-comments-models>` for
|
see :ref:`the comment model documentation <ref-contrib-comments-models>` for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
.. templatetag:: get_comment_permalink
|
||||||
|
|
||||||
|
Linking to comments
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
To provide a permalink to a specific comment, use :ttag:`get_comment_permalink`::
|
||||||
|
|
||||||
|
{% get_comment_permalink comment_obj [format_string] %}
|
||||||
|
|
||||||
|
By default, the named anchor that will be appended to the URL will be the letter
|
||||||
|
'c' followed by the comment id, for example 'c82'. You may specify a custom
|
||||||
|
format string if you wish to override this behavior::
|
||||||
|
|
||||||
|
{% get_comment_permalink comment "#c%(id)s-by-%(user_name)s"%}
|
||||||
|
|
||||||
|
The format string is a standard python format string. Valid mapping keys
|
||||||
|
include any attributes of the comment object.
|
||||||
|
|
||||||
|
Regardless of whether you specify a custom anchor pattern, you must supply a
|
||||||
|
matching named anchor at a suitable place in your template.
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
{% for comment in comment_list %}
|
||||||
|
<a name="c{{ comment.id }}"></a>
|
||||||
|
<a href="{% get_comment_permalink comment %}">
|
||||||
|
permalink for comment #{{ forloop.counter }}
|
||||||
|
</a>
|
||||||
|
...
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
There's a known bug in Safari/Webkit which causes the named anchor to be
|
||||||
|
forgotten following a redirect. The practical impact for comments is that
|
||||||
|
the Safari/webkit browsers will arrive at the correct page but will not
|
||||||
|
scroll to the named anchor.
|
||||||
|
|
||||||
.. templatetag:: get_comment_count
|
.. templatetag:: get_comment_count
|
||||||
|
|
||||||
Counting comments
|
Counting comments
|
||||||
@ -157,7 +218,7 @@ you can use in the template::
|
|||||||
A complete form might look like::
|
A complete form might look like::
|
||||||
|
|
||||||
{% get_comment_form for event as form %}
|
{% get_comment_form for event as form %}
|
||||||
<form action="{% comment_form_target %}" method="POST">
|
<form action="{% comment_form_target %}" method="post">
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
@ -178,7 +239,7 @@ You may have noticed that the above example uses another template tag --
|
|||||||
form. This will always return the correct URL that comments should be posted to;
|
form. This will always return the correct URL that comments should be posted to;
|
||||||
you'll always want to use it like above::
|
you'll always want to use it like above::
|
||||||
|
|
||||||
<form action="{% comment_form_target %}" method="POST">
|
<form action="{% comment_form_target %}" method="post">
|
||||||
|
|
||||||
Redirecting after the comment post
|
Redirecting after the comment post
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -238,3 +299,4 @@ More information
|
|||||||
custom
|
custom
|
||||||
forms
|
forms
|
||||||
moderation
|
moderation
|
||||||
|
example
|
||||||
|
@ -49,7 +49,7 @@ To enable CSRF protection for your views, follow these steps:
|
|||||||
2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside
|
2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside
|
||||||
the ``<form>`` element if the form is for an internal URL, e.g.::
|
the ``<form>`` element if the form is for an internal URL, e.g.::
|
||||||
|
|
||||||
<form action="" method="POST">{% csrf_token %}
|
<form action="" method="post">{% csrf_token %}
|
||||||
|
|
||||||
This should not be done for POST forms that target external URLs, since
|
This should not be done for POST forms that target external URLs, since
|
||||||
that would cause the CSRF token to be leaked, leading to a vulnerability.
|
that would cause the CSRF token to be leaked, leading to a vulnerability.
|
||||||
|
@ -1026,6 +1026,12 @@ number of roles in which color is used:
|
|||||||
* ``sql_coltype`` - The type of a model field in SQL.
|
* ``sql_coltype`` - The type of a model field in SQL.
|
||||||
* ``sql_keyword`` - A SQL keyword.
|
* ``sql_keyword`` - A SQL keyword.
|
||||||
* ``sql_table`` - The name of a model in SQL.
|
* ``sql_table`` - The name of a model in SQL.
|
||||||
|
* ``http_info`` - A 1XX HTTP Informational server response.
|
||||||
|
* ``http_success`` - A 2XX HTTP Success server response.
|
||||||
|
* ``http_redirect`` - A 3XX HTTP Redirect server response.
|
||||||
|
* ``http_not_found`` - A 404 HTTP Not Found server response.
|
||||||
|
* ``http_bad_request`` - A 4XX HTTP Bad Request server response other than 404.
|
||||||
|
* ``http_server_error`` - A 5XX HTTP Server Error response.
|
||||||
|
|
||||||
Each of these roles can be assigned a specific foreground and
|
Each of these roles can be assigned a specific foreground and
|
||||||
background color, from the following list:
|
background color, from the following list:
|
||||||
|
@ -286,7 +286,7 @@ connection with which to send e-mail, you can explicitly request an
|
|||||||
SMTP connection::
|
SMTP connection::
|
||||||
|
|
||||||
from django.core.mail import get_connection
|
from django.core.mail import get_connection
|
||||||
connection = get_connection('django.core.mail.backends.smtp')
|
connection = get_connection('django.core.mail.backends.smtp.EmailBackend')
|
||||||
messages = get_notification_email()
|
messages = get_notification_email()
|
||||||
connection.send_messages(messages)
|
connection.send_messages(messages)
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ If your call to construct an instance of ``SMTPConnection`` required
|
|||||||
additional arguments, those arguments can be passed to the
|
additional arguments, those arguments can be passed to the
|
||||||
:meth:`~django.core.mail.get_connection()` call::
|
:meth:`~django.core.mail.get_connection()` call::
|
||||||
|
|
||||||
connection = get_connection('django.core.mail.backends.smtp', hostname='localhost', port=1234)
|
connection = get_connection('django.core.mail.backends.smtp.EmailBackend', hostname='localhost', port=1234)
|
||||||
|
|
||||||
User Messages API
|
User Messages API
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -408,7 +408,7 @@ settings file.
|
|||||||
The SMTP backend is the default configuration inherited by Django. If you
|
The SMTP backend is the default configuration inherited by Django. If you
|
||||||
want to specify it explicitly, put the following in your settings::
|
want to specify it explicitly, put the following in your settings::
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
|
||||||
.. admonition:: SMTPConnection objects
|
.. admonition:: SMTPConnection objects
|
||||||
|
|
||||||
@ -433,7 +433,7 @@ providing the ``stream`` keyword argument when constructing the connection.
|
|||||||
|
|
||||||
To specify this backend, put the following in your settings::
|
To specify this backend, put the following in your settings::
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.console'
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||||
|
|
||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development.
|
convenience that can be used during development.
|
||||||
@ -451,7 +451,7 @@ the ``file_path`` keyword when creating a connection with
|
|||||||
|
|
||||||
To specify this backend, put the following in your settings::
|
To specify this backend, put the following in your settings::
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.filebased'
|
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
|
||||||
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location
|
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location
|
||||||
|
|
||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
@ -470,7 +470,7 @@ be send.
|
|||||||
|
|
||||||
To specify this backend, put the following in your settings::
|
To specify this backend, put the following in your settings::
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.locmem'
|
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
|
||||||
|
|
||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development and testing.
|
convenience that can be used during development and testing.
|
||||||
@ -483,7 +483,7 @@ Dummy backend
|
|||||||
As the name suggests the dummy backend does nothing with your messages. To
|
As the name suggests the dummy backend does nothing with your messages. To
|
||||||
specify this backend, put the following in your settings::
|
specify this backend, put the following in your settings::
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.dummy'
|
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
|
||||||
|
|
||||||
This backend is not intended for use in production -- it is provided as a
|
This backend is not intended for use in production -- it is provided as a
|
||||||
convenience that can be used during development.
|
convenience that can be used during development.
|
||||||
@ -495,7 +495,7 @@ Defining a custom e-mail backend
|
|||||||
|
|
||||||
If you need to change how e-mails are send you can write your own e-mail
|
If you need to change how e-mails are send you can write your own e-mail
|
||||||
backend. The ``EMAIL_BACKEND`` setting in your settings file is then the
|
backend. The ``EMAIL_BACKEND`` setting in your settings file is then the
|
||||||
Python import path for your backend.
|
Python import path for your backend class.
|
||||||
|
|
||||||
Custom e-mail backends should subclass ``BaseEmailBackend`` that is located in
|
Custom e-mail backends should subclass ``BaseEmailBackend`` that is located in
|
||||||
the ``django.core.mail.backends.base`` module. A custom e-mail backend must
|
the ``django.core.mail.backends.base`` module. A custom e-mail backend must
|
||||||
@ -503,7 +503,7 @@ implement the ``send_messages(email_messages)`` method. This method receives a
|
|||||||
list of :class:`~django.core.mail.EmailMessage` instances and returns the
|
list of :class:`~django.core.mail.EmailMessage` instances and returns the
|
||||||
number of successfully delivered messages. If your backend has any concept of
|
number of successfully delivered messages. If your backend has any concept of
|
||||||
a persistent session or connection, you should also implement the ``open()``
|
a persistent session or connection, you should also implement the ``open()``
|
||||||
and ``close()`` methods. Refer to ``SMTPEmailBackend`` for a reference
|
and ``close()`` methods. Refer to ``smtp.EmailBackend`` for a reference
|
||||||
implementation.
|
implementation.
|
||||||
|
|
||||||
.. _topics-sending-multiple-emails:
|
.. _topics-sending-multiple-emails:
|
||||||
|
@ -355,7 +355,7 @@ The ``manage_articles.html`` template might look like this:
|
|||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
{{ formset.management_form }}
|
{{ formset.management_form }}
|
||||||
<table>
|
<table>
|
||||||
{% for form in formset.forms %}
|
{% for form in formset.forms %}
|
||||||
@ -369,7 +369,7 @@ with the management form:
|
|||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
<table>
|
<table>
|
||||||
{{ formset }}
|
{{ formset }}
|
||||||
</table>
|
</table>
|
||||||
|
@ -172,7 +172,7 @@ Forms are designed to work with the Django template language. In the above
|
|||||||
example, we passed our ``ContactForm`` instance to the template using the
|
example, we passed our ``ContactForm`` instance to the template using the
|
||||||
context variable ``form``. Here's a simple example template::
|
context variable ``form``. Here's a simple example template::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
<input type="submit" value="Submit" />
|
<input type="submit" value="Submit" />
|
||||||
</form>
|
</form>
|
||||||
@ -183,7 +183,7 @@ The form only outputs its own fields; it is up to you to provide the surrounding
|
|||||||
``form.as_p`` will output the form with each form field and accompanying label
|
``form.as_p`` will output the form with each form field and accompanying label
|
||||||
wrapped in a paragraph. Here's the output for our example template::
|
wrapped in a paragraph. Here's the output for our example template::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
<p><label for="id_subject">Subject:</label>
|
<p><label for="id_subject">Subject:</label>
|
||||||
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
|
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
|
||||||
<p><label for="id_message">Message:</label>
|
<p><label for="id_message">Message:</label>
|
||||||
@ -211,7 +211,7 @@ If the default generated HTML is not to your taste, you can completely customize
|
|||||||
the way a form is presented using the Django template language. Extending the
|
the way a form is presented using the Django template language. Extending the
|
||||||
above example::
|
above example::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
<div class="fieldWrapper">
|
<div class="fieldWrapper">
|
||||||
{{ form.subject.errors }}
|
{{ form.subject.errors }}
|
||||||
<label for="id_subject">E-mail subject:</label>
|
<label for="id_subject">E-mail subject:</label>
|
||||||
@ -263,7 +263,7 @@ If you're using the same HTML for each of your form fields, you can reduce
|
|||||||
duplicate code by looping through each field in turn using a ``{% for %}``
|
duplicate code by looping through each field in turn using a ``{% for %}``
|
||||||
loop::
|
loop::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="fieldWrapper">
|
<div class="fieldWrapper">
|
||||||
{{ field.errors }}
|
{{ field.errors }}
|
||||||
@ -322,7 +322,7 @@ and visible fields independently: ``hidden_fields()`` and
|
|||||||
``visible_fields()``. Here's a modification of an earlier example that uses
|
``visible_fields()``. Here's a modification of an earlier example that uses
|
||||||
these two methods::
|
these two methods::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
{% for field in form.visible_fields %}
|
{% for field in form.visible_fields %}
|
||||||
<div class="fieldWrapper">
|
<div class="fieldWrapper">
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ If your site uses the same rendering logic for forms in multiple places, you
|
|||||||
can reduce duplication by saving the form's loop in a standalone template and
|
can reduce duplication by saving the form's loop in a standalone template and
|
||||||
using the :ttag:`include` tag to reuse it in other templates::
|
using the :ttag:`include` tag to reuse it in other templates::
|
||||||
|
|
||||||
<form action="/contact/" method="POST">
|
<form action="/contact/" method="post">
|
||||||
{% include "form_snippet.html" %}
|
{% include "form_snippet.html" %}
|
||||||
<p><input type="submit" value="Send message" /></p>
|
<p><input type="submit" value="Send message" /></p>
|
||||||
</form>
|
</form>
|
||||||
@ -373,7 +373,7 @@ using the :ttag:`include` tag to reuse it in other templates::
|
|||||||
If the form object passed to a template has a different name within the
|
If the form object passed to a template has a different name within the
|
||||||
context, you can alias it using the :ttag:`with` tag::
|
context, you can alias it using the :ttag:`with` tag::
|
||||||
|
|
||||||
<form action="/comments/add/" method="POST">
|
<form action="/comments/add/" method="post">
|
||||||
{% with comment_form as form %}
|
{% with comment_form as form %}
|
||||||
{% include "form_snippet.html" %}
|
{% include "form_snippet.html" %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
@ -705,14 +705,14 @@ There are three ways to render a formset in a Django template.
|
|||||||
|
|
||||||
First, you can let the formset do most of the work::
|
First, you can let the formset do most of the work::
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
{{ formset }}
|
{{ formset }}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
Second, you can manually render the formset, but let the form deal with
|
Second, you can manually render the formset, but let the form deal with
|
||||||
itself::
|
itself::
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
{{ formset.management_form }}
|
{{ formset.management_form }}
|
||||||
{% for form in formset.forms %}
|
{% for form in formset.forms %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
@ -725,7 +725,7 @@ form as shown above. See the :ref:`management form documentation
|
|||||||
|
|
||||||
Third, you can manually render each field::
|
Third, you can manually render each field::
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
{{ formset.management_form }}
|
{{ formset.management_form }}
|
||||||
{% for form in formset.forms %}
|
{% for form in formset.forms %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
@ -738,7 +738,7 @@ If you opt to use this third method and you don't iterate over the fields with
|
|||||||
a ``{% for %}`` loop, you'll need to render the primary key field. For example,
|
a ``{% for %}`` loop, you'll need to render the primary key field. For example,
|
||||||
if you were rendering the ``name`` and ``age`` fields of a model::
|
if you were rendering the ``name`` and ``age`` fields of a model::
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="post" action="">
|
||||||
{{ formset.management_form }}
|
{{ formset.management_form }}
|
||||||
{% for form in formset.forms %}
|
{% for form in formset.forms %}
|
||||||
{{ form.id }}
|
{{ form.id }}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from django.contrib.comments.forms import CommentForm
|
from django.contrib.comments.forms import CommentForm
|
||||||
from django.contrib.comments.models import Comment
|
from django.contrib.comments.models import Comment
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.template import Template, Context
|
from django.template import Template, Context
|
||||||
from regressiontests.comment_tests.models import Article, Author
|
from regressiontests.comment_tests.models import Article, Author
|
||||||
from regressiontests.comment_tests.tests import CommentTestCase
|
from regressiontests.comment_tests.tests import CommentTestCase
|
||||||
@ -63,3 +64,34 @@ class CommentTemplateTagTests(CommentTestCase):
|
|||||||
|
|
||||||
def testGetCommentListFromObject(self):
|
def testGetCommentListFromObject(self):
|
||||||
self.testGetCommentList("{% get_comment_list for a as cl %}")
|
self.testGetCommentList("{% get_comment_list for a as cl %}")
|
||||||
|
|
||||||
|
def testGetCommentPermalink(self):
|
||||||
|
self.createSomeComments()
|
||||||
|
t = "{% load comments %}{% get_comment_list for comment_tests.author author.id as cl %}"
|
||||||
|
t += "{% get_comment_permalink cl.0 %}"
|
||||||
|
ct = ContentType.objects.get_for_model(Author)
|
||||||
|
author = Author.objects.get(pk=1)
|
||||||
|
ctx, out = self.render(t, author=author)
|
||||||
|
self.assertEqual(out, "/cr/%s/%s/#c2" % (ct.id, author.id))
|
||||||
|
|
||||||
|
def testGetCommentPermalinkFormatted(self):
|
||||||
|
self.createSomeComments()
|
||||||
|
t = "{% load comments %}{% get_comment_list for comment_tests.author author.id as cl %}"
|
||||||
|
t += "{% get_comment_permalink cl.0 '#c%(id)s-by-%(user_name)s' %}"
|
||||||
|
ct = ContentType.objects.get_for_model(Author)
|
||||||
|
author = Author.objects.get(pk=1)
|
||||||
|
ctx, out = self.render(t, author=author)
|
||||||
|
self.assertEqual(out, "/cr/%s/%s/#c2-by-Joe Somebody" % (ct.id, author.id))
|
||||||
|
|
||||||
|
def testRenderCommentList(self, tag=None):
|
||||||
|
t = "{% load comments %}" + (tag or "{% render_comment_list for comment_tests.article a.id %}")
|
||||||
|
ctx, out = self.render(t, a=Article.objects.get(pk=1))
|
||||||
|
self.assert_(out.strip().startswith("<dl id=\"comments\">"))
|
||||||
|
self.assert_(out.strip().endswith("</dl>"))
|
||||||
|
|
||||||
|
def testRenderCommentListFromLiteral(self):
|
||||||
|
self.testRenderCommentList("{% render_comment_list for comment_tests.article 1 %}")
|
||||||
|
|
||||||
|
def testRenderCommentListFromObject(self):
|
||||||
|
self.testRenderCommentList("{% render_comment_list for a %}")
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from django.template import RequestContext, Template
|
|||||||
# Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
|
# Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
|
||||||
def post_form_response():
|
def post_form_response():
|
||||||
resp = HttpResponse(content="""
|
resp = HttpResponse(content="""
|
||||||
<html><body><form method="POST"><input type="text" /></form></body></html>
|
<html><body><form method="post"><input type="text" /></form></body></html>
|
||||||
""", mimetype="text/html")
|
""", mimetype="text/html")
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ Content
|
|||||||
|
|
||||||
# Test that the console backend can be pointed at an arbitrary stream
|
# Test that the console backend can be pointed at an arbitrary stream
|
||||||
>>> s = StringIO()
|
>>> s = StringIO()
|
||||||
>>> connection = mail.get_connection('django.core.mail.backends.console', stream=s)
|
>>> connection = mail.get_connection('django.core.mail.backends.console.EmailBackend', stream=s)
|
||||||
>>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
|
>>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
|
||||||
1
|
1
|
||||||
>>> print s.getvalue()
|
>>> print s.getvalue()
|
||||||
@ -270,7 +270,7 @@ Content
|
|||||||
True
|
True
|
||||||
|
|
||||||
# Test custom backend defined in this suite.
|
# Test custom backend defined in this suite.
|
||||||
>>> conn = mail.get_connection('regressiontests.mail.custombackend')
|
>>> conn = mail.get_connection('regressiontests.mail.custombackend.EmailBackend')
|
||||||
>>> hasattr(conn, 'test_outbox')
|
>>> hasattr(conn, 'test_outbox')
|
||||||
True
|
True
|
||||||
>>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
|
>>> email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'})
|
||||||
@ -280,23 +280,23 @@ True
|
|||||||
1
|
1
|
||||||
|
|
||||||
# Test backend argument of mail.get_connection()
|
# Test backend argument of mail.get_connection()
|
||||||
>>> isinstance(mail.get_connection('django.core.mail.backends.smtp'), smtp.EmailBackend)
|
>>> isinstance(mail.get_connection('django.core.mail.backends.smtp.EmailBackend'), smtp.EmailBackend)
|
||||||
True
|
True
|
||||||
>>> isinstance(mail.get_connection('django.core.mail.backends.locmem'), locmem.EmailBackend)
|
>>> isinstance(mail.get_connection('django.core.mail.backends.locmem.EmailBackend'), locmem.EmailBackend)
|
||||||
True
|
True
|
||||||
>>> isinstance(mail.get_connection('django.core.mail.backends.dummy'), dummy.EmailBackend)
|
>>> isinstance(mail.get_connection('django.core.mail.backends.dummy.EmailBackend'), dummy.EmailBackend)
|
||||||
True
|
True
|
||||||
>>> isinstance(mail.get_connection('django.core.mail.backends.console'), console.EmailBackend)
|
>>> isinstance(mail.get_connection('django.core.mail.backends.console.EmailBackend'), console.EmailBackend)
|
||||||
True
|
True
|
||||||
>>> tmp_dir = tempfile.mkdtemp()
|
>>> tmp_dir = tempfile.mkdtemp()
|
||||||
>>> isinstance(mail.get_connection('django.core.mail.backends.filebased', file_path=tmp_dir), filebased.EmailBackend)
|
>>> isinstance(mail.get_connection('django.core.mail.backends.filebased.EmailBackend', file_path=tmp_dir), filebased.EmailBackend)
|
||||||
True
|
True
|
||||||
>>> shutil.rmtree(tmp_dir)
|
>>> shutil.rmtree(tmp_dir)
|
||||||
>>> isinstance(mail.get_connection(), locmem.EmailBackend)
|
>>> isinstance(mail.get_connection(), locmem.EmailBackend)
|
||||||
True
|
True
|
||||||
|
|
||||||
# Test connection argument of send_mail() et al
|
# Test connection argument of send_mail() et al
|
||||||
>>> connection = mail.get_connection('django.core.mail.backends.console')
|
>>> connection = mail.get_connection('django.core.mail.backends.console.EmailBackend')
|
||||||
>>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
|
>>> send_mail('Subject', 'Content', 'from@example.com', ['to@example.com'], connection=connection)
|
||||||
Content-Type: text/plain; charset="utf-8"
|
Content-Type: text/plain; charset="utf-8"
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user