mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
sqlalchemy: Merged revisions 3770 to 3831 from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@3832 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8afc419b12
commit
1bb4fa2cb6
9
AUTHORS
9
AUTHORS
@ -42,6 +42,7 @@ And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
|
||||
people who have submitted patches, reported bugs, added translations, helped
|
||||
answer newbie questions, and generally made Django that much better:
|
||||
|
||||
adurdin@gmail.com
|
||||
akaihola
|
||||
Andreas
|
||||
ant9000@netwise.it
|
||||
@ -68,15 +69,19 @@ answer newbie questions, and generally made Django that much better:
|
||||
Alex Dedul
|
||||
deric@monowerks.com
|
||||
dne@mayonnaise.net
|
||||
Maximillian Dornseif <md@hudora.de>
|
||||
dummy@habmalnefrage.de
|
||||
Jeremy Dunck <http://dunck.us/>
|
||||
Andy Dustman <farcepest@gmail.com>
|
||||
Clint Ecker
|
||||
favo@exoweb.net
|
||||
gandalf@owca.info
|
||||
Baishampayan Ghose
|
||||
martin.glueck@gmail.com
|
||||
Simon Greenhill <dev@simon.net.nz>
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
Brant Harris
|
||||
heckj@mac.com
|
||||
hipertracker@gmail.com
|
||||
Ian Holsman <http://feh.holsman.net/>
|
||||
Kieran Holland <http://www.kieranholland.com>
|
||||
@ -96,6 +101,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
lakin.wecker@gmail.com
|
||||
Stuart Langridge <http://www.kryogenix.org/>
|
||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||
Jeong-Min Lee
|
||||
Christopher Lenz <http://www.cmlenz.net/>
|
||||
limodou
|
||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||
@ -122,6 +128,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Daniel Poelzleithner <http://poelzi.org/>
|
||||
J. Rademaker
|
||||
Michael Radziej <mir@noris.de>
|
||||
ramiro
|
||||
Brian Ray <http://brianray.chipy.org/>
|
||||
rhettg@gmail.com
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
@ -144,8 +151,10 @@ answer newbie questions, and generally made Django that much better:
|
||||
Milton Waddams
|
||||
Dan Watson <http://theidioteque.net/>
|
||||
Rachel Willmer <http://www.willmer.com/kb/>
|
||||
Gary Wilson <gary.wilson@gmail.com>
|
||||
wojtek
|
||||
ye7cakf02@sneakemail.com
|
||||
ymasuda@ethercube.com
|
||||
Cheng Zhang
|
||||
|
||||
A big THANK YOU goes to:
|
||||
|
4
README
4
README
@ -25,10 +25,10 @@ http://code.djangoproject.com/newticket
|
||||
To get more help:
|
||||
|
||||
* Join the #django channel on irc.freenode.net. Lots of helpful people
|
||||
hang out there. Read the archives at http://loglibrary.com/179 .
|
||||
hang out there. Read the archives at http://simon.bofh.ms/logger/django/ .
|
||||
|
||||
* Join the django-users mailing list, or read the archives, at
|
||||
http://groups-beta.google.com/group/django-users.
|
||||
http://groups.google.com/group/django-users.
|
||||
|
||||
To contribute to Django:
|
||||
|
||||
|
@ -64,6 +64,7 @@ LANGUAGES = (
|
||||
('sr', gettext_noop('Serbian')),
|
||||
('sv', gettext_noop('Swedish')),
|
||||
('ta', gettext_noop('Tamil')),
|
||||
('tr', gettext_noop('Turkish')),
|
||||
('uk', gettext_noop('Ukrainian')),
|
||||
('zh-cn', gettext_noop('Simplified Chinese')),
|
||||
('zh-tw', gettext_noop('Traditional Chinese')),
|
||||
@ -272,6 +273,10 @@ CACHE_MIDDLEWARE_KEY_PREFIX = ''
|
||||
|
||||
COMMENTS_ALLOW_PROFANITIES = False
|
||||
|
||||
# The profanities that will trigger a validation error in the
|
||||
# 'hasNoProfanities' validator. All of these should be in lower-case.
|
||||
PROFANITIES_LIST = ['asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit']
|
||||
|
||||
# The group ID that designates which users are banned.
|
||||
# Set to None if you're not using it.
|
||||
COMMENTS_BANNED_USERS_GROUP = None
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
django/conf/locale/tr/LC_MESSAGES/django.mo
Normal file
BIN
django/conf/locale/tr/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
1898
django/conf/locale/tr/LC_MESSAGES/django.po
Normal file
1898
django/conf/locale/tr/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: django v1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-05-16 10:10+0200\n"
|
||||
"PO-Revision-Date: 2006-05-17 13:47+0800\n"
|
||||
"PO-Revision-Date: 2006-09-01 22:05+0800\n"
|
||||
"Last-Translator: limodou <limodou@gmail.com>\n"
|
||||
"Language-Team: Simplified Chinese <limodou@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -1167,7 +1167,7 @@ msgstr "个人信息"
|
||||
|
||||
#: contrib/auth/models.py:77
|
||||
msgid "Permissions"
|
||||
msgstr "许可"
|
||||
msgstr "权限"
|
||||
|
||||
#: contrib/auth/models.py:78
|
||||
msgid "Important dates"
|
||||
|
Binary file not shown.
@ -3,22 +3,21 @@
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Project-Id-Version: Django 0.95\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2006-03-21 18:43+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <max@exoweb.net>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"PO-Revision-Date: 2006-09-25 08:35+0800\n"
|
||||
"Last-Translator: limodou <limodou@gmail.com>\n"
|
||||
"Language-Team: limodou <limodou@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
msgid "Available %s"
|
||||
msgstr "可行 %s"
|
||||
msgstr "可用 %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
@ -30,34 +29,32 @@ msgstr "增加"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
msgstr "移出"
|
||||
msgstr "删除"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
msgid "Chosen %s"
|
||||
msgstr "选择 %s"
|
||||
msgstr "选中的 %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "挑选你的选择并且点击 "
|
||||
msgstr "选择并点击 "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "清除所有"
|
||||
msgstr "清除全部"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgid "January February March April May June July August September October November December"
|
||||
msgstr "一月 二月 三月 四月 五月 六月 六月 七月 八月 九月 十月 十一月 十二月"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "星期天 星期一 星期二 星期三 星期四 星期五 星期六"
|
||||
msgstr "星期日 星期一 星期二 星期三 星期四 星期五 星期六"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "日 月 火 水 木 金 土"
|
||||
msgstr "日 一 二 三 四 五 六"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
@ -105,3 +102,4 @@ msgstr "昨天"
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
msgid "Tomorrow"
|
||||
msgstr "明天"
|
||||
|
||||
|
@ -160,8 +160,10 @@ class EditInlineNode(template.Node):
|
||||
context.push()
|
||||
if relation.field.rel.edit_inline == models.TABULAR:
|
||||
bound_related_object_class = TabularBoundRelatedObject
|
||||
else:
|
||||
elif relation.field.rel.edit_inline == models.STACKED:
|
||||
bound_related_object_class = StackedBoundRelatedObject
|
||||
else:
|
||||
bound_related_object_class = relation.field.rel.edit_inline
|
||||
original = context.get('original', None)
|
||||
bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
|
||||
context['bound_related_object'] = bound_related_object
|
||||
|
@ -727,6 +727,8 @@ class ChangeList(object):
|
||||
for bit in self.query.split():
|
||||
or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields]
|
||||
other_qs = QuerySet(self.model)
|
||||
if qs._select_related:
|
||||
other_qs = other_qs.select_related()
|
||||
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
|
||||
qs = qs & other_qs
|
||||
|
||||
|
@ -26,3 +26,11 @@ login_required.__doc__ = (
|
||||
to the log-in page if necessary.
|
||||
"""
|
||||
)
|
||||
|
||||
def permission_required(perm, login_url=LOGIN_URL):
|
||||
"""
|
||||
Decorator for views that checks if a user has a particular permission
|
||||
enabled, redirectiing to the log-in page if necessary.
|
||||
"""
|
||||
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
|
||||
|
||||
|
@ -81,7 +81,7 @@ class PasswordResetForm(forms.Manipulator):
|
||||
try:
|
||||
self.user_cache = User.objects.get(email__iexact=new_data)
|
||||
except User.DoesNotExist:
|
||||
raise validators.ValidationError, "That e-mail address doesn't have an associated user acount. Are you sure you've registered?"
|
||||
raise validators.ValidationError, _("That e-mail address doesn't have an associated user acount. Are you sure you've registered?")
|
||||
|
||||
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html'):
|
||||
"Calculates a new password randomly and sends it to the user"
|
||||
@ -113,14 +113,14 @@ class PasswordChangeForm(forms.Manipulator):
|
||||
forms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True,
|
||||
validator_list=[self.isValidOldPassword]),
|
||||
forms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('new_password2', "The two 'new password' fields didn't match.")]),
|
||||
validator_list=[validators.AlwaysMatchesOtherField('new_password2', _("The two 'new password' fields didn't match."))]),
|
||||
forms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True),
|
||||
)
|
||||
|
||||
def isValidOldPassword(self, new_data, all_data):
|
||||
"Validates that the old_password field is correct."
|
||||
if not self.user.check_password(new_data):
|
||||
raise validators.ValidationError, "Your old password was entered incorrectly. Please enter it again."
|
||||
raise validators.ValidationError, _("Your old password was entered incorrectly. Please enter it again.")
|
||||
|
||||
def save(self, new_data):
|
||||
"Saves the new password."
|
||||
|
@ -22,6 +22,8 @@ def authenhandler(req, **kwargs):
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django import db
|
||||
db.reset_queries()
|
||||
|
||||
# check that the username is valid
|
||||
kwargs = {'username': req.user, 'is_active': True}
|
||||
@ -30,18 +32,21 @@ def authenhandler(req, **kwargs):
|
||||
if superuser_only:
|
||||
kwargs['is_superuser'] = True
|
||||
try:
|
||||
user = User.objects.get(**kwargs)
|
||||
except User.DoesNotExist:
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
try:
|
||||
user = User.objects.get(**kwargs)
|
||||
except User.DoesNotExist:
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
|
||||
# check the password and any permission given
|
||||
if user.check_password(req.get_basic_auth_pw()):
|
||||
if permission_name:
|
||||
if user.has_perm(permission_name):
|
||||
return apache.OK
|
||||
# check the password and any permission given
|
||||
if user.check_password(req.get_basic_auth_pw()):
|
||||
if permission_name:
|
||||
if user.has_perm(permission_name):
|
||||
return apache.OK
|
||||
else:
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
else:
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
return apache.OK
|
||||
else:
|
||||
return apache.OK
|
||||
else:
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
return apache.HTTP_UNAUTHORIZED
|
||||
finally:
|
||||
db.connection.close()
|
||||
|
@ -51,15 +51,19 @@ def request(request):
|
||||
class PermLookupDict(object):
|
||||
def __init__(self, user, module_name):
|
||||
self.user, self.module_name = user, module_name
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.user.get_permission_list())
|
||||
return str(self.user.get_all_permissions())
|
||||
|
||||
def __getitem__(self, perm_name):
|
||||
return self.user.has_perm("%s.%s" % (self.module_name, perm_name))
|
||||
|
||||
def __nonzero__(self):
|
||||
return self.user.has_module_perms(self.module_name)
|
||||
|
||||
class PermWrapper(object):
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
|
||||
def __getitem__(self, module_name):
|
||||
return PermLookupDict(self.user, module_name)
|
||||
|
@ -16,9 +16,26 @@ class ModPythonRequest(http.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>'
|
||||
return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
|
||||
(self.path, pformat(self.GET), pformat(self.POST), pformat(self.COOKIES),
|
||||
pformat(self.META))
|
||||
(self.path, get, post, cookies, meta)
|
||||
|
||||
def get_full_path(self):
|
||||
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
|
||||
@ -155,8 +172,11 @@ def populate_apache_request(http_response, mod_python_req):
|
||||
for c in http_response.cookies.values():
|
||||
mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
|
||||
mod_python_req.status = http_response.status_code
|
||||
for chunk in http_response.iterator:
|
||||
mod_python_req.write(chunk)
|
||||
try:
|
||||
for chunk in http_response:
|
||||
mod_python_req.write(chunk)
|
||||
finally:
|
||||
http_response.close()
|
||||
|
||||
def handler(req):
|
||||
# mod_python hooks into this function.
|
||||
|
@ -4,6 +4,11 @@ from django.dispatch import dispatcher
|
||||
from django.utils import datastructures
|
||||
from django import http
|
||||
from pprint import pformat
|
||||
from shutil import copyfileobj
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
STATUS_CODE_TEXT = {
|
||||
@ -50,6 +55,21 @@ STATUS_CODE_TEXT = {
|
||||
505: 'HTTP VERSION NOT SUPPORTED',
|
||||
}
|
||||
|
||||
def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
|
||||
"""
|
||||
A version of shutil.copyfileobj that will not read more than 'size' bytes.
|
||||
This makes it safe from clients sending more than CONTENT_LENGTH bytes of
|
||||
data in the body.
|
||||
"""
|
||||
if not size:
|
||||
return copyfileobj(fsrc, fdst, length)
|
||||
while size > 0:
|
||||
buf = fsrc.read(min(length, size))
|
||||
if not buf:
|
||||
break
|
||||
fdst.write(buf)
|
||||
size -= len(buf)
|
||||
|
||||
class WSGIRequest(http.HttpRequest):
|
||||
def __init__(self, environ):
|
||||
self.environ = environ
|
||||
@ -58,9 +78,26 @@ class WSGIRequest(http.HttpRequest):
|
||||
self.method = environ['REQUEST_METHOD'].upper()
|
||||
|
||||
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>'
|
||||
return '<WSGIRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
|
||||
(pformat(self.GET), pformat(self.POST), pformat(self.COOKIES),
|
||||
pformat(self.META))
|
||||
(get, post, cookies, meta)
|
||||
|
||||
def get_full_path(self):
|
||||
return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '')
|
||||
@ -119,7 +156,11 @@ class WSGIRequest(http.HttpRequest):
|
||||
try:
|
||||
return self._raw_post_data
|
||||
except AttributeError:
|
||||
self._raw_post_data = self.environ['wsgi.input'].read(int(self.environ["CONTENT_LENGTH"]))
|
||||
buf = StringIO()
|
||||
content_length = int(self.environ['CONTENT_LENGTH'])
|
||||
safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length)
|
||||
self._raw_post_data = buf.getvalue()
|
||||
buf.close()
|
||||
return self._raw_post_data
|
||||
|
||||
GET = property(_get_get, _set_get)
|
||||
@ -163,4 +204,4 @@ class WSGIHandler(BaseHandler):
|
||||
for c in response.cookies.values():
|
||||
response_headers.append(('Set-Cookie', c.output(header='')))
|
||||
start_response(status, response_headers)
|
||||
return response.iterator
|
||||
return response
|
||||
|
@ -347,7 +347,7 @@ def get_sql_initial_data_for_model(model):
|
||||
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
|
||||
for sql_file in sql_files:
|
||||
if os.path.exists(sql_file):
|
||||
fp = open(sql_file)
|
||||
fp = open(sql_file, 'U')
|
||||
for statement in statements.split(fp.read()):
|
||||
if statement.strip():
|
||||
output.append(statement + ";")
|
||||
@ -958,7 +958,8 @@ def get_validation_errors(outfile, app=None):
|
||||
try:
|
||||
f = opts.get_field(fn)
|
||||
except models.FieldDoesNotExist:
|
||||
e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
|
||||
if not hasattr(cls, fn):
|
||||
e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
|
||||
if fn not in opts.admin.list_display:
|
||||
e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
|
||||
# list_filter
|
||||
@ -1016,10 +1017,12 @@ def get_validation_errors(outfile, app=None):
|
||||
|
||||
return len(e.errors)
|
||||
|
||||
def validate(outfile=sys.stdout):
|
||||
def validate(outfile=sys.stdout, silent_success=False):
|
||||
"Validates all installed models."
|
||||
try:
|
||||
num_errors = get_validation_errors(outfile)
|
||||
if silent_success and num_errors == 0:
|
||||
return
|
||||
outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
|
||||
except ImproperlyConfigured:
|
||||
outfile.write("Skipping validation because things aren't configured properly.")
|
||||
@ -1042,7 +1045,7 @@ def _check_for_validation_errors(app=None):
|
||||
sys.stderr.write(s.read())
|
||||
sys.exit(1)
|
||||
|
||||
def runserver(addr, port, use_reloader=True):
|
||||
def runserver(addr, port, use_reloader=True, admin_media_dir=''):
|
||||
"Starts a lightweight Web server for development."
|
||||
from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
@ -1060,7 +1063,10 @@ def runserver(addr, port, use_reloader=True):
|
||||
print "Development server is running at http://%s:%s/" % (addr, port)
|
||||
print "Quit the server with %s." % quit_command
|
||||
try:
|
||||
run(addr, int(port), AdminMediaHandler(WSGIHandler()))
|
||||
import django
|
||||
path = admin_media_dir or django.__path__[0] + '/contrib/admin/media'
|
||||
handler = AdminMediaHandler(WSGIHandler(), path)
|
||||
run(addr, int(port), handler)
|
||||
except WSGIServerException, e:
|
||||
# Use helpful error messages instead of ugly tracebacks.
|
||||
ERRORS = {
|
||||
@ -1081,7 +1087,7 @@ def runserver(addr, port, use_reloader=True):
|
||||
autoreload.main(inner_run)
|
||||
else:
|
||||
inner_run()
|
||||
runserver.args = '[--noreload] [optional port number, or ipaddr:port]'
|
||||
runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
|
||||
|
||||
def createcachetable(tablename):
|
||||
"Creates the table needed to use the SQL cache backend"
|
||||
@ -1267,7 +1273,8 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
help='Tells Django to NOT use the auto-reloader when running the development server.')
|
||||
parser.add_option('--verbosity', action='store', dest='verbosity', default='2',
|
||||
type='choice', choices=['0', '1', '2'],
|
||||
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
|
||||
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
|
||||
parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Lets you manually specify the directory to serve admin media from when running the development server.'),
|
||||
|
||||
options, args = parser.parse_args(argv[1:])
|
||||
|
||||
@ -1331,11 +1338,12 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
addr, port = args[1].split(':')
|
||||
except ValueError:
|
||||
addr, port = '', args[1]
|
||||
action_mapping[action](addr, port, options.use_reloader)
|
||||
action_mapping[action](addr, port, options.use_reloader, options.admin_media_path)
|
||||
elif action == 'runfcgi':
|
||||
action_mapping[action](args[1:])
|
||||
else:
|
||||
from django.db import models
|
||||
validate(silent_success=True)
|
||||
try:
|
||||
mod_list = [models.get_app(app_label) for app_label in args[1:]]
|
||||
except ImportError, e:
|
||||
|
@ -16,7 +16,7 @@ class Serializer(PythonSerializer):
|
||||
Convert a queryset to JSON.
|
||||
"""
|
||||
def end_serialization(self):
|
||||
simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder)
|
||||
simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder, **self.options)
|
||||
|
||||
def getvalue(self):
|
||||
return self.stream.getvalue()
|
||||
|
@ -594,11 +594,14 @@ class AdminMediaHandler(object):
|
||||
Use this ONLY LOCALLY, for development! This hasn't been tested for
|
||||
security and is not super efficient.
|
||||
"""
|
||||
def __init__(self, application):
|
||||
def __init__(self, application, media_dir = None):
|
||||
from django.conf import settings
|
||||
import django
|
||||
self.application = application
|
||||
self.media_dir = django.__path__[0] + '/contrib/admin/media'
|
||||
if not media_dir:
|
||||
import django
|
||||
self.media_dir = django.__path__[0] + '/contrib/admin/media'
|
||||
else:
|
||||
self.media_dir = media_dir
|
||||
self.media_url = settings.ADMIN_MEDIA_PREFIX
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
|
@ -74,7 +74,7 @@ def fastcgi_help(message=None):
|
||||
print message
|
||||
return False
|
||||
|
||||
def runfastcgi(argset, **kwargs):
|
||||
def runfastcgi(argset=[], **kwargs):
|
||||
options = FASTCGI_OPTIONS.copy()
|
||||
options.update(kwargs)
|
||||
for x in argset:
|
||||
|
@ -13,7 +13,7 @@ from django.utils.translation import gettext, gettext_lazy, ngettext
|
||||
from django.utils.functional import Promise, lazy
|
||||
import re
|
||||
|
||||
_datere = r'(19|2\d)\d{2}-((?:0?[1-9])|(?:1[0-2]))-((?:0?[1-9])|(?:[12][0-9])|(?:3[0-1]))'
|
||||
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
|
||||
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
|
||||
alnum_re = re.compile(r'^\w+$')
|
||||
alnumurl_re = re.compile(r'^[-\w/]+$')
|
||||
@ -122,9 +122,29 @@ def isOnlyLetters(field_data, all_data):
|
||||
if not field_data.isalpha():
|
||||
raise ValidationError, gettext("Only alphabetical characters are allowed here.")
|
||||
|
||||
def _isValidDate(date_string):
|
||||
"""
|
||||
A helper function used by isValidANSIDate and isValidANSIDatetime to
|
||||
check if the date is valid. The date string is assumed to already be in
|
||||
YYYY-MM-DD format.
|
||||
"""
|
||||
from datetime import date
|
||||
# Could use time.strptime here and catch errors, but datetime.date below
|
||||
# produces much friendlier error messages.
|
||||
year, month, day = map(int, date_string.split('-'))
|
||||
# This check is needed because strftime is used when saving the date
|
||||
# value to the database, and strftime requires that the year be >=1900.
|
||||
if year < 1900:
|
||||
raise ValidationError, gettext('Year must be 1900 or later.')
|
||||
try:
|
||||
date(year, month, day)
|
||||
except ValueError, e:
|
||||
raise ValidationError, gettext('Invalid date: %s.' % e)
|
||||
|
||||
def isValidANSIDate(field_data, all_data):
|
||||
if not ansi_date_re.search(field_data):
|
||||
raise ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
|
||||
_isValidDate(field_data)
|
||||
|
||||
def isValidANSITime(field_data, all_data):
|
||||
if not ansi_time_re.search(field_data):
|
||||
@ -133,6 +153,7 @@ def isValidANSITime(field_data, all_data):
|
||||
def isValidANSIDatetime(field_data, all_data):
|
||||
if not ansi_datetime_re.search(field_data):
|
||||
raise ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
|
||||
_isValidDate(field_data.split()[0])
|
||||
|
||||
def isValidEmail(field_data, all_data):
|
||||
if not email_re.search(field_data):
|
||||
@ -227,9 +248,8 @@ def hasNoProfanities(field_data, all_data):
|
||||
catch 'motherfucker' as well. Raises a ValidationError such as:
|
||||
Watch your mouth! The words "f--k" and "s--t" are not allowed here.
|
||||
"""
|
||||
bad_words = ['asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit'] # all in lower case
|
||||
field_data = field_data.lower() # normalize
|
||||
words_seen = [w for w in bad_words if field_data.find(w) > -1]
|
||||
words_seen = [w for w in settings.PROFANITIES_LIST if field_data.find(w) > -1]
|
||||
if words_seen:
|
||||
from django.utils.text import get_text_list
|
||||
plural = len(words_seen) > 1
|
||||
@ -352,10 +372,12 @@ class IsValidFloat(object):
|
||||
float(data)
|
||||
except ValueError:
|
||||
raise ValidationError, gettext("Please enter a valid decimal number.")
|
||||
if len(data) > (self.max_digits + 1):
|
||||
# Negative floats require more space to input.
|
||||
max_allowed_length = data.startswith('-') and (self.max_digits + 2) or (self.max_digits + 1)
|
||||
if len(data) > max_allowed_length:
|
||||
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
|
||||
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
|
||||
if (not '.' in data and len(data) > (self.max_digits - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
|
||||
if (not '.' in data and len(data) > (max_allowed_length - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):
|
||||
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
|
||||
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
|
||||
if '.' in data and len(data.split('.')[1]) > self.decimal_places:
|
||||
|
@ -13,9 +13,10 @@ def populate_xheaders(request, response, model, object_id):
|
||||
"""
|
||||
Adds the "X-Object-Type" and "X-Object-Id" headers to the given
|
||||
HttpResponse according to the given model and object_id -- but only if the
|
||||
given HttpRequest object has an IP address within the INTERNAL_IPS setting.
|
||||
given HttpRequest object has an IP address within the INTERNAL_IPS setting
|
||||
or if the request is from a logged in staff member.
|
||||
"""
|
||||
from django.conf import settings
|
||||
if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
|
||||
if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff):
|
||||
response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())
|
||||
response['X-Object-Id'] = str(object_id)
|
||||
|
@ -4,10 +4,18 @@ SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/).
|
||||
|
||||
from django.db.backends import util
|
||||
try:
|
||||
from pysqlite2 import dbapi2 as Database
|
||||
try:
|
||||
from sqlite3 import dbapi2 as Database
|
||||
except ImportError:
|
||||
from pysqlite2 import dbapi2 as Database
|
||||
except ImportError, e:
|
||||
import sys
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured, "Error loading pysqlite2 module: %s" % e
|
||||
if sys.version_info < (2, 5, 0):
|
||||
module = 'pysqlite2'
|
||||
else:
|
||||
module = 'sqlite3'
|
||||
raise ImproperlyConfigured, "Error loading %s module: %s" % (module, e)
|
||||
|
||||
DatabaseError = Database.DatabaseError
|
||||
|
||||
|
@ -110,9 +110,11 @@ def dictfetchone(cursor):
|
||||
def dictfetchmany(cursor, number):
|
||||
"Returns a certain number of rows from a cursor as a dict"
|
||||
desc = cursor.description
|
||||
return [_dict_helper(desc, row) for row in cursor.fetchmany(number)]
|
||||
for row in cursor.fetchmany(number):
|
||||
yield _dict_helper(desc, row)
|
||||
|
||||
def dictfetchall(cursor):
|
||||
"Returns all rows from a cursor as a dict"
|
||||
desc = cursor.description
|
||||
return [_dict_helper(desc, row) for row in cursor.fetchall()]
|
||||
for row in cursor.fetchall():
|
||||
yield _dict_helper(desc, row)
|
||||
|
@ -117,7 +117,7 @@ class GenericRelation(RelatedField, Field):
|
||||
return self.object_id_field_name
|
||||
|
||||
def m2m_reverse_name(self):
|
||||
return self.model._meta.pk.attname
|
||||
return self.object_id_field_name
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
super(GenericRelation, self).contribute_to_class(cls, name)
|
||||
|
@ -215,8 +215,8 @@ class AutomaticManipulator(forms.Manipulator):
|
||||
# Save many-to-many objects.
|
||||
for f in related.opts.many_to_many:
|
||||
if child_follow.get(f.name, None) and not f.rel.edit_inline:
|
||||
was_changed = getattr(new_rel_obj, 'set_%s' % f.name)(rel_new_data[f.attname])
|
||||
if self.change and was_changed:
|
||||
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=rel_new_data[f.attname]))
|
||||
if self.change:
|
||||
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
|
||||
|
||||
# If, in the change stage, all of the core fields were blank and
|
||||
|
@ -712,14 +712,10 @@ def parse_lookup(kwarg_items, opts):
|
||||
# Extract the last elements of the kwarg.
|
||||
# The very-last is the lookup_type (equals, like, etc).
|
||||
# The second-last is the table column on which the lookup_type is
|
||||
# to be performed.
|
||||
# The exceptions to this are:
|
||||
# 1) "pk", which is an implicit id__exact;
|
||||
# if we find "pk", make the lookup_type "exact', and insert
|
||||
# a dummy name of None, which we will replace when
|
||||
# we know which table column to grab as the primary key.
|
||||
# 2) If there is only one part, or the last part is not a query
|
||||
# term, assume that the query is an __exact
|
||||
# to be performed. If this name is 'pk', it will be substituted with
|
||||
# the name of the primary key.
|
||||
# If there is only one part, or the last part is not a query
|
||||
# term, assume that the query is an __exact
|
||||
lookup_type = path.pop()
|
||||
if lookup_type == 'pk':
|
||||
lookup_type = 'exact'
|
||||
@ -766,7 +762,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
|
||||
name = path.pop(0)
|
||||
# Has the primary key been requested? If so, expand it out
|
||||
# to be the name of the current class' primary key
|
||||
if name is None:
|
||||
if name is None or name == 'pk':
|
||||
name = current_opts.pk.name
|
||||
|
||||
# Try to find the name in the fields associated with the current class
|
||||
|
@ -2,7 +2,7 @@ from django.core import validators
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.utils.html import escape
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext, gettext_lazy, ngettext
|
||||
from django.utils.translation import gettext, ngettext
|
||||
|
||||
FORM_FIELD_ID_PREFIX = 'id_'
|
||||
|
||||
@ -343,7 +343,7 @@ class FormField(object):
|
||||
def get_validation_errors(self, new_data):
|
||||
errors = {}
|
||||
if self.is_required and not new_data.get(self.field_name, False):
|
||||
errors.setdefault(self.field_name, []).append(gettext_lazy('This field is required.'))
|
||||
errors.setdefault(self.field_name, []).append(gettext('This field is required.'))
|
||||
return errors
|
||||
try:
|
||||
for validator in self.validator_list:
|
||||
@ -434,11 +434,11 @@ class HiddenField(FormField):
|
||||
(self.get_id(), self.field_name, escape(data))
|
||||
|
||||
class CheckboxField(FormField):
|
||||
def __init__(self, field_name, checked_by_default=False, validator_list=None):
|
||||
def __init__(self, field_name, checked_by_default=False, validator_list=None, is_required=False):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name = field_name
|
||||
self.checked_by_default = checked_by_default
|
||||
self.is_required = False # because the validator looks for these
|
||||
self.is_required = is_required
|
||||
self.validator_list = validator_list[:]
|
||||
|
||||
def render(self, data):
|
||||
@ -639,8 +639,8 @@ class CheckboxSelectMultipleField(SelectMultipleField):
|
||||
checked_html = ' checked="checked"'
|
||||
field_name = '%s%s' % (self.field_name, value)
|
||||
output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s /> <label for="%s">%s</label></li>' % \
|
||||
(self.get_id() + value , self.__class__.__name__, field_name, checked_html,
|
||||
self.get_id() + value, choice))
|
||||
(self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
|
||||
self.get_id() + escape(value), choice))
|
||||
output.append('</ul>')
|
||||
return '\n'.join(output)
|
||||
|
||||
@ -743,7 +743,7 @@ class FloatField(TextField):
|
||||
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)
|
||||
TextField.__init__(self, field_name, max_digits+2, max_digits+2, is_required, validator_list)
|
||||
|
||||
def isValidFloat(self, field_data, all_data):
|
||||
v = validators.IsValidFloat(self.max_digits, self.decimal_places)
|
||||
@ -952,10 +952,7 @@ 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
|
||||
return data.upper() # Should always be stored in upper case
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
class CommaSeparatedIntegerField(TextField):
|
||||
@ -972,9 +969,19 @@ class CommaSeparatedIntegerField(TextField):
|
||||
except validators.ValidationError, e:
|
||||
raise validators.CriticalValidationError, e.messages
|
||||
|
||||
def render(self, data):
|
||||
if data is None:
|
||||
data = ''
|
||||
elif isinstance(data, (list, tuple)):
|
||||
data = ','.join(data)
|
||||
return super(CommaSeparatedIntegerField, self).render(data)
|
||||
|
||||
class RawIdAdminField(CommaSeparatedIntegerField):
|
||||
def html2python(data):
|
||||
return data.split(',')
|
||||
if data:
|
||||
return data.split(',')
|
||||
else:
|
||||
return []
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
class XMLLargeTextField(LargeTextField):
|
||||
|
@ -161,10 +161,10 @@ class HttpResponse(object):
|
||||
if not mimetype:
|
||||
mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET)
|
||||
if hasattr(content, '__iter__'):
|
||||
self._iterator = content
|
||||
self._container = content
|
||||
self._is_string = False
|
||||
else:
|
||||
self._iterator = [content]
|
||||
self._container = [content]
|
||||
self._is_string = True
|
||||
self.headers = {'Content-Type': mimetype}
|
||||
self.cookies = SimpleCookie()
|
||||
@ -213,32 +213,37 @@ class HttpResponse(object):
|
||||
self.cookies[key]['max-age'] = 0
|
||||
|
||||
def _get_content(self):
|
||||
content = ''.join(self._iterator)
|
||||
content = ''.join(self._container)
|
||||
if isinstance(content, unicode):
|
||||
content = content.encode(self._charset)
|
||||
return content
|
||||
|
||||
def _set_content(self, value):
|
||||
self._iterator = [value]
|
||||
self._container = [value]
|
||||
self._is_string = True
|
||||
|
||||
content = property(_get_content, _set_content)
|
||||
|
||||
def _get_iterator(self):
|
||||
"Output iterator. Converts data into client charset if necessary."
|
||||
for chunk in self._iterator:
|
||||
if isinstance(chunk, unicode):
|
||||
chunk = chunk.encode(self._charset)
|
||||
yield chunk
|
||||
def __iter__(self):
|
||||
self._iterator = self._container.__iter__()
|
||||
return self
|
||||
|
||||
iterator = property(_get_iterator)
|
||||
def next(self):
|
||||
chunk = self._iterator.next()
|
||||
if isinstance(chunk, unicode):
|
||||
chunk = chunk.encode(self._charset)
|
||||
return chunk
|
||||
|
||||
def close(self):
|
||||
if hasattr(self._container, 'close'):
|
||||
self._container.close()
|
||||
|
||||
# The remaining methods partially implement the file-like object interface.
|
||||
# See http://docs.python.org/lib/bltin-file-objects.html
|
||||
def write(self, content):
|
||||
if not self._is_string:
|
||||
raise Exception, "This %s instance is not writable" % self.__class__
|
||||
self._iterator.append(content)
|
||||
self._container.append(content)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
@ -246,7 +251,7 @@ class HttpResponse(object):
|
||||
def tell(self):
|
||||
if not self._is_string:
|
||||
raise Exception, "This %s instance cannot tell its position" % self.__class__
|
||||
return sum([len(chunk) for chunk in self._iterator])
|
||||
return sum([len(chunk) for chunk in self._container])
|
||||
|
||||
class HttpResponseRedirect(HttpResponse):
|
||||
def __init__(self, redirect_to):
|
||||
|
@ -64,8 +64,9 @@ class CommonMiddleware(object):
|
||||
is_internal = referer and (domain in referer)
|
||||
path = request.get_full_path()
|
||||
if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer):
|
||||
ua = request.META.get('HTTP_USER_AGENT','<none>')
|
||||
mail_managers("Broken %slink on %s" % ((is_internal and 'INTERNAL ' or ''), domain),
|
||||
"Referrer: %s\nRequested URL: %s\n" % (referer, request.get_full_path()))
|
||||
"Referrer: %s\nRequested URL: %s\nUser Agent: %s\n" % (referer, request.get_full_path(), ua))
|
||||
return response
|
||||
|
||||
# Use ETags, if requested.
|
||||
|
@ -7,11 +7,12 @@ class XViewMiddleware(object):
|
||||
"""
|
||||
def process_view(self, request, view_func, view_args, view_kwargs):
|
||||
"""
|
||||
If the request method is HEAD and the IP is internal, quickly return
|
||||
with an x-header indicating the view function. This is used by the
|
||||
documentation module to lookup the view function for an arbitrary page.
|
||||
If the request method is HEAD and either the IP is internal or the
|
||||
user is a logged-in staff member, quickly return with an x-header
|
||||
indicating the view function. This is used by the documentation module
|
||||
to lookup the view function for an arbitrary page.
|
||||
"""
|
||||
if request.method == 'HEAD' and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
|
||||
if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff)):
|
||||
response = http.HttpResponse()
|
||||
response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__)
|
||||
return response
|
||||
|
@ -15,7 +15,7 @@ register = Library()
|
||||
|
||||
def addslashes(value):
|
||||
"Adds slashes - useful for passing strings to JavaScript, for example."
|
||||
return value.replace('"', '\\"').replace("'", "\\'")
|
||||
return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
|
||||
|
||||
def capfirst(value):
|
||||
"Capitalizes the first character of the value"
|
||||
|
@ -13,14 +13,18 @@ class CommentNode(Node):
|
||||
return ''
|
||||
|
||||
class CycleNode(Node):
|
||||
def __init__(self, cyclevars):
|
||||
def __init__(self, cyclevars, variable_name=None):
|
||||
self.cyclevars = cyclevars
|
||||
self.cyclevars_len = len(cyclevars)
|
||||
self.counter = -1
|
||||
self.variable_name = variable_name
|
||||
|
||||
def render(self, context):
|
||||
self.counter += 1
|
||||
return self.cyclevars[self.counter % self.cyclevars_len]
|
||||
value = self.cyclevars[self.counter % self.cyclevars_len]
|
||||
if self.variable_name:
|
||||
context[self.variable_name] = value
|
||||
return value
|
||||
|
||||
class DebugNode(Node):
|
||||
def render(self, context):
|
||||
@ -125,6 +129,8 @@ class IfChangedNode(Node):
|
||||
self._last_seen = None
|
||||
|
||||
def render(self, context):
|
||||
if context.has_key('forloop') and context['forloop']['first']:
|
||||
self._last_seen = None
|
||||
content = self.nodelist.render(context)
|
||||
if content != self._last_seen:
|
||||
firstloop = (self._last_seen == None)
|
||||
@ -385,7 +391,7 @@ def cycle(parser, token):
|
||||
raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
|
||||
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
|
||||
name = args[3]
|
||||
node = CycleNode(cyclevars)
|
||||
node = CycleNode(cyclevars, name)
|
||||
|
||||
if not hasattr(parser, '_namedCycleNodes'):
|
||||
parser._namedCycleNodes = {}
|
||||
|
@ -1319,13 +1319,16 @@ class DocTestRunner:
|
||||
__LINECACHE_FILENAME_RE = re.compile(r'<doctest '
|
||||
r'(?P<name>[\w\.]+)'
|
||||
r'\[(?P<examplenum>\d+)\]>$')
|
||||
def __patched_linecache_getlines(self, filename):
|
||||
def __patched_linecache_getlines(self, filename, module_globals=None):
|
||||
m = self.__LINECACHE_FILENAME_RE.match(filename)
|
||||
if m and m.group('name') == self.test.name:
|
||||
example = self.test.examples[int(m.group('examplenum'))]
|
||||
return example.source.splitlines(True)
|
||||
else:
|
||||
return self.save_linecache_getlines(filename)
|
||||
if sys.version_info < (2, 5, 0):
|
||||
return self.save_linecache_getlines(filename)
|
||||
else:
|
||||
return self.save_linecache_getlines(filename, module_globals)
|
||||
|
||||
def run(self, test, compileflags=None, out=None, clear_globs=True):
|
||||
"""
|
||||
|
@ -14,6 +14,9 @@ class MergeDict(object):
|
||||
pass
|
||||
raise KeyError
|
||||
|
||||
def __contains__(self, key):
|
||||
return self.has_key(key)
|
||||
|
||||
def get(self, key, default):
|
||||
try:
|
||||
return self[key]
|
||||
|
@ -3,12 +3,11 @@ Iterator based sre token scanner
|
||||
"""
|
||||
import sre_parse, sre_compile, sre_constants
|
||||
from sre_constants import BRANCH, SUBPATTERN
|
||||
from sre import VERBOSE, MULTILINE, DOTALL
|
||||
import re
|
||||
|
||||
__all__ = ['Scanner', 'pattern']
|
||||
|
||||
FLAGS = (VERBOSE | MULTILINE | DOTALL)
|
||||
FLAGS = (re.VERBOSE | re.MULTILINE | re.DOTALL)
|
||||
class Scanner(object):
|
||||
def __init__(self, lexicon, flags=FLAGS):
|
||||
self.actions = [None]
|
||||
|
@ -94,7 +94,8 @@ def compress_string(s):
|
||||
return zbuf.getvalue()
|
||||
|
||||
ustring_re = re.compile(u"([\u0080-\uffff])")
|
||||
def javascript_quote(s):
|
||||
|
||||
def javascript_quote(s, quote_double_quotes=False):
|
||||
|
||||
def fix(match):
|
||||
return r"\u%04x" % ord(match.group(1))
|
||||
@ -104,9 +105,12 @@ def javascript_quote(s):
|
||||
elif type(s) != unicode:
|
||||
raise TypeError, s
|
||||
s = s.replace('\\', '\\\\')
|
||||
s = s.replace('\r', '\\r')
|
||||
s = s.replace('\n', '\\n')
|
||||
s = s.replace('\t', '\\t')
|
||||
s = s.replace("'", "\\'")
|
||||
if quote_double_quotes:
|
||||
s = s.replace('"', '"')
|
||||
return str(ustring_re.sub(fix, s))
|
||||
|
||||
smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)')
|
||||
|
@ -4,7 +4,7 @@ from django.utils.html import escape
|
||||
from django.http import HttpResponseServerError, HttpResponseNotFound
|
||||
import os, re
|
||||
|
||||
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD')
|
||||
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
|
||||
|
||||
def linebreak_iter(template_source):
|
||||
yield 0
|
||||
|
@ -456,6 +456,10 @@ As a shortcut, you can use the convenient ``user_passes_test`` decorator::
|
||||
# ...
|
||||
my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view)
|
||||
|
||||
We are using this particular test as a relatively simple example, however be
|
||||
aware that if you just want to test if a permission is available to a user,
|
||||
you can use the ``permission_required()`` decorator described below.
|
||||
|
||||
Here's the same thing, using Python 2.4's decorator syntax::
|
||||
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
@ -488,6 +492,24 @@ Example in Python 2.4 syntax::
|
||||
def my_view(request):
|
||||
# ...
|
||||
|
||||
The permission_required decorator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since checking whether a user has a particular permission available to them is a
|
||||
relatively common operation, Django provides a shortcut for that particular
|
||||
case: the ``permission_required()`` decorator. Using this decorator, the
|
||||
earlier example can be written as::
|
||||
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
|
||||
def my_view(request):
|
||||
# ...
|
||||
|
||||
my_view = permission_required('polls.can_vote')(my_view)
|
||||
|
||||
Note that ``permission_required()`` also takes an optional ``login_url``
|
||||
parameter.
|
||||
|
||||
Limiting access to generic views
|
||||
--------------------------------
|
||||
|
||||
@ -677,7 +699,7 @@ timestamps.
|
||||
Messages are used by the Django admin after successful actions. For example,
|
||||
``"The poll Foo was created successfully."`` is a message.
|
||||
|
||||
The API is simple::
|
||||
The API is simple:
|
||||
|
||||
* To create a new message, use
|
||||
``user_obj.message_set.create(message='message_text')``.
|
||||
|
@ -247,18 +247,23 @@ Django tarball. It's our policy to make sure all tests pass at all times.
|
||||
|
||||
The tests cover:
|
||||
|
||||
* Models and the database API (``tests/testapp/models``).
|
||||
* The cache system (``tests/otherthests/cache.py``).
|
||||
* The ``django.utils.dateformat`` module (``tests/othertests/dateformat.py``).
|
||||
* Database typecasts (``tests/othertests/db_typecasts.py``).
|
||||
* The template system (``tests/othertests/templates.py`` and
|
||||
``tests/othertests/defaultfilters.py``).
|
||||
* ``QueryDict`` objects (``tests/othertests/httpwrappers.py``).
|
||||
* Markup template tags (``tests/othertests/markup.py``).
|
||||
* The ``django.utils.timesince`` module (``tests/othertests/timesince.py``).
|
||||
* Models and the database API (``tests/modeltests/``).
|
||||
* The cache system (``tests/regressiontests/cache.py``).
|
||||
* The ``django.utils.dateformat`` module (``tests/regressiontests/dateformat/``).
|
||||
* Database typecasts (``tests/regressiontests/db_typecasts/``).
|
||||
* The template system (``tests/regressiontests/templates/`` and
|
||||
``tests/regressiontests/defaultfilters/``).
|
||||
* ``QueryDict`` objects (``tests/regressiontests/httpwrappers/``).
|
||||
* Markup template tags (``tests/regressiontests/markup/``).
|
||||
|
||||
We appreciate any and all contributions to the test suite!
|
||||
|
||||
The Django tests all use the testing infrastructure that ships with Django for
|
||||
testing applications. See `Testing Django Applications`_ for an explanation of
|
||||
how to write new tests.
|
||||
|
||||
.. _Testing Django Applications: http://www.djangoproject.com/documentation/testing/
|
||||
|
||||
Running the unit tests
|
||||
----------------------
|
||||
|
||||
@ -268,10 +273,14 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
|
||||
|
||||
Yes, the unit tests need a settings module, but only for database connection
|
||||
info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``.
|
||||
You will also need a ``ROOT_URLCONF`` setting (it's value is ignored; it just
|
||||
needs to be present) and a ``SITE_ID`` setting (any integer value will do) in
|
||||
order for all the tests to pass.
|
||||
|
||||
The unit tests will not touch your database; they create a new database, called
|
||||
``django_test_db``, which is deleted when the tests are finished. This means
|
||||
your user account needs permission to execute ``CREATE DATABASE``.
|
||||
The unit tests will not touch your existing databases; they create a new
|
||||
database, called ``django_test_db``, which is deleted when the tests are
|
||||
finished. This means your user account needs permission to execute ``CREATE
|
||||
DATABASE``.
|
||||
|
||||
Requesting features
|
||||
===================
|
||||
|
@ -1140,7 +1140,7 @@ The pk lookup shortcut
|
||||
----------------------
|
||||
|
||||
For convenience, Django provides a ``pk`` lookup type, which stands for
|
||||
"primary_key". This is shorthand for "an exact lookup on the primary-key."
|
||||
"primary_key".
|
||||
|
||||
In the example ``Blog`` model, the primary key is the ``id`` field, so these
|
||||
three statements are equivalent::
|
||||
@ -1149,6 +1149,14 @@ three statements are equivalent::
|
||||
Blog.objects.get(id=14) # __exact is implied
|
||||
Blog.objects.get(pk=14) # pk implies id__exact
|
||||
|
||||
The use of ``pk`` isn't limited to ``__exact`` queries -- any query term
|
||||
can be combined with ``pk`` to perform a query on the primary key of a model::
|
||||
|
||||
# Get blogs entries with id 1, 4 and 7
|
||||
Blog.objects.filter(pk__in=[1,4,7])
|
||||
# Get all blog entries with id > 14
|
||||
Blog.objects.filter(pk__gt=14)
|
||||
|
||||
``pk`` lookups also work across joins. For example, these three statements are
|
||||
equivalent::
|
||||
|
||||
@ -1511,7 +1519,7 @@ Many-to-many relationships
|
||||
--------------------------
|
||||
|
||||
Both ends of a many-to-many relationship get automatic API access to the other
|
||||
end. The API works just as a "backward" one-to-many relationship. See _Backward
|
||||
end. The API works just as a "backward" one-to-many relationship. See Backward_
|
||||
above.
|
||||
|
||||
The only difference is in the attribute naming: The model that defines the
|
||||
|
@ -352,8 +352,9 @@ options.
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Inform django-admin that the user should NOT be prompted for any input. Useful if
|
||||
the django-admin script will be executed as an unattended, automated script.
|
||||
Inform django-admin that the user should NOT be prompted for any input. Useful
|
||||
if the django-admin script will be executed as an unattended, automated
|
||||
script.
|
||||
|
||||
--noreload
|
||||
----------
|
||||
@ -383,6 +384,19 @@ Verbosity determines the amount of notification and debug information that
|
||||
will be printed to the console. '0' is no output, '1' is normal output,
|
||||
and `2` is verbose output.
|
||||
|
||||
--adminmedia
|
||||
------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Example usage::
|
||||
django-admin.py manage.py --adminmedia=/tmp/new-admin-style/
|
||||
|
||||
Tell Django where to find the various stylesheets and Javascript files for the
|
||||
admin interface when running the development server. Normally these files are
|
||||
served out of the Django source tree, but since some designers change these
|
||||
files for their site, this option allows you to test against custom versions.
|
||||
|
||||
Extra niceties
|
||||
==============
|
||||
|
||||
|
@ -136,7 +136,7 @@ template::
|
||||
{% endblock %}
|
||||
|
||||
Before we get back to the problems with these naive set of views, let's go over
|
||||
some salient points of the above template::
|
||||
some salient points of the above template:
|
||||
|
||||
* Field "widgets" are handled for you: ``{{ form.field }}`` automatically
|
||||
creates the "right" type of widget for the form, as you can see with the
|
||||
@ -148,8 +148,8 @@ some salient points of the above template::
|
||||
If you must use tables, use tables. If you're a semantic purist, you can
|
||||
probably find better HTML than in the above template.
|
||||
|
||||
* To avoid name conflicts, the ``id``s of form elements take the form
|
||||
"id_*fieldname*".
|
||||
* To avoid name conflicts, the ``id`` values of form elements take the
|
||||
form "id_*fieldname*".
|
||||
|
||||
By creating a creation form we've solved problem number 3 above, but we still
|
||||
don't have any validation. Let's revise the validation issue by writing a new
|
||||
@ -481,6 +481,33 @@ the data being validated.
|
||||
Also, because consistency in user interfaces is important, we strongly urge you
|
||||
to put punctuation at the end of your validation messages.
|
||||
|
||||
When Are Validators Called?
|
||||
---------------------------
|
||||
|
||||
After a form has been submitted, Django first checks to see that all the
|
||||
required fields are present and non-empty. For each field that passes that
|
||||
test *and if the form submission contained data* for that field, all the
|
||||
validators for that field are called in turn. The emphasised portion in the
|
||||
last sentence is important: if a form field is not submitted (because it
|
||||
contains no data -- which is normal HTML behaviour), the validators are not
|
||||
run against the field.
|
||||
|
||||
This feature is particularly important for models using
|
||||
``models.BooleanField`` or custom manipulators using things like
|
||||
``forms.CheckBoxField``. If the checkbox is not selected, it will not
|
||||
contribute to the form submission.
|
||||
|
||||
If you would like your validator to *always* run, regardless of whether the
|
||||
field it is attached to contains any data, set the ``always_test`` attribute
|
||||
on the validator function. For example::
|
||||
|
||||
def my_custom_validator(field_data, all_data):
|
||||
# ...
|
||||
|
||||
my_custom_validator.always_test = True
|
||||
|
||||
This validator will always be executed for any field it is attached to.
|
||||
|
||||
Ready-made Validators
|
||||
---------------------
|
||||
|
||||
|
@ -543,7 +543,9 @@ The default value for the field.
|
||||
``editable``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
If ``False``, the field will not be editable in the admin. Default is ``True``.
|
||||
If ``False``, the field will not be editable in the admin or via form
|
||||
processing using the object's ``AddManipulator`` or ``ChangeManipulator``
|
||||
classes. Default is ``True``.
|
||||
|
||||
``help_text``
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -96,6 +96,21 @@ Django "ships" with a few included serializers:
|
||||
.. _json: http://json.org/
|
||||
.. _simplejson: http://undefined.org/python/#simplejson
|
||||
|
||||
Notes For Specific Serialization Formats
|
||||
----------------------------------------
|
||||
|
||||
json
|
||||
~~~~
|
||||
|
||||
If you are using UTF-8 (or any other non-ASCII encoding) data with the JSON
|
||||
serializer, you must pass ``ensure_ascii=False`` as a parameter to the
|
||||
``serialize()`` call. Otherwise the output will not be encoded correctly.
|
||||
|
||||
For example::
|
||||
|
||||
json_serializer = serializers.get_serializer("json")
|
||||
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
|
||||
|
||||
Writing custom serializers
|
||||
``````````````````````````
|
||||
|
||||
|
@ -596,6 +596,12 @@ Whether to prepend the "www." subdomain to URLs that don't have it. This is
|
||||
only used if ``CommonMiddleware`` is installed (see the `middleware docs`_).
|
||||
See also ``APPEND_SLASH``.
|
||||
|
||||
PROFANITIES_LIST
|
||||
----------------
|
||||
|
||||
A list of profanities that will trigger a validation error when the
|
||||
``hasNoProfanities`` validator is called.
|
||||
|
||||
ROOT_URLCONF
|
||||
------------
|
||||
|
||||
|
@ -763,17 +763,17 @@ will use the function's name as the tag name.
|
||||
Shortcut for simple tags
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Many template tags take a single argument -- a string or a template variable
|
||||
reference -- and return a string after doing some processing based solely on
|
||||
Many template tags take a number of arguments -- strings or a template variables
|
||||
-- and return a string after doing some processing based solely on
|
||||
the input argument and some external information. For example, the
|
||||
``current_time`` tag we wrote above is of this variety: we give it a format
|
||||
string, it returns the time as a string.
|
||||
|
||||
To ease the creation of the types of tags, Django provides a helper function,
|
||||
``simple_tag``. This function, which is a method of
|
||||
``django.template.Library``, takes a function that accepts one argument, wraps
|
||||
it in a ``render`` function and the other necessary bits mentioned above and
|
||||
registers it with the template system.
|
||||
``django.template.Library``, takes a function that accepts any number of
|
||||
arguments, wraps it in a ``render`` function and the other necessary bits
|
||||
mentioned above and registers it with the template system.
|
||||
|
||||
Our earlier ``current_time`` function could thus be written like this::
|
||||
|
||||
@ -789,11 +789,16 @@ In Python 2.4, the decorator syntax also works::
|
||||
...
|
||||
|
||||
A couple of things to note about the ``simple_tag`` helper function:
|
||||
* Only the (single) argument is passed into our function.
|
||||
* Checking for the required number of arguments, etc, has already been
|
||||
done by the time our function is called, so we don't need to do that.
|
||||
* The quotes around the argument (if any) have already been stripped away,
|
||||
so we just receive a plain string.
|
||||
* If the argument was a template variable, our function is passed the
|
||||
current value of the variable, not the variable itself.
|
||||
|
||||
When your template tag does not need access to the current context, writing a
|
||||
function to work with the input values and using the ``simple_tag`` helper is
|
||||
the easiest way to create a new tag.
|
||||
|
||||
Inclusion tags
|
||||
~~~~~~~~~~~~~~
|
||||
|
1
setup.py
1
setup.py
@ -26,6 +26,7 @@ setup(
|
||||
'media/js/*.js',
|
||||
'media/js/admin/*js'],
|
||||
'django.contrib.comments': ['templates/comments/*.html'],
|
||||
'django.contrib.sitemaps': ['templates/*.xml'],
|
||||
},
|
||||
scripts = ['django/bin/django-admin.py'],
|
||||
zip_safe = False,
|
||||
|
@ -86,6 +86,10 @@ DoesNotExist: Article matching query does not exist.
|
||||
>>> Article.objects.get(pk=1)
|
||||
<Article: Area woman programs in Python>
|
||||
|
||||
# pk can be used as a shortcut for the primary key name in any query
|
||||
>>> Article.objects.filter(pk__in=[1])
|
||||
[<Article: Area woman programs in Python>]
|
||||
|
||||
# Model instances of the same type and same ID are considered equal.
|
||||
>>> a = Article.objects.get(pk=1)
|
||||
>>> b = Article.objects.get(pk=1)
|
||||
|
@ -51,6 +51,10 @@ DoesNotExist: Employee matching query does not exist.
|
||||
>>> Employee.objects.get(employee_code__exact='ABC123')
|
||||
<Employee: Dan Jones>
|
||||
|
||||
# pk can be used as a substitute for the primary key.
|
||||
>>> Employee.objects.filter(pk__in=['ABC123','XYZ456'])
|
||||
[<Employee: Fran Bones>, <Employee: Dan Jones>]
|
||||
|
||||
# Fran got married and changed her last name.
|
||||
>>> fran = Employee.objects.get(pk='XYZ456')
|
||||
>>> fran.last_name = 'Jones'
|
||||
|
@ -15,6 +15,9 @@ r"""
|
||||
>>> addslashes('"double quotes" and \'single quotes\'')
|
||||
'\\"double quotes\\" and \\\'single quotes\\\''
|
||||
|
||||
>>> addslashes(r'\ : backslashes, too')
|
||||
'\\\\ : backslashes, too'
|
||||
|
||||
>>> capfirst('hello world')
|
||||
'Hello world'
|
||||
|
||||
|
@ -4,4 +4,5 @@ INSERT INTO initial_sql_regress_simple (name) VALUES ('Ringo');
|
||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('George');
|
||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('Miles O''Brien');
|
||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('Semicolon;Man');
|
||||
INSERT INTO initial_sql_regress_simple (name) VALUES ('This line has a Windows line ending');
|
||||
|
||||
|
@ -187,6 +187,7 @@ class Templates(unittest.TestCase):
|
||||
'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError),
|
||||
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
|
||||
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
|
||||
'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),
|
||||
|
||||
### EXCEPTIONS ############################################################
|
||||
|
||||
@ -304,6 +305,10 @@ class Templates(unittest.TestCase):
|
||||
'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
|
||||
'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
|
||||
'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
|
||||
'ifchanged04': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 2, 3), 'numx': (2, 2, 2)}, '122232'),
|
||||
'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'),
|
||||
'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'),
|
||||
'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'),
|
||||
|
||||
### IFEQUAL TAG ###########################################################
|
||||
'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
|
||||
|
Loading…
x
Reference in New Issue
Block a user