上传及下载 #2

Open
innov wants to merge 39 commits from stable/0.91.x into stable/1.0.x
18 changed files with 334 additions and 168 deletions

60
README
View File

@ -1,37 +1,49 @@
Django is a high-level Python Web framework that encourages rapid development Django is a high-level Python Web framework that encourages rapid
and clean, pragmatic design. development and clean, pragmatic design.
All documentation is in the "docs" directory and online at
http://www.djangoproject.com/documentation/. If you're just getting started,
here's how we recommend you read the docs:
* First, read docs/install.txt for instructions on installing Django. About this version
==================
* Next, work through the tutorials in order (docs/tutorial01.txt, This is the Django 0.91 "bugfixes" branch, which is intended to
docs/tutorial02.txt, etc.). provide bugfix and patch support for users of Django 0.91 who have not
been able to migrate to a more recent version. No new features will be
added in this branch, and it is maintained solely as a means of
providing support to legacy Django installations.
* If you want to set up an actual deployment server, read docs/modpython.txt If you're completely new to Django we highly recommend that you use
for instructions on running Django under mod_python. either the latest stable release or a Subversion checkout from
Django's trunk; Django is always evolving, and the latest and greatest
features are only available to users of newer versions of the
framework.
* The rest of the documentation is of the reference-manual variety.
Read it -- and the FAQ -- as you run into problems.
Docs are updated rigorously. If you find any problems in the docs, or think they More information
should be clarified in any way, please take 30 seconds to fill out a ticket ================
here:
http://code.djangoproject.com/newticket The complete history of bugs fixed in this branch can be viewed online
at http://code.djangoproject.com/log/django/branches/0.91-bugfixes.
To get more help: We also recommend that users of this branch subscribe to the
"django-announce" mailing list, a low-traffic, announcements-only list
which will send messages whenever an important (i.e.,
security-related) bug is fixed. You can subscribe to the list via
Google Groups at http://groups.google.com/group/django-announce.
* Join the #django channel on irc.freenode.net. Lots of helpful people The documentation for this version of Django has been frozen, and is
hang out there. Read the archives at http://loglibrary.com/179 . available online at http://www.djangoproject.com/documentation/0_91/.
* Join the django-users mailing list, or read the archives, at
http://groups-beta.google.com/group/django-users.
To contribute to Django: Submitting bugs
===============
* Check out http://www.djangoproject.com/community/ for information If you run into a bug in Django 0.91, please search the Django ticket
about getting involved. database to see if the issue has already been reported; if not, please
head over to http://code.djangoproject.com/newticket and file a new
ticket with as much information about the bug as you can provide.
If you're running into a bug which has been reported but not fixed,
feel free to update the ticket with any additional information you
have, and to assign it to 'ubernostrum' (AKA James Bennett, the
maintainer of this branch).

View File

@ -1 +1 @@
VERSION = (0, 9, 1, 'SVN') VERSION = (0, 91, 3, 'SVN')

View File

@ -20,7 +20,14 @@ def compile_messages():
if f.endswith('.po'): if f.endswith('.po'):
sys.stderr.write('processing file %s in %s\n' % (f, dirpath)) sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
pf = os.path.splitext(os.path.join(dirpath, f))[0] pf = os.path.splitext(os.path.join(dirpath, f))[0]
cmd = 'msgfmt -o "%s.mo" "%s.po"' % (pf, pf) # Store the names of the .mo and .po files in an environment
# variable, rather than doing a string replacement into the
# command, so that we can take advantage of shell quoting, to
# quote any malicious characters/escaping.
# See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
os.environ['djangocompilemo'] = pf + '.mo'
os.environ['djangocompilepo'] = pf + '.po'
cmd = 'msgfmt -o "$djangocompilemo" "$djangocompilepo"'
os.system(cmd) os.system(cmd)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,8 +1,35 @@
// Handles related-objects functionality: lookup link for raw_id_admin=True // Handles related-objects functionality: lookup link for raw_id_admin=True
// and Add Another links. // and Add Another links.
function html_unescape(text) {
// Unescape a string that was escaped using django.utils.html.escape.
text = text.replace(/&lt;/g, '<');
text = text.replace(/&gt;/g, '>');
text = text.replace(/&quot;/g, '"');
text = text.replace(/&#39;/g, "'");
text = text.replace(/&amp;/g, '&');
return text;
}
// IE doesn't accept periods or dashes in the window name, but the element IDs
// we use to generate popup window names may contain them, therefore we map them
// to allowed characters in a reversible way so that we can locate the correct
// element when the popup window is dismissed.
function id_to_windowname(text) {
text = text.replace(/\./g, '__dot__');
text = text.replace(/\-/g, '__dash__');
return text;
}
function windowname_to_id(text) {
text = text.replace(/__dot__/g, '.');
text = text.replace(/__dash__/g, '-');
return text;
}
function showRelatedObjectLookupPopup(triggeringLink) { function showRelatedObjectLookupPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^lookup_/, ''); var name = triggeringLink.id.replace(/^lookup_/, '');
name = id_to_windowname(name);
var href; var href;
if (triggeringLink.href.search(/\?/) >= 0) { if (triggeringLink.href.search(/\?/) >= 0) {
href = triggeringLink.href + '&pop=1'; href = triggeringLink.href + '&pop=1';
@ -15,25 +42,36 @@ function showRelatedObjectLookupPopup(triggeringLink) {
} }
function dismissRelatedLookupPopup(win, chosenId) { function dismissRelatedLookupPopup(win, chosenId) {
var elem = document.getElementById(win.name); var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem.className.indexOf('vRawIdAdminField') != -1 && elem.value) { if (elem.className.indexOf('vRawIdAdminField') != -1 && elem.value) {
elem.value += ',' + chosenId; elem.value += ',' + chosenId;
} else { } else {
document.getElementById(win.name).value = chosenId; document.getElementById(name).value = chosenId;
} }
win.close(); win.close();
} }
function showAddAnotherPopup(triggeringLink) { function showAddAnotherPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^add_/, ''); var name = triggeringLink.id.replace(/^add_/, '');
name = name.replace(/\./g, '___'); name = id_to_windowname(name);
var win = window.open(triggeringLink.href + '?_popup=1', name, 'height=500,width=800,resizable=yes,scrollbars=yes'); href = triggeringLink.href
if (href.indexOf('?') == -1) {
href += '?_popup=1';
} else {
href += '&_popup=1';
}
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus(); win.focus();
return false; return false;
} }
function dismissAddAnotherPopup(win, newId, newRepr) { function dismissAddAnotherPopup(win, newId, newRepr) {
var name = win.name.replace(/___/g, '.'); // newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = windowname_to_id(win.name);
var elem = document.getElementById(name); var elem = document.getElementById(name);
if (elem) { if (elem) {
if (elem.nodeName == 'SELECT') { if (elem.nodeName == 'SELECT') {

View File

@ -17,7 +17,6 @@
<p class="aligned"> <p class="aligned">
<label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
<input type="hidden" name="this_is_the_login_form" value="1" /> <input type="hidden" name="this_is_the_login_form" value="1" />
<input type="hidden" name="post_data" value="{{ post_data }}" />{% comment %} <span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %}
</p> </p>
<div class="aligned "> <div class="aligned ">

View File

@ -2,43 +2,21 @@ from django.core.extensions import DjangoContext, render_to_response
from django.conf.settings import SECRET_KEY from django.conf.settings import SECRET_KEY
from django.models.auth import users from django.models.auth import users
from django.utils import httpwrappers from django.utils import httpwrappers
from django.utils.html import escape
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
import base64, datetime, md5 import base64, datetime
import cPickle as pickle
ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form' LOGIN_FORM_KEY = 'this_is_the_login_form'
def _display_login_form(request, error_message=''): def _display_login_form(request, error_message=''):
request.session.set_test_cookie() 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', { return render_to_response('admin/login', {
'title': _('Log in'), 'title': _('Log in'),
'app_path': request.path, 'app_path': escape(request.path),
'post_data': post_data,
'error_message': error_message 'error_message': error_message
}, context_instance=DjangoContext(request)) }, 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): def staff_member_required(view_func):
""" """
Decorator for views that checks that the user is logged in and is a staff Decorator for views that checks that the user is logged in and is a staff
@ -47,10 +25,6 @@ def staff_member_required(view_func):
def _checklogin(request, *args, **kwargs): def _checklogin(request, *args, **kwargs):
if not request.user.is_anonymous() and request.user.is_staff: if not request.user.is_anonymous() and request.user.is_staff:
# The user is valid. Continue to the admin page. # The user is valid. Continue to the admin page.
if request.POST.has_key('post_data'):
# User must have re-authenticated through a different window
# or tab.
request.POST = _decode_post_data(request.POST['post_data'])
return view_func(request, *args, **kwargs) 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'." assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.middleware.sessions.SessionMiddleware'."
@ -58,7 +32,7 @@ def staff_member_required(view_func):
# If this isn't already the login page, display it. # If this isn't already the login page, display it.
if not request.POST.has_key(LOGIN_FORM_KEY): if not request.POST.has_key(LOGIN_FORM_KEY):
if request.POST: if request.POST:
message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") message = _("Please log in again, because your session has expired.")
else: else:
message = "" message = ""
return _display_login_form(request, message) return _display_login_form(request, message)
@ -90,15 +64,6 @@ def staff_member_required(view_func):
request.session[users.SESSION_KEY] = user.id request.session[users.SESSION_KEY] = user.id
user.last_login = datetime.datetime.now() user.last_login = datetime.datetime.now()
user.save() user.save()
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) return httpwrappers.HttpResponseRedirect(request.path)
else: else:
return _display_login_form(request, ERROR_MESSAGE) return _display_login_form(request, ERROR_MESSAGE)

View File

@ -98,7 +98,15 @@ class ChangeList(object):
if not request.user.has_perm(app_label + '.' + self.opts.get_change_permission()): if not request.user.has_perm(app_label + '.' + self.opts.get_change_permission()):
raise PermissionDenied raise PermissionDenied
self.lookup_mod, self.lookup_opts = self.mod, self.opts lookup_mod, lookup_opts = self.mod, self.opts
if self.opts.one_to_one_field:
lookup_mod = self.opts.one_to_one_field.rel.to.get_model_module()
lookup_opts = lookup_mod.Klass._meta
# If lookup_opts doesn't have admin set, give it the default meta.Admin().
if not lookup_opts.admin:
lookup_opts.admin = meta.Admin()
self.lookup_mod, self.lookup_opts = lookup_mod, lookup_opts
def get_search_parameters(self, request): def get_search_parameters(self, request):
# Get search parameters from the query string. # Get search parameters from the query string.

View File

@ -43,6 +43,6 @@ class LatestCommentsFeed(LatestFreeCommentsFeed):
kwargs = LatestFreeCommentsFeed._get_lookup_kwargs(self) kwargs = LatestFreeCommentsFeed._get_lookup_kwargs(self)
kwargs['is_removed__exact'] = False kwargs['is_removed__exact'] = False
if settings.COMMENTS_BANNED_USERS_GROUP: if settings.COMMENTS_BANNED_USERS_GROUP:
kwargs['where'] = ['user_id NOT IN (SELECT user_id FROM auth_users_group WHERE group_id = %s)'] kwargs['where'] = ['user_id NOT IN (SELECT user_id FROM auth_users_groups WHERE group_id = %s)']
kwargs['params'] = [COMMENTS_BANNED_USERS_GROUP] kwargs['params'] = [settings.COMMENTS_BANNED_USERS_GROUP]
return kwargs return kwargs

View File

@ -107,7 +107,7 @@ class PublicCommentManipulator(AuthenticationForm):
# send the comment to the managers. # send the comment to the managers.
if self.user_cache.get_comments_comment_count() <= COMMENTS_FIRST_FEW: if self.user_cache.get_comments_comment_count() <= COMMENTS_FIRST_FEW:
message = ngettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s', message = ngettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s',
'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s') % \ 'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s', COMMENTS_FIRST_FEW) % \
{'count': COMMENTS_FIRST_FEW, 'text': c.get_as_text()} {'count': COMMENTS_FIRST_FEW, 'text': c.get_as_text()}
mail_managers("Comment posted by rookie user", message) mail_managers("Comment posted by rookie user", message)
if COMMENTS_SKETCHY_USERS_GROUP and COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]: if COMMENTS_SKETCHY_USERS_GROUP and COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]:

View File

@ -16,13 +16,54 @@ except ImportError:
# Import copy of _thread_local.py from python 2.4 # Import copy of _thread_local.py from python 2.4
from django.utils._threading_local import local from django.utils._threading_local import local
def smart_basestring(s, charset):
if isinstance(s, unicode):
return s.encode(charset)
return s
class UnicodeCursorWrapper(object):
"""
A thin wrapper around psycopg cursors that allows them to accept Unicode
strings as params.
This is necessary because psycopg doesn't apply any DB quoting to
parameters that are Unicode strings. If a param is Unicode, this will
convert it to a bytestring using DEFAULT_CHARSET before passing it to
psycopg.
"""
def __init__(self, cursor, charset):
self.cursor = cursor
self.charset = charset
def execute(self, sql, params=()):
try:
params = dict([(k, smart_basestring(v, self.charset)) for (k, v) in params.items()])
except AttributeError:
params = [smart_basestring(p, self.charset) for p in params]
return self.cursor.execute(sql, params)
def executemany(self, sql, param_list):
try:
new_param_list = [dict([(k, smart_basestring(v, self.charset)) for (k, v) in params.items()])
for params in param_list]
except AttributeError:
new_param_list = [tuple([smart_basestring(p, self.charset) for p in params])
for params in param_list]
return self.cursor.executemany(sql, new_param_list)
def __getattr__(self, attr):
if self.__dict__.has_key(attr):
return self.__dict__[attr]
else:
return getattr(self.cursor, attr)
class DatabaseWrapper(local): class DatabaseWrapper(local):
def __init__(self): def __init__(self):
self.connection = None self.connection = None
self.queries = [] self.queries = []
def cursor(self): def cursor(self):
from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG, TIME_ZONE from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG, DEFAULT_CHARSET, TIME_ZONE
if self.connection is None: if self.connection is None:
if DATABASE_NAME == '': if DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -40,6 +81,7 @@ class DatabaseWrapper(local):
self.connection.set_isolation_level(1) # make transactions transparent to all cursors self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor() cursor = self.connection.cursor()
cursor.execute("SET TIME ZONE %s", [TIME_ZONE]) cursor.execute("SET TIME ZONE %s", [TIME_ZONE])
cursor = UnicodeCursorWrapper(cursor, DEFAULT_CHARSET)
if DEBUG: if DEBUG:
return base.CursorDebugWrapper(cursor, self) return base.CursorDebugWrapper(cursor, self)
return cursor return cursor

View File

@ -325,7 +325,8 @@ class FormField:
class TextField(FormField): class TextField(FormField):
input_type = "text" input_type = "text"
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[], member_name=None): def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
self.length, self.maxlength = length, maxlength self.length, self.maxlength = length, maxlength
self.is_required = is_required self.is_required = is_required
@ -362,7 +363,8 @@ class PasswordField(TextField):
input_type = "password" input_type = "password"
class LargeTextField(TextField): class LargeTextField(TextField):
def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None): def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
self.rows, self.cols, self.is_required = rows, cols, is_required self.rows, self.cols, self.is_required = rows, cols, is_required
self.validator_list = validator_list[:] self.validator_list = validator_list[:]
@ -380,7 +382,8 @@ class LargeTextField(TextField):
self.field_name, self.rows, self.cols, escape(data)) self.field_name, self.rows, self.cols, escape(data))
class HiddenField(FormField): class HiddenField(FormField):
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required self.field_name, self.is_required = field_name, is_required
self.validator_list = validator_list[:] self.validator_list = validator_list[:]
@ -410,7 +413,8 @@ class CheckboxField(FormField):
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class SelectField(FormField): class SelectField(FormField):
def __init__(self, field_name, choices=[], size=1, is_required=False, validator_list=[], member_name=None): def __init__(self, field_name, choices=[], size=1, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters # choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.size, self.is_required = choices, size, is_required self.choices, self.size, self.is_required = choices, size, is_required
@ -446,7 +450,8 @@ class NullSelectField(SelectField):
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class RadioSelectField(FormField): class RadioSelectField(FormField):
def __init__(self, field_name, choices=[], ul_class='', is_required=False, validator_list=[], member_name=None): def __init__(self, field_name, choices=[], ul_class='', is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters # choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.is_required = choices, is_required self.choices, self.is_required = choices, is_required
@ -510,7 +515,8 @@ class RadioSelectField(FormField):
class NullBooleanField(SelectField): class NullBooleanField(SelectField):
"This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None" "This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None"
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')], SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')],
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -563,7 +569,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
back into the single list that validators, renderers and save() expect. back into the single list that validators, renderers and save() expect.
""" """
requires_data_list = True requires_data_list = True
def __init__(self, field_name, choices=[], validator_list=[]): def __init__(self, field_name, choices=[], validator_list=None):
if validator_list is None: validator_list = []
SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list) SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list)
def prepare(self, new_data): def prepare(self, new_data):
@ -594,7 +601,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
#################### ####################
class FileUploadField(FormField): class FileUploadField(FormField):
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required self.field_name, self.is_required = field_name, is_required
self.validator_list = [self.isNonEmptyFile] + validator_list self.validator_list = [self.isNonEmptyFile] + validator_list
@ -629,7 +637,8 @@ class ImageUploadField(FileUploadField):
#################### ####################
class IntegerField(TextField): class IntegerField(TextField):
def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[], member_name=None): def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = []
validator_list = [self.isInteger] + validator_list validator_list = [self.isInteger] + validator_list
if member_name is not None: if member_name is not None:
self.member_name = member_name self.member_name = member_name
@ -648,7 +657,8 @@ class IntegerField(TextField):
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class SmallIntegerField(IntegerField): class SmallIntegerField(IntegerField):
def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=[]): def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isSmallInteger] + validator_list validator_list = [self.isSmallInteger] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@ -657,7 +667,8 @@ class SmallIntegerField(IntegerField):
raise validators.CriticalValidationError, _("Enter a whole number between -32,768 and 32,767.") raise validators.CriticalValidationError, _("Enter a whole number between -32,768 and 32,767.")
class PositiveIntegerField(IntegerField): class PositiveIntegerField(IntegerField):
def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[]): def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isPositive] + validator_list validator_list = [self.isPositive] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@ -666,7 +677,8 @@ class PositiveIntegerField(IntegerField):
raise validators.CriticalValidationError, _("Enter a positive number.") raise validators.CriticalValidationError, _("Enter a positive number.")
class PositiveSmallIntegerField(IntegerField): class PositiveSmallIntegerField(IntegerField):
def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=[]): def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isPositiveSmall] + validator_list validator_list = [self.isPositiveSmall] + validator_list
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
@ -675,7 +687,8 @@ class PositiveSmallIntegerField(IntegerField):
raise validators.CriticalValidationError, _("Enter a whole number between 0 and 32,767.") raise validators.CriticalValidationError, _("Enter a whole number between 0 and 32,767.")
class FloatField(TextField): class FloatField(TextField):
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=[]): def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.max_digits, self.decimal_places = max_digits, decimal_places self.max_digits, self.decimal_places = max_digits, decimal_places
validator_list = [self.isValidFloat] + validator_list validator_list = [self.isValidFloat] + validator_list
TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list) TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list)
@ -700,7 +713,8 @@ class FloatField(TextField):
class DatetimeField(TextField): class DatetimeField(TextField):
"""A FormField that automatically converts its data to a datetime.datetime object. """A FormField that automatically converts its data to a datetime.datetime object.
The data should be in the format YYYY-MM-DD HH:MM:SS.""" The data should be in the format YYYY-MM-DD HH:MM:SS."""
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[]): def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.field_name = field_name self.field_name = field_name
self.length, self.maxlength = length, maxlength self.length, self.maxlength = length, maxlength
self.is_required = is_required self.is_required = is_required
@ -723,7 +737,8 @@ class DatetimeField(TextField):
class DateField(TextField): class DateField(TextField):
"""A FormField that automatically converts its data to a datetime.date object. """A FormField that automatically converts its data to a datetime.date object.
The data should be in the format YYYY-MM-DD.""" The data should be in the format YYYY-MM-DD."""
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidDate] + validator_list validator_list = [self.isValidDate] + validator_list
TextField.__init__(self, field_name, length=10, maxlength=10, TextField.__init__(self, field_name, length=10, maxlength=10,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -747,7 +762,8 @@ class DateField(TextField):
class TimeField(TextField): class TimeField(TextField):
"""A FormField that automatically converts its data to a datetime.time object. """A FormField that automatically converts its data to a datetime.time object.
The data should be in the format HH:MM:SS or HH:MM:SS.mmmmmm.""" The data should be in the format HH:MM:SS or HH:MM:SS.mmmmmm."""
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidTime] + validator_list validator_list = [self.isValidTime] + validator_list
TextField.__init__(self, field_name, length=8, maxlength=8, TextField.__init__(self, field_name, length=8, maxlength=8,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -781,7 +797,8 @@ class TimeField(TextField):
class EmailField(TextField): class EmailField(TextField):
"A convenience FormField for validating e-mail addresses" "A convenience FormField for validating e-mail addresses"
def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=[]): def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidEmail] + validator_list validator_list = [self.isValidEmail] + validator_list
TextField.__init__(self, field_name, length, maxlength=maxlength, TextField.__init__(self, field_name, length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -794,7 +811,8 @@ class EmailField(TextField):
class URLField(TextField): class URLField(TextField):
"A convenience FormField for validating URLs" "A convenience FormField for validating URLs"
def __init__(self, field_name, length=50, is_required=False, validator_list=[]): def __init__(self, field_name, length=50, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidURL] + validator_list validator_list = [self.isValidURL] + validator_list
TextField.__init__(self, field_name, length=length, maxlength=200, TextField.__init__(self, field_name, length=length, maxlength=200,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -806,7 +824,8 @@ class URLField(TextField):
raise validators.CriticalValidationError, e.messages raise validators.CriticalValidationError, e.messages
class IPAddressField(TextField): class IPAddressField(TextField):
def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=[]): def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidIPAddress] + validator_list validator_list = [self.isValidIPAddress] + validator_list
TextField.__init__(self, field_name, length=length, maxlength=maxlength, TextField.__init__(self, field_name, length=length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -827,7 +846,8 @@ class IPAddressField(TextField):
class FilePathField(SelectField): class FilePathField(SelectField):
"A SelectField whose choices are the files in a given directory." "A SelectField whose choices are the files in a given directory."
def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[]): def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
import os import os
if match is not None: if match is not None:
import re import re
@ -850,7 +870,8 @@ class FilePathField(SelectField):
class PhoneNumberField(TextField): class PhoneNumberField(TextField):
"A convenience FormField for validating phone numbers (e.g. '630-555-1234')" "A convenience FormField for validating phone numbers (e.g. '630-555-1234')"
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidPhone] + validator_list validator_list = [self.isValidPhone] + validator_list
TextField.__init__(self, field_name, length=12, maxlength=12, TextField.__init__(self, field_name, length=12, maxlength=12,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -863,7 +884,8 @@ class PhoneNumberField(TextField):
class USStateField(TextField): class USStateField(TextField):
"A convenience FormField for validating U.S. states (e.g. 'IL')" "A convenience FormField for validating U.S. states (e.g. 'IL')"
def __init__(self, field_name, is_required=False, validator_list=[]): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isValidUSState] + validator_list validator_list = [self.isValidUSState] + validator_list
TextField.__init__(self, field_name, length=2, maxlength=2, TextField.__init__(self, field_name, length=2, maxlength=2,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
@ -875,15 +897,13 @@ class USStateField(TextField):
raise validators.CriticalValidationError, e.messages raise validators.CriticalValidationError, e.messages
def html2python(data): def html2python(data):
if data:
return data.upper() # Should always be stored in upper case return data.upper() # Should always be stored in upper case
else:
return None
html2python = staticmethod(html2python) html2python = staticmethod(html2python)
class CommaSeparatedIntegerField(TextField): class CommaSeparatedIntegerField(TextField):
"A convenience FormField for validating comma-separated integer fields" "A convenience FormField for validating comma-separated integer fields"
def __init__(self, field_name, maxlength=None, is_required=False, validator_list=[]): def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [self.isCommaSeparatedIntegerList] + validator_list validator_list = [self.isCommaSeparatedIntegerList] + validator_list
TextField.__init__(self, field_name, length=20, maxlength=maxlength, TextField.__init__(self, field_name, length=20, maxlength=maxlength,
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)

View File

@ -55,14 +55,14 @@ class BaseHandler:
# Reset query list per request. # Reset query list per request.
db.db.queries = [] db.db.queries = []
resolver = urlresolvers.RegexURLResolver(r'^/', ROOT_URLCONF)
try:
# Apply request middleware # Apply request middleware
for middleware_method in self._request_middleware: for middleware_method in self._request_middleware:
response = middleware_method(request) response = middleware_method(request)
if response: if response:
return response return response
resolver = urlresolvers.RegexURLResolver(r'^/', ROOT_URLCONF)
try:
callback, callback_args, callback_kwargs = resolver.resolve(path) callback, callback_args, callback_kwargs = resolver.resolve(path)
# Apply view middleware # Apply view middleware

View File

@ -13,9 +13,30 @@ class ModPythonRequest(httpwrappers.HttpRequest):
self.path = req.uri self.path = req.uri
def __repr__(self): def __repr__(self):
# Since this is called as part of error handling, we need to be very
# robust against potentially malformed input.
try:
get = pformat(self.GET)
except:
get = '<could not parse>'
try:
post = pformat(self.POST)
except:
post = '<could not parse>'
try:
cookies = pformat(self.COOKIES)
except:
cookies = '<could not parse>'
try:
meta = pformat(self.META)
except:
meta = '<could not parse>'
try:
user = self.user
except:
user = '<could not parse>'
return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s,\nuser:%s>' % \ return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s,\nuser:%s>' % \
(self.path, pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), (self.path, get, post, cookies, meta, user)
pformat(self.META), pformat(self.user))
def get_full_path(self): def get_full_path(self):
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '') return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
@ -141,12 +162,11 @@ class ModPythonHandler(BaseHandler):
try: try:
request = ModPythonRequest(req) request = ModPythonRequest(req)
response = self.get_response(req.uri, request) response = self.get_response(req.uri, request)
finally:
db.db.close()
# Apply response middleware # Apply response middleware
for middleware_method in self._response_middleware: for middleware_method in self._response_middleware:
response = middleware_method(request, response) response = middleware_method(request, response)
finally:
db.db.close()
# Convert our custom HttpResponse object back into the mod_python req. # Convert our custom HttpResponse object back into the mod_python req.
populate_apache_request(response, req) populate_apache_request(response, req)

View File

@ -55,9 +55,30 @@ class WSGIRequest(httpwrappers.HttpRequest):
def __repr__(self): def __repr__(self):
from pprint import pformat from pprint import pformat
return '<DjangoRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ # Since this is called as part of error handling, we need to be very
(pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), # robust against potentially malformed input.
pformat(self.META)) try:
get = pformat(self.GET)
except:
get = '<could not parse>'
try:
post = pformat(self.POST)
except:
post = '<could not parse>'
try:
cookies = pformat(self.COOKIES)
except:
cookies = '<could not parse>'
try:
meta = pformat(self.META)
except:
meta = '<could not parse>'
try:
user = self.user
except:
user = '<could not parse>'
return '<DjangoRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s,\nuser:%s>' % \
(self.path, get, post, cookies, meta, user)
def get_full_path(self): def get_full_path(self):
return '%s%s' % (self.path, self.environ['QUERY_STRING'] and ('?' + self.environ['QUERY_STRING']) or '') return '%s%s' % (self.path, self.environ['QUERY_STRING'] and ('?' + self.environ['QUERY_STRING']) or '')
@ -157,12 +178,11 @@ class WSGIHandler(BaseHandler):
try: try:
request = WSGIRequest(environ) request = WSGIRequest(environ)
response = self.get_response(request.path, request) response = self.get_response(request.path, request)
finally:
db.db.close()
# Apply response middleware # Apply response middleware
for middleware_method in self._response_middleware: for middleware_method in self._response_middleware:
response = middleware_method(request, response) response = middleware_method(request, response)
finally:
db.db.close()
try: try:
status_text = STATUS_CODE_TEXT[response.status_code] status_text = STATUS_CODE_TEXT[response.status_code]

View File

@ -151,7 +151,7 @@ class BadKeywordArguments(Exception):
class BoundRelatedObject(object): class BoundRelatedObject(object):
def __init__(self, related_object, field_mapping, original): def __init__(self, related_object, field_mapping, original):
self.relation = related_object self.relation = related_object
self.field_mappings = field_mapping[related_object.opts.module_name] self.field_mappings = field_mapping[related_object.name]
def template_name(self): def template_name(self):
raise NotImplementedError raise NotImplementedError
@ -165,7 +165,7 @@ class RelatedObject(object):
self.opts = opts self.opts = opts
self.field = field self.field = field
self.edit_inline = field.rel.edit_inline self.edit_inline = field.rel.edit_inline
self.name = opts.module_name self.name = '%s_%s' % (opts.app_label, opts.module_name)
self.var_name = opts.object_name.lower() self.var_name = opts.object_name.lower()
def flatten_data(self, follow, obj=None): def flatten_data(self, follow, obj=None):
@ -1734,7 +1734,7 @@ def manipulator_init(opts, add, change, self, obj_key=None, follow=None):
# Sanity check -- Make sure the "parent" object exists. # Sanity check -- Make sure the "parent" object exists.
# For example, make sure the Place exists for the Restaurant. # For example, make sure the Place exists for the Restaurant.
# Let the ObjectDoesNotExist exception propagate up. # Let the ObjectDoesNotExist exception propagate up.
lookup_kwargs = opts.one_to_one_field.rel.limit_choices_to lookup_kwargs = opts.one_to_one_field.rel.limit_choices_to.copy()
lookup_kwargs['%s__exact' % opts.one_to_one_field.rel.field_name] = obj_key lookup_kwargs['%s__exact' % opts.one_to_one_field.rel.field_name] = obj_key
_ = opts.one_to_one_field.rel.to.get_model_module().get_object(**lookup_kwargs) _ = opts.one_to_one_field.rel.to.get_model_module().get_object(**lookup_kwargs)
params = dict([(f.attname, f.get_default()) for f in opts.fields]) params = dict([(f.attname, f.get_default()) for f in opts.fields])

View File

@ -327,18 +327,26 @@ def get_digit(value, arg):
# DATES # # DATES #
################### ###################
EMPTY_DATE_VALUES = (None, '')
def date(value, arg=DATE_FORMAT): def date(value, arg=DATE_FORMAT):
"Formats a date according to the given format" "Formats a date according to the given format"
if value in EMPTY_DATE_VALUES:
return ''
from django.utils.dateformat import format from django.utils.dateformat import format
return format(value, arg) return format(value, arg)
def time(value, arg=TIME_FORMAT): def time(value, arg=TIME_FORMAT):
"Formats a time according to the given format" "Formats a time according to the given format"
if value in EMPTY_DATE_VALUES:
return ''
from django.utils.dateformat import time_format from django.utils.dateformat import time_format
return time_format(value, arg) return time_format(value, arg)
def timesince(value): def timesince(value):
'Formats a date as the time since that date (i.e. "4 days, 6 hours")' 'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
if value in EMPTY_DATE_VALUES:
return ''
from django.utils.timesince import timesince from django.utils.timesince import timesince
return timesince(value) return timesince(value)

View File

@ -1,6 +1,9 @@
"translation helper functions" "translation helper functions"
import os, re, sys import locale
import os
import re
import sys
import gettext as gettext_module import gettext as gettext_module
from cStringIO import StringIO from cStringIO import StringIO
from django.utils.functional import lazy from django.utils.functional import lazy
@ -25,14 +28,24 @@ _active = {}
# The default translation is based on the settings file. # The default translation is based on the settings file.
_default = None _default = None
# This is a cache for accept-header to translation object mappings to prevent # This is a cache for normalised accept-header languages to prevent multiple
# the accept parser to run multiple times for one user. # file lookups when checking the same locale on repeated requests.
_accepted = {} _accepted = {}
def to_locale(language): # Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9.
accept_language_re = re.compile(r'''
([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*) # "en", "en-au", "x-y-z", "*"
(?:;q=(0(?:\.\d{,3})?|1(?:.0{,3})?))? # Optional "q=1.00", "q=0.8"
(?:\s*,\s*|$) # Multiple accepts per header.
''', re.VERBOSE)
def to_locale(language, to_lower=False):
"Turns a language name (en-us) into a locale name (en_US)." "Turns a language name (en-us) into a locale name (en_US)."
p = language.find('-') p = language.find('-')
if p >= 0: if p >= 0:
if to_lower:
return language[:p].lower()+'_'+language[p+1:].lower()
else:
return language[:p].lower()+'_'+language[p+1:].upper() return language[:p].lower()+'_'+language[p+1:].upper()
else: else:
return language.lower() return language.lower()
@ -297,45 +310,39 @@ def get_language_from_request(request):
if lang_code in supported and lang_code is not None and check_for_language(lang_code): if lang_code in supported and lang_code is not None and check_for_language(lang_code):
return lang_code return lang_code
lang_code = request.COOKIES.get('django_language', None) lang_code = request.COOKIES.get('django_language')
if lang_code in supported and lang_code is not None and check_for_language(lang_code): if lang_code and lang_code in supported and check_for_language(lang_code):
return lang_code return lang_code
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None) accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
if accept is not None: for lang, unused in parse_accept_lang_header(accept):
if lang == '*':
break
t = _accepted.get(accept, None) # We have a very restricted form for our language files (no encoding
if t is not None: # specifier, since they all must be UTF-8 and only one possible
return t # language each time. So we avoid the overhead of gettext.find() and
# look up the MO file manually.
def _parsed(el): normalized = locale.locale_alias.get(to_locale(lang, True))
p = el.find(';q=') if not normalized:
if p >= 0: continue
lang = el[:p].strip()
order = int(float(el[p+3:].strip())*100)
else:
lang = el
order = 100
p = lang.find('-')
if p >= 0:
mainlang = lang[:p]
else:
mainlang = lang
return (lang, mainlang, order)
langs = [_parsed(el) for el in accept.split(',')] # Remove the default encoding from locale_alias
langs.sort(lambda a,b: -1*cmp(a[2], b[2])) normalized = normalized.split('.')[0]
for lang, mainlang, order in langs: if normalized in _accepted:
if lang in supported or mainlang in supported: # We've seen this locale before and have an MO file for it, so no
langfile = gettext_module.find('django', globalpath, [to_locale(lang)]) # need to check again.
if langfile: return _accepted[normalized]
# reconstruct the actual language from the language
# filename, because otherwise we might incorrectly for lang in (normalized, normalized.split('_')[0]):
# report de_DE if we only have de available, but if lang not in supported:
# did find de_DE because of language normalization continue
lang = langfile[len(globalpath):].split(os.path.sep)[1] langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
_accepted[accept] = lang 'django.mo')
if os.path.exists(langfile):
_accepted[normalized] = lang
return lang return lang
return settings.LANGUAGE_CODE return settings.LANGUAGE_CODE
@ -457,3 +464,23 @@ def templatize(src):
else: else:
out.write(blankout(t.contents, 'X')) out.write(blankout(t.contents, 'X'))
return out.getvalue() return out.getvalue()
def parse_accept_lang_header(lang_string):
"""
Parses the lang_string, which is the body of an HTTP Accept-Language
header, and returns a list of (lang, q-value), ordered by 'q' values.
Any format errors in lang_string results in an empty list being returned.
"""
result = []
pieces = accept_language_re.split(lang_string)
if pieces[-1]:
return []
for i in range(0, len(pieces) - 1, 3):
first, lang, priority = pieces[i : i + 3]
if first:
return []
priority = priority and float(priority) or 1.0
result.append((lang, priority))
result.sort(lambda x, y: -cmp(x[1], y[1]))
return result

View File

@ -5,7 +5,7 @@ from setuptools import setup, find_packages
setup( setup(
name = "Django", name = "Django",
version = "0.91", version = "0.91.3",
url = 'http://www.djangoproject.com/', url = 'http://www.djangoproject.com/',
author = 'Lawrence Journal-World', author = 'Lawrence Journal-World',
author_email = 'holovaty@gmail.com', author_email = 'holovaty@gmail.com',