上传及下载 #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
and clean, pragmatic design.
Django is a high-level Python Web framework that encourages rapid
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,
docs/tutorial02.txt, etc.).
This is the Django 0.91 "bugfixes" branch, which is intended to
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
for instructions on running Django under mod_python.
If you're completely new to Django we highly recommend that you use
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
should be clarified in any way, please take 30 seconds to fill out a ticket
here:
More information
================
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
hang out there. Read the archives at http://loglibrary.com/179 .
The documentation for this version of Django has been frozen, and is
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
about getting involved.
If you run into a bug in Django 0.91, please search the Django ticket
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'):
sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
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)
if __name__ == "__main__":

View File

@ -1,8 +1,35 @@
// Handles related-objects functionality: lookup link for raw_id_admin=True
// 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) {
var name = triggeringLink.id.replace(/^lookup_/, '');
name = id_to_windowname(name);
var href;
if (triggeringLink.href.search(/\?/) >= 0) {
href = triggeringLink.href + '&pop=1';
@ -15,25 +42,36 @@ function showRelatedObjectLookupPopup(triggeringLink) {
}
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) {
elem.value += ',' + chosenId;
} else {
document.getElementById(win.name).value = chosenId;
document.getElementById(name).value = chosenId;
}
win.close();
}
function showAddAnotherPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^add_/, '');
name = name.replace(/\./g, '___');
var win = window.open(triggeringLink.href + '?_popup=1', name, 'height=500,width=800,resizable=yes,scrollbars=yes');
name = id_to_windowname(name);
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();
return false;
}
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);
if (elem) {
if (elem.nodeName == 'SELECT') {

View File

@ -17,7 +17,6 @@
<p class="aligned">
<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="post_data" value="{{ post_data }}" />{% comment %} <span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %}
</p>
<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.models.auth import users
from django.utils import httpwrappers
from django.utils.html import escape
from django.utils.translation import gettext_lazy
import base64, datetime, md5
import cPickle as pickle
import base64, datetime
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'
def _display_login_form(request, error_message=''):
request.session.set_test_cookie()
if request.POST and request.POST.has_key('post_data'):
# User has failed login BUT has previously saved post data.
post_data = request.POST['post_data']
elif request.POST:
# User's session must have expired; save their post data.
post_data = _encode_post_data(request.POST)
else:
post_data = _encode_post_data({})
return render_to_response('admin/login', {
'title': _('Log in'),
'app_path': request.path,
'post_data': post_data,
'app_path': escape(request.path),
'error_message': error_message
}, context_instance=DjangoContext(request))
def _encode_post_data(post_data):
pickled = pickle.dumps(post_data)
pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def _decode_post_data(encoded_data):
encoded_data = base64.decodestring(encoded_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
if md5.new(pickled + SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User may have tampered with session cookie."
return pickle.loads(pickled)
def staff_member_required(view_func):
"""
Decorator for views that checks that the user is logged in and is a staff
@ -47,10 +25,6 @@ def staff_member_required(view_func):
def _checklogin(request, *args, **kwargs):
if not request.user.is_anonymous() and request.user.is_staff:
# The user is valid. Continue to the admin page.
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)
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 not request.POST.has_key(LOGIN_FORM_KEY):
if request.POST:
message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.")
message = _("Please log in again, because your session has expired.")
else:
message = ""
return _display_login_form(request, message)
@ -90,15 +64,6 @@ def staff_member_required(view_func):
request.session[users.SESSION_KEY] = user.id
user.last_login = datetime.datetime.now()
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)
else:
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()):
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):
# Get search parameters from the query string.

View File

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

View File

@ -107,7 +107,7 @@ class PublicCommentManipulator(AuthenticationForm):
# send the comment to the managers.
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',
'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()}
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()]:

View File

@ -16,13 +16,54 @@ except ImportError:
# Import copy of _thread_local.py from python 2.4
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):
def __init__(self):
self.connection = None
self.queries = []
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 DATABASE_NAME == '':
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
cursor = self.connection.cursor()
cursor.execute("SET TIME ZONE %s", [TIME_ZONE])
cursor = UnicodeCursorWrapper(cursor, DEFAULT_CHARSET)
if DEBUG:
return base.CursorDebugWrapper(cursor, self)
return cursor

View File

@ -325,7 +325,8 @@ class FormField:
class TextField(FormField):
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.length, self.maxlength = length, maxlength
self.is_required = is_required
@ -362,7 +363,8 @@ class PasswordField(TextField):
input_type = "password"
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.rows, self.cols, self.is_required = rows, cols, is_required
self.validator_list = validator_list[:]
@ -380,7 +382,8 @@ class LargeTextField(TextField):
self.field_name, self.rows, self.cols, escape(data))
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.validator_list = validator_list[:]
@ -410,7 +413,8 @@ class CheckboxField(FormField):
html2python = staticmethod(html2python)
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
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.size, self.is_required = choices, size, is_required
@ -446,7 +450,8 @@ class NullSelectField(SelectField):
html2python = staticmethod(html2python)
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
# choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.is_required = choices, is_required
@ -510,7 +515,8 @@ class RadioSelectField(FormField):
class NullBooleanField(SelectField):
"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')],
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.
"""
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)
def prepare(self, new_data):
@ -594,7 +601,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
####################
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.validator_list = [self.isNonEmptyFile] + validator_list
@ -629,7 +637,8 @@ class ImageUploadField(FileUploadField):
####################
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
if member_name is not None:
self.member_name = member_name
@ -648,7 +657,8 @@ class IntegerField(TextField):
html2python = staticmethod(html2python)
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
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.")
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
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.")
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
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.")
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
validator_list = [self.isValidFloat] + 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):
"""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."""
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.length, self.maxlength = length, maxlength
self.is_required = is_required
@ -723,7 +737,8 @@ class DatetimeField(TextField):
class DateField(TextField):
"""A FormField that automatically converts its data to a datetime.date object.
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
TextField.__init__(self, field_name, length=10, maxlength=10,
is_required=is_required, validator_list=validator_list)
@ -747,7 +762,8 @@ class DateField(TextField):
class TimeField(TextField):
"""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."""
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
TextField.__init__(self, field_name, length=8, maxlength=8,
is_required=is_required, validator_list=validator_list)
@ -781,7 +797,8 @@ class TimeField(TextField):
class EmailField(TextField):
"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
TextField.__init__(self, field_name, length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
@ -794,7 +811,8 @@ class EmailField(TextField):
class URLField(TextField):
"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
TextField.__init__(self, field_name, length=length, maxlength=200,
is_required=is_required, validator_list=validator_list)
@ -806,7 +824,8 @@ class URLField(TextField):
raise validators.CriticalValidationError, e.messages
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
TextField.__init__(self, field_name, length=length, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)
@ -827,7 +846,8 @@ class IPAddressField(TextField):
class FilePathField(SelectField):
"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
if match is not None:
import re
@ -850,7 +870,8 @@ class FilePathField(SelectField):
class PhoneNumberField(TextField):
"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
TextField.__init__(self, field_name, length=12, maxlength=12,
is_required=is_required, validator_list=validator_list)
@ -863,7 +884,8 @@ class PhoneNumberField(TextField):
class USStateField(TextField):
"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
TextField.__init__(self, field_name, length=2, maxlength=2,
is_required=is_required, validator_list=validator_list)
@ -875,15 +897,13 @@ class USStateField(TextField):
raise validators.CriticalValidationError, e.messages
def html2python(data):
if data:
return data.upper() # Should always be stored in upper case
else:
return None
html2python = staticmethod(html2python)
class CommaSeparatedIntegerField(TextField):
"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
TextField.__init__(self, field_name, length=20, maxlength=maxlength,
is_required=is_required, validator_list=validator_list)

View File

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

View File

@ -13,9 +13,30 @@ class ModPythonRequest(httpwrappers.HttpRequest):
self.path = req.uri
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>' % \
(self.path, pformat(self.GET), pformat(self.POST), pformat(self.COOKIES),
pformat(self.META), pformat(self.user))
(self.path, get, post, cookies, meta, user)
def get_full_path(self):
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
@ -141,12 +162,11 @@ class ModPythonHandler(BaseHandler):
try:
request = ModPythonRequest(req)
response = self.get_response(req.uri, request)
finally:
db.db.close()
# Apply response middleware
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
finally:
db.db.close()
# Convert our custom HttpResponse object back into the mod_python req.
populate_apache_request(response, req)

View File

@ -55,9 +55,30 @@ class WSGIRequest(httpwrappers.HttpRequest):
def __repr__(self):
from pprint import pformat
return '<DjangoRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
(pformat(self.GET), pformat(self.POST), pformat(self.COOKIES),
pformat(self.META))
# 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 '<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):
return '%s%s' % (self.path, self.environ['QUERY_STRING'] and ('?' + self.environ['QUERY_STRING']) or '')
@ -157,12 +178,11 @@ class WSGIHandler(BaseHandler):
try:
request = WSGIRequest(environ)
response = self.get_response(request.path, request)
finally:
db.db.close()
# Apply response middleware
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
finally:
db.db.close()
try:
status_text = STATUS_CODE_TEXT[response.status_code]

View File

@ -151,7 +151,7 @@ class BadKeywordArguments(Exception):
class BoundRelatedObject(object):
def __init__(self, related_object, field_mapping, original):
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):
raise NotImplementedError
@ -165,7 +165,7 @@ class RelatedObject(object):
self.opts = opts
self.field = field
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()
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.
# For example, make sure the Place exists for the Restaurant.
# 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
_ = 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])

View File

@ -327,18 +327,26 @@ def get_digit(value, arg):
# DATES #
###################
EMPTY_DATE_VALUES = (None, '')
def date(value, arg=DATE_FORMAT):
"Formats a date according to the given format"
if value in EMPTY_DATE_VALUES:
return ''
from django.utils.dateformat import format
return format(value, arg)
def time(value, arg=TIME_FORMAT):
"Formats a time according to the given format"
if value in EMPTY_DATE_VALUES:
return ''
from django.utils.dateformat import time_format
return time_format(value, arg)
def timesince(value):
'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
return timesince(value)

View File

@ -1,6 +1,9 @@
"translation helper functions"
import os, re, sys
import locale
import os
import re
import sys
import gettext as gettext_module
from cStringIO import StringIO
from django.utils.functional import lazy
@ -25,14 +28,24 @@ _active = {}
# The default translation is based on the settings file.
_default = None
# This is a cache for accept-header to translation object mappings to prevent
# the accept parser to run multiple times for one user.
# This is a cache for normalised accept-header languages to prevent multiple
# file lookups when checking the same locale on repeated requests.
_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)."
p = language.find('-')
if p >= 0:
if to_lower:
return language[:p].lower()+'_'+language[p+1:].lower()
else:
return language[:p].lower()+'_'+language[p+1:].upper()
else:
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):
return lang_code
lang_code = request.COOKIES.get('django_language', None)
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
lang_code = request.COOKIES.get('django_language')
if lang_code and lang_code in supported and check_for_language(lang_code):
return lang_code
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None)
if accept is not None:
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
for lang, unused in parse_accept_lang_header(accept):
if lang == '*':
break
t = _accepted.get(accept, None)
if t is not None:
return t
# We have a very restricted form for our language files (no encoding
# specifier, since they all must be UTF-8 and only one possible
# language each time. So we avoid the overhead of gettext.find() and
# look up the MO file manually.
def _parsed(el):
p = el.find(';q=')
if p >= 0:
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)
normalized = locale.locale_alias.get(to_locale(lang, True))
if not normalized:
continue
langs = [_parsed(el) for el in accept.split(',')]
langs.sort(lambda a,b: -1*cmp(a[2], b[2]))
# Remove the default encoding from locale_alias
normalized = normalized.split('.')[0]
for lang, mainlang, order in langs:
if lang in supported or mainlang in supported:
langfile = gettext_module.find('django', globalpath, [to_locale(lang)])
if langfile:
# reconstruct the actual language from the language
# filename, because otherwise we might incorrectly
# report de_DE if we only have de available, but
# did find de_DE because of language normalization
lang = langfile[len(globalpath):].split(os.path.sep)[1]
_accepted[accept] = lang
if normalized in _accepted:
# We've seen this locale before and have an MO file for it, so no
# need to check again.
return _accepted[normalized]
for lang in (normalized, normalized.split('_')[0]):
if lang not in supported:
continue
langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
'django.mo')
if os.path.exists(langfile):
_accepted[normalized] = lang
return lang
return settings.LANGUAGE_CODE
@ -457,3 +464,23 @@ def templatize(src):
else:
out.write(blankout(t.contents, 'X'))
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(
name = "Django",
version = "0.91",
version = "0.91.3",
url = 'http://www.djangoproject.com/',
author = 'Lawrence Journal-World',
author_email = 'holovaty@gmail.com',