1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +00:00

sqlalchemy: Merged revisions 3832 to 3917 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@3918 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robin Munn 2006-10-24 07:49:37 +00:00
parent 1bb4fa2cb6
commit 0b059aa4ea
69 changed files with 3214 additions and 2269 deletions

View File

@ -64,6 +64,7 @@ answer newbie questions, and generally made Django that much better:
Ian Clelland <clelland@gmail.com>
crankycoder@gmail.com
Matt Croydon <http://www.postneo.com/>
dackze+django@gmail.com
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
Jason Davies (Esaj) <http://www.jasondavies.com/>
Alex Dedul
@ -74,6 +75,7 @@ answer newbie questions, and generally made Django that much better:
Jeremy Dunck <http://dunck.us/>
Andy Dustman <farcepest@gmail.com>
Clint Ecker
Enrico <rico.bl@gmail.com>
favo@exoweb.net
gandalf@owca.info
Baishampayan Ghose
@ -82,6 +84,7 @@ answer newbie questions, and generally made Django that much better:
Espen Grindhaug <http://grindhaug.org/>
Brant Harris
heckj@mac.com
Joel Heenan <joelh-django@planetjoel.com>
hipertracker@gmail.com
Ian Holsman <http://feh.holsman.net/>
Kieran Holland <http://www.kieranholland.com>
@ -95,6 +98,7 @@ answer newbie questions, and generally made Django that much better:
kilian <kilian.cavalotti@lip6.fr>
Sune Kirkeby <http://ibofobi.dk/>
Cameron Knight (ckknight)
Meir Kriheli <http://mksoft.co.il/>
Bruce Kroeze <http://coderseye.com/>
Joseph Kocherhans
konrad@gwu.edu
@ -103,7 +107,9 @@ answer newbie questions, and generally made Django that much better:
Eugene Lazutkin <http://lazutkin.com/blog/>
Jeong-Min Lee
Christopher Lenz <http://www.cmlenz.net/>
lerouxb@gmail.com
limodou
mattmcc
Martin Maney <http://www.chipy.org/Martin_Maney>
Manuzhai
Petar Marić
@ -115,6 +121,7 @@ answer newbie questions, and generally made Django that much better:
Eric Moritz <http://eric.themoritzfamily.com/>
Robin Munn <http://www.geekforgod.com/>
Nebojša Dorđević
Fraser Nevett <mail@nevett.org>
Sam Newman <http://www.magpiebrain.com/>
Neal Norwitz <nnorwitz@google.com>
oggie rob <oz.robharvey@gmail.com>
@ -142,6 +149,7 @@ answer newbie questions, and generally made Django that much better:
Radek Švarz <http://www.svarz.cz/translate/>
Swaroop C H <http://www.swaroopch.info>
Aaron Swartz <http://www.aaronsw.com/>
Tyson Tate <tyson@fallingbullets.com>
Tom Tobin
Tom Insam
Joe Topjian <http://joe.terrarum.net/geek/code/python/django/>

8
MANIFEST.in Normal file
View File

@ -0,0 +1,8 @@
include AUTHORS
include INSTALL
include LICENSE
recursive-include django/conf/locale *
recursive-include django/contrib/admin/templates
recursive-include django/contrib/admin/media
recursive-include django/contrib/comments/templates
recursive-include django/contrib/sitemaps/templates

View File

@ -1,16 +1,17 @@
"Daily cleanup file"
"""
Daily cleanup job.
Can be run as a cronjob to clean out old data from the database (only expired
sessions at the moment).
"""
from django.db import backend, connection, transaction
DOCUMENTATION_DIRECTORY = '/home/html/documentation/'
def clean_up():
# Clean up old database records
cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
(backend.quote_name('core_sessions'), backend.quote_name('expire_date')))
cursor.execute("DELETE FROM %s WHERE %s < NOW() - INTERVAL '1 week'" % \
(backend.quote_name('registration_challenges'), backend.quote_name('request_date')))
(backend.quote_name('django_session'), backend.quote_name('expire_date')))
transaction.commit_unless_managed()
if __name__ == "__main__":

View File

@ -56,6 +56,7 @@ LANGUAGES = (
('ja', gettext_noop('Japanese')),
('nl', gettext_noop('Dutch')),
('no', gettext_noop('Norwegian')),
('pl', gettext_noop('Polish')),
('pt-br', gettext_noop('Brazilian')),
('ro', gettext_noop('Romanian')),
('ru', gettext_noop('Russian')),
@ -223,10 +224,6 @@ YEAR_MONTH_FORMAT = 'F Y'
# http://www.djangoproject.com/documentation/templates/#now
MONTH_DAY_FORMAT = 'F j'
# Whether to enable Psyco, which optimizes Python code. Requires Psyco.
# http://psyco.sourceforge.net/
ENABLE_PSYCO = False
# Do you want to manage transactions manually?
# Hint: you really don't!
TRANSACTIONS_MANAGED = False
@ -274,8 +271,8 @@ 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']
# 'hasNoProfanities' validator. All of these should be in lowercase.
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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,13 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: Django-users Japan <django-ja@googlegroups.com>\n"
"POT-Creation-Date: 2006-05-02 23:06+0900\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-10-06 00:30+0900\n"
"PO-Revision-Date: 2006-05-08 13:39+0900\n"
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
"Language-Team: Japanese <django-ja@googlegroups.com>\n"
@ -61,50 +61,58 @@ msgstr "選択してクリック"
msgid "Clear all"
msgstr "全てクリア"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr "表示"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr "非表示"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "現在"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "時計"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "時間を選択"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "夜中"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "午前 6 時"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "正午"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "キャンセル"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "今日"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "カレンダー"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "昨日"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "明日"

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,109 @@
# Django 0.95
# Copyright (C) 2006 Django
# This file is distributed under the same license as the Django package.
# Bahadır Kandemir <bahadir@pardus.org.tr>, 2006.
#
msgid ""
msgstr ""
"Project-Id-Version: Django 0.95\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-09-30 01:31+0300\n"
"PO-Revision-Date: 2006-09-30 01:31+0300\n"
"Last-Translator: Bahadır Kandemir <bahadir@pardus.org.tr>\n"
"Language-Team: Bahadır Kandemir <bahadir@pardus.org.tr>\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
#, perl-format
msgid "Available %s"
msgstr "Mevcut %s"
#: contrib/admin/media/js/SelectFilter2.js:41
msgid "Choose all"
msgstr "Hepsini seç"
#: contrib/admin/media/js/SelectFilter2.js:46
msgid "Add"
msgstr "Ekle"
#: contrib/admin/media/js/SelectFilter2.js:48
msgid "Remove"
msgstr "Kaldır"
#: contrib/admin/media/js/SelectFilter2.js:53
#, perl-format
msgid "Chosen %s"
msgstr "Seçilen %s"
#: contrib/admin/media/js/SelectFilter2.js:54
msgid "Select your choice(s) and click "
msgstr "Seçiminizi yapın ve tıklayın "
#: contrib/admin/media/js/SelectFilter2.js:59
msgid "Clear all"
msgstr "Hepsini temizle"
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
msgid ""
"January February March April May June July August September October November "
"December"
msgstr "Ocak Şubat Mart Nisan Mayıs Haziran Temmuz Ağustos Eylül Ekim Kasım "
"Aralık"
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr "Pazar Pazartesi Salı Çarşamba Perşembe Cuma Cumartesi"
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr "P P S Ç P C C"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
msgid "Now"
msgstr "Şimdi"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
msgid "Clock"
msgstr "Saat"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
msgid "Choose a time"
msgstr "Saat seçin"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Midnight"
msgstr "Geceyarısı"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "6 a.m."
msgstr "Sabah 6"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "Noon"
msgstr "Öğle"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
msgid "Cancel"
msgstr "İptal"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
msgid "Today"
msgstr "Bugün"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
msgid "Calendar"
msgstr "Takvim"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
msgid "Yesterday"
msgstr "Dün"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
msgid "Tomorrow"
msgstr "Yarın"

View File

@ -8,7 +8,7 @@
<h1>{{ name }}</h1>
<h2 class="subhead">{{ summary|escape }}</h2>
<h2 class="subhead">{{ summary }}</h2>
<p>{{ body }}</p>

View File

@ -87,7 +87,7 @@ def staff_member_required(view_func):
# The user data is correct; log in the user in and continue.
else:
if user.is_staff:
if user.is_active and user.is_staff:
login(request, user)
# TODO: set last_login with an event.
user.last_login = datetime.datetime.now()

View File

@ -46,6 +46,7 @@ def createsuperuser(username=None, email=None, password=None):
if not username.isalnum():
sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
username = None
continue
try:
User.objects.get(username=username)
except User.DoesNotExist:

View File

@ -29,8 +29,8 @@ login_required.__doc__ = (
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.
Decorator for views that checks whether a user has a particular permission
enabled, redirecting to the log-in page if necessary.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)

View File

@ -13,7 +13,7 @@ class UserCreationForm(forms.Manipulator):
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
validator_list=[validators.AlwaysMatchesOtherField('password1', "The two password fields didn't match.")]),
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
)
def isValidUsername(self, field_data, all_data):
@ -21,7 +21,7 @@ class UserCreationForm(forms.Manipulator):
User.objects.get(username=field_data)
except User.DoesNotExist:
return
raise validators.ValidationError, 'A user with that username already exists.'
raise validators.ValidationError, _('A user with that username already exists.')
def save(self, new_data):
"Creates the user."
@ -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 account. 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"

View File

@ -216,6 +216,8 @@ class User(models.Model):
def has_module_perms(self, app_label):
"Returns True if the user has any permissions in the given app label."
if not self.is_active:
return False
if self.is_superuser:
return True
return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">
{% spaceless %}
{% for url in urlset %}
<url>
<loc>{{ url.location|escape }}</loc>
@ -8,4 +9,5 @@
{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
</url>
{% endfor %}
{% endspaceless %}
</urlset>

View File

@ -1,8 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.google.com/schemas/sitemap/0.84">
{% for location in sitemaps %}
<sitemap>
<loc>{{ location|escape }}</loc>
</sitemap>
{% endfor %}
{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %}
</sitemapindex>

View File

@ -48,7 +48,7 @@ class BaseHandler(object):
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.insert(0, mw_instance.process_exception)
def get_response(self, path, request):
def get_response(self, request):
"Returns an HttpResponse object for the given HttpRequest"
from django.core import exceptions, urlresolvers
from django.core.mail import mail_admins
@ -62,7 +62,7 @@ class BaseHandler(object):
resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF)
try:
callback, callback_args, callback_kwargs = resolver.resolve(path)
callback, callback_args, callback_kwargs = resolver.resolve(request.path)
# Apply view middleware
for middleware_method in self._view_middleware:
@ -89,7 +89,8 @@ class BaseHandler(object):
return response
except http.Http404, e:
if settings.DEBUG:
return self.get_technical_error_response(request, is404=True, exception=e)
from django.views import debug
return debug.technical_404_response(request, e)
else:
callback, param_dict = resolver.resolve404()
return callback(request, **param_dict)
@ -99,39 +100,23 @@ class BaseHandler(object):
pass # See http://code.djangoproject.com/ticket/1023
except: # Handle everything else, including SuspiciousOperation, etc.
if settings.DEBUG:
return self.get_technical_error_response(request)
from django.views import debug
return debug.technical_500_response(request, *sys.exc_info())
else:
# Get the exception info now, in case another exception is thrown later.
exc_info = sys.exc_info()
receivers = dispatcher.send(signal=signals.got_request_exception)
# When DEBUG is False, send an error message to the admins.
subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', ''))
subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
try:
request_repr = repr(request)
except:
request_repr = "Request repr() unavailable"
message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
mail_admins(subject, message, fail_silently=True)
return self.get_friendly_error_response(request, resolver)
def get_friendly_error_response(self, request, resolver):
"""
Returns an HttpResponse that displays a PUBLIC error message for a
fundamental error.
"""
callback, param_dict = resolver.resolve500()
return callback(request, **param_dict)
def get_technical_error_response(self, request, is404=False, exception=None):
"""
Returns an HttpResponse that displays a TECHNICAL error message for a
fundamental error.
"""
from django.views import debug
if is404:
return debug.technical_404_response(request, exception)
else:
return debug.technical_500_response(request, *sys.exc_info())
# Return an HttpResponse that displays a friendly error message.
callback, param_dict = resolver.resolve500()
return callback(request, **param_dict)
def _get_traceback(self, exc_info=None):
"Helper function to return the traceback as a string"

View File

@ -102,7 +102,7 @@ class ModPythonRequest(http.HttpRequest):
'REQUEST_METHOD': self._req.method,
'SCRIPT_NAME': None, # Not supported
'SERVER_NAME': self._req.server.server_hostname,
'SERVER_PORT': self._req.server.port,
'SERVER_PORT': str(self._req.connection.local_addr[1]),
'SERVER_PROTOCOL': self._req.protocol,
'SERVER_SOFTWARE': 'mod_python'
}
@ -139,10 +139,6 @@ class ModPythonHandler(BaseHandler):
# that use settings now can work
from django.conf import settings
if settings.ENABLE_PSYCO:
import psyco
psyco.profile()
# if we need to set up middleware, now that settings works we can do it now.
if self._request_middleware is None:
self.load_middleware()
@ -150,7 +146,7 @@ class ModPythonHandler(BaseHandler):
dispatcher.send(signal=signals.request_started)
try:
request = ModPythonRequest(req)
response = self.get_response(req.uri, request)
response = self.get_response(request)
# Apply response middleware
for middleware_method in self._response_middleware:
@ -160,23 +156,20 @@ class ModPythonHandler(BaseHandler):
dispatcher.send(signal=signals.request_finished)
# Convert our custom HttpResponse object back into the mod_python req.
populate_apache_request(response, req)
return 0 # mod_python.apache.OK
req.content_type = response['Content-Type']
for key, value in response.headers.items():
if key != 'Content-Type':
req.headers_out[key] = value
for c in response.cookies.values():
req.headers_out.add('Set-Cookie', c.output(header=''))
req.status = response.status_code
try:
for chunk in response:
req.write(chunk)
finally:
response.close()
def populate_apache_request(http_response, mod_python_req):
"Populates the mod_python request object with an HttpResponse"
mod_python_req.content_type = http_response['Content-Type']
for key, value in http_response.headers.items():
if key != 'Content-Type':
mod_python_req.headers_out[key] = value
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
try:
for chunk in http_response:
mod_python_req.write(chunk)
finally:
http_response.close()
return 0 # mod_python.apache.OK
def handler(req):
# mod_python hooks into this function.

View File

@ -74,7 +74,7 @@ class WSGIRequest(http.HttpRequest):
def __init__(self, environ):
self.environ = environ
self.path = environ['PATH_INFO']
self.META = environ
self.META = environ
self.method = environ['REQUEST_METHOD'].upper()
def __repr__(self):
@ -174,10 +174,6 @@ class WSGIHandler(BaseHandler):
def __call__(self, environ, start_response):
from django.conf import settings
if settings.ENABLE_PSYCO:
import psyco
psyco.profile()
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
if self._request_middleware is None:
@ -186,7 +182,7 @@ class WSGIHandler(BaseHandler):
dispatcher.send(signal=signals.request_started)
try:
request = WSGIRequest(environ)
response = self.get_response(request.path, request)
response = self.get_response(request)
# Apply response middleware
for middleware_method in self._response_middleware:

View File

@ -103,7 +103,6 @@ def get_sql_create(app):
known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
pending_references = {}
for model in app_models:
output, references = _get_sql_model_create(model, known_models)
final_output.extend(output)
@ -147,7 +146,7 @@ def _get_sql_model_create(model, known_models=set()):
table_output = []
pending_references = {}
for f in opts.fields:
if isinstance(f, models.ForeignKey):
if isinstance(f, (models.ForeignKey, models.OneToOneField)):
rel_field = f.rel.get_related_field()
data_type = get_rel_data_type(rel_field)
else:
@ -398,32 +397,39 @@ get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting Postg
get_sql_sequence_reset.args = APP_ARGS
def get_sql_indexes(app):
"Returns a list of the CREATE INDEX SQL statements for the given app."
from django.db import backend, models
"Returns a list of the CREATE INDEX SQL statements for all models in the given app."
from django.db import models
output = []
for model in models.get_models(app):
for f in model._meta.fields:
if f.db_index:
unique = f.unique and 'UNIQUE ' or ''
output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
)
output.extend(get_sql_indexes_for_model(model))
return output
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
get_sql_indexes.args = APP_ARGS
def get_sql_indexes_for_model(model):
"Returns the CREATE INDEX SQL statements for a single model"
from django.db import backend
output = []
for f in model._meta.fields:
if f.db_index:
unique = f.unique and 'UNIQUE ' or ''
output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
)
return output
def get_sql_all(app):
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app)
get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
get_sql_all.args = APP_ARGS
def syncdb(verbosity=2, interactive=True):
def syncdb(verbosity=1, interactive=True):
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
from django.db import connection, transaction, models, get_creation_module
from django.db.models import signals
@ -457,21 +463,21 @@ def syncdb(verbosity=2, interactive=True):
pending_references = {}
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
model_list = models.get_models(app)
for model in model_list:
# Create the model's database table, if it doesn't already exist.
if verbosity >= 2:
print "Processing %s.%s model" % (app_name, model._meta.object_name)
if model._meta.db_table in table_list:
continue
sql, references = _get_sql_model_create(model, seen_models)
seen_models.add(model)
created_models.add(model)
for refto, refs in references.items():
try:
pending_references[refto].extend(refs)
except KeyError:
pending_references[refto] = refs
pending_references.setdefault(refto, []).extend(refs)
sql.extend(_get_sql_for_pending_references(model, pending_references))
if verbosity >= 2:
if verbosity >= 1:
print "Creating table %s" % model._meta.db_table
for statement in sql:
cursor.execute(statement)
@ -482,7 +488,7 @@ def syncdb(verbosity=2, interactive=True):
sql = _get_many_to_many_sql_for_model(model)
if sql:
if verbosity >= 2:
print "Creating many-to-many tables for %s model" % model.__name__
print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
for statement in sql:
cursor.execute(statement)
@ -491,6 +497,9 @@ def syncdb(verbosity=2, interactive=True):
# Send the post_syncdb signal, so individual apps can do whatever they need
# to do at this point.
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
if verbosity >= 2:
print "Running post-sync handlers for application", app_name
dispatcher.send(signal=signals.post_syncdb, sender=app,
app=app, created_models=created_models,
verbosity=verbosity, interactive=interactive)
@ -501,18 +510,37 @@ def syncdb(verbosity=2, interactive=True):
if model in created_models:
initial_sql = get_sql_initial_data_for_model(model)
if initial_sql:
if verbosity >= 2:
print "Installing initial data for %s model" % model._meta.object_name
if verbosity >= 1:
print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name)
try:
for sql in initial_sql:
cursor.execute(sql)
except Exception, e:
sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \
(model._meta.object_name, e))
sys.stderr.write("Failed to install initial SQL data for %s.%s model: %s" % \
(app_name, model._meta.object_name, e))
transaction.rollback_unless_managed()
else:
transaction.commit_unless_managed()
# Install SQL indicies for all newly created models
for app in models.get_apps():
app_name = app.__name__.split('.')[-2]
for model in models.get_models(app):
if model in created_models:
index_sql = get_sql_indexes_for_model(model)
if index_sql:
if verbosity >= 1:
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
try:
for sql in index_sql:
cursor.execute(sql)
except Exception, e:
sys.stderr.write("Failed to install index for %s.%s model: %s" % \
(app_name, model._meta.object_name, e))
transaction.rollback_unless_managed()
else:
transaction.commit_unless_managed()
syncdb.args = ''
def get_admin_index(app):
@ -596,7 +624,7 @@ The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
install.args = APP_ARGS
def reset(app):
def reset(app, interactive=True):
"Executes the equivalent of 'get_sql_reset' in the current database."
from django.db import connection, transaction
app_name = app.__name__.split('.')[-2]
@ -607,21 +635,25 @@ def reset(app):
_check_for_validation_errors(app)
sql_list = get_sql_reset(app)
confirm = raw_input("""
if interactive:
confirm = raw_input("""
You have requested a database reset.
This will IRREVERSIBLY DESTROY any data in your database.
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: """)
else:
confirm = 'yes'
if confirm == 'yes':
try:
cursor = connection.cursor()
for sql in sql_list:
cursor.execute(sql)
except Exception, e:
sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
sys.stderr.write(style.ERROR("""Error: %s couldn't be reset. Possible reasons:
* The database isn't running or isn't configured correctly.
* At least one of the database tables already exists.
* At least one of the database tables doesn't exist.
* The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
@ -820,7 +852,8 @@ def get_validation_errors(outfile, app=None):
validates all models of all installed apps. Writes errors, if any, to outfile.
Returns number of errors.
"""
from django.db import models
from django.conf import settings
from django.db import models, connection
from django.db.models.loading import get_app_errors
from django.db.models.fields.related import RelatedObject
@ -862,6 +895,12 @@ def get_validation_errors(outfile, app=None):
if f.db_index not in (None, True, False):
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
# Check that maxlength <= 255 if using older MySQL versions.
if settings.DATABASE_ENGINE == 'mysql':
db_version = connection.get_server_version()
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
# Check to see if the related field will clash with any
# existing fields, m2m fields, m2m related objects or related objects
if f.rel:
@ -1169,7 +1208,7 @@ def runfcgi(args):
runfastcgi(args)
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
def test(verbosity, app_labels):
def test(app_labels, verbosity=1):
"Runs the test suite for the specified applications"
from django.conf import settings
from django.db.models import get_app, get_apps
@ -1271,10 +1310,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
help='Tells Django to NOT prompt the user for input of any kind.')
parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
help='Tells Django to NOT use the auto-reloader when running the development server.')
parser.add_option('--verbosity', action='store', dest='verbosity', default='2',
parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
type='choice', choices=['0', '1', '2'],
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.'),
parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'),
options, args = parser.parse_args(argv[1:])
@ -1320,7 +1359,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
parser.print_usage_and_exit()
elif action == 'test':
try:
action_mapping[action](int(options.verbosity), args[1:])
action_mapping[action](args[1:], int(options.verbosity))
except IndexError:
parser.print_usage_and_exit()
elif action in ('startapp', 'startproject'):
@ -1354,7 +1393,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("BEGIN;")
for mod in mod_list:
output = action_mapping[action](mod)
if action == 'reset':
output = action_mapping[action](mod, options.interactive)
else:
output = action_mapping[action](mod)
if output:
print '\n'.join(output)
if action not in NO_SQL_TRANSACTION:

View File

@ -594,7 +594,7 @@ 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, media_dir = None):
def __init__(self, application, media_dir=None):
from django.conf import settings
self.application = application
if not media_dir:

View File

@ -15,7 +15,8 @@ class Resolver404(Http404):
pass
class NoReverseMatch(Exception):
pass
# Don't make this raise an error when used in a template.
silent_variable_failure = True
def get_mod_func(callback):
# Converts 'django.views.news.stories.story_detail' to

View File

@ -249,7 +249,7 @@ def hasNoProfanities(field_data, all_data):
Watch your mouth! The words "f--k" and "s--t" are not allowed here.
"""
field_data = field_data.lower() # normalize
words_seen = [w for w in settings.PROFANITIES_LIST if field_data.find(w) > -1]
words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data]
if words_seen:
from django.utils.text import get_text_list
plural = len(words_seen) > 1
@ -377,7 +377,7 @@ class IsValidFloat(object):
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) > (max_allowed_length - 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 - 1)) or ('.' in data and len(data) > (max_allowed_length - (self.decimal_places - len(data.split('.')[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:

View File

@ -13,6 +13,7 @@ except ImportError, e:
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
import types
import re
DatabaseError = Database.DatabaseError
@ -24,6 +25,12 @@ django_conversions.update({
FIELD_TYPE.TIME: util.typecast_time,
})
# This should match the numerical portion of the version numbers (we can treat
# versions like 5.0.24 and 5.0.24a as the same). Based on the list of version
# at http://dev.mysql.com/doc/refman/4.1/en/news.html and
# http://dev.mysql.com/doc/refman/5.0/en/news.html .
server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
# This is an extra debug layer over MySQL queries, to display warnings.
# It's only used when DEBUG=True.
class MysqlDebugWrapper:
@ -61,6 +68,7 @@ class DatabaseWrapper(local):
def __init__(self):
self.connection = None
self.queries = []
self.server_version = None
def _valid_connection(self):
if self.connection is not None:
@ -110,6 +118,16 @@ class DatabaseWrapper(local):
self.connection.close()
self.connection = None
def get_server_version(self):
if not self.server_version:
if not self._valid_connection():
self.cursor()
m = server_version_re.match(self.connection.get_server_info())
if not m:
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
self.server_version = tuple([int(x) for x in m.groups()])
return self.server_version
supports_constraints = True
def quote_name(name):

View File

@ -5,6 +5,7 @@ from django.core import validators
from django import forms
from django.core.exceptions import ObjectDoesNotExist
from django.utils.functional import curry
from django.utils.itercompat import tee
from django.utils.text import capfirst
from django.utils.translation import gettext, gettext_lazy
import datetime, os, time
@ -80,7 +81,7 @@ class Field(object):
self.prepopulate_from = prepopulate_from
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
self.unique_for_year = unique_for_year
self.choices = choices or []
self._choices = choices or []
self.radio_admin = radio_admin
self.help_text = help_text
self.db_column = db_column
@ -324,6 +325,14 @@ class Field(object):
def bind(self, fieldmapping, original, bound_field_class):
return bound_field_class(self, fieldmapping, original)
def _get_choices(self):
if hasattr(self._choices, 'next'):
choices, self._choices = tee(self._choices)
return choices
else:
return self._choices
choices = property(_get_choices)
class AutoField(Field):
empty_strings_allowed = False
def __init__(self, *args, **kwargs):
@ -367,8 +376,8 @@ class BooleanField(Field):
def to_python(self, value):
if value in (True, False): return value
if value in ('t', 'True'): return True
if value in ('f', 'False'): return False
if value in ('t', 'True', '1'): return True
if value in ('f', 'False', '0'): return False
raise validators.ValidationError, gettext("This value must be either True or False.")
def get_manipulator_field_objs(self):

View File

@ -618,7 +618,7 @@ class ManyToManyField(RelatedField, Field):
msg = gettext_lazy('Separate multiple IDs with commas.')
else:
msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
self.help_text = string_concat(self.help_text, msg)
self.help_text = string_concat(self.help_text, ' ', msg)
def get_manipulator_field_objs(self):
if self.rel.raw_id_admin:

View File

@ -177,7 +177,7 @@ class AutomaticManipulator(forms.Manipulator):
# case, because they'll be dealt with later.
if f == related.field:
param = getattr(new_object, related.field.rel.field_name)
param = getattr(new_object, related.field.rel.get_related_field().attname)
elif (not self.change) and isinstance(f, AutoField):
param = None
elif self.change and (isinstance(f, FileField) or not child_follow.get(f.name, None)):
@ -215,7 +215,10 @@ 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:
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=rel_new_data[f.attname]))
new_value = rel_new_data[f.attname]
if f.rel.raw_id_admin:
new_value = new_value[0]
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value))
if self.change:
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
@ -300,7 +303,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
pass
else:
raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list(field_name_list[1:], 'and')}
{'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], 'and')}
def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data):
from django.db.models.fields.related import ManyToOneRel

View File

@ -707,30 +707,35 @@ def parse_lookup(kwarg_items, opts):
joins, where, params = SortedDict(), [], []
for kwarg, value in kwarg_items:
if value is not None:
path = kwarg.split(LOOKUP_SEPARATOR)
# 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. 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'
path.append(None)
elif len(path) == 0 or lookup_type not in QUERY_TERMS:
path.append(lookup_type)
lookup_type = 'exact'
path = kwarg.split(LOOKUP_SEPARATOR)
# 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. 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'
path.append(None)
elif len(path) == 0 or lookup_type not in QUERY_TERMS:
path.append(lookup_type)
lookup_type = 'exact'
if len(path) < 1:
raise TypeError, "Cannot parse keyword query %r" % kwarg
if len(path) < 1:
raise TypeError, "Cannot parse keyword query %r" % kwarg
if value is None:
# Interpret '__exact=None' as the sql '= NULL'; otherwise, reject
# all uses of None as a query value.
if lookup_type != 'exact':
raise ValueError, "Cannot use None as a query value"
joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
joins.update(joins2)
where.extend(where2)
params.extend(params2)
joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None)
joins.update(joins2)
where.extend(where2)
params.extend(params2)
return joins, where, params
class FieldFound(Exception):

View File

@ -54,6 +54,7 @@ class Manipulator(object):
def get_validation_errors(self, new_data):
"Returns dictionary mapping field_names to error-message lists"
errors = {}
self.prepare(new_data)
for field in self.fields:
errors.update(field.get_validation_errors(new_data))
val_name = 'validate_%s' % field.field_name
@ -638,7 +639,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
if str(value) in str_data_list:
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>' % \
output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \
(self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
self.get_id() + escape(value), choice))
output.append('</ul>')

View File

@ -2,6 +2,7 @@ from django.conf import settings
from django import http
from django.core.mail import mail_managers
import md5
import re
class CommonMiddleware(object):
"""
@ -61,12 +62,12 @@ class CommonMiddleware(object):
# send a note to the managers.
domain = http.get_host(request)
referer = request.META.get('HTTP_REFERER', None)
is_internal = referer and (domain in referer)
is_internal = _is_internal_request(domain, 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>')
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\nUser Agent: %s\n" % (referer, request.get_full_path(), ua))
"Referrer: %s\nRequested URL: %s\nUser agent: %s\n" % (referer, request.get_full_path(), ua))
return response
# Use ETags, if requested.
@ -88,3 +89,8 @@ def _is_ignorable_404(uri):
if uri.endswith(end):
return True
return False
def _is_internal_request(domain, referer):
"Return true if the referring URL is the same domain as the current request"
# Different subdomains are treated as different domains.
return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer)

View File

@ -532,7 +532,7 @@ class FilterExpression(object):
constant_arg, i18n_arg, var_arg = match.group("constant_arg", "i18n_arg", "var_arg")
if i18n_arg:
args.append((False, _(i18n_arg.replace(r'\"', '"'))))
elif constant_arg:
elif constant_arg is not None:
args.append((False, constant_arg.replace(r'\"', '"')))
elif var_arg:
args.append((True, var_arg))

View File

@ -8,7 +8,7 @@ from django.utils.functional import curry
class ClientHandler(BaseHandler):
"""
A HTTP Handler that can be used for testing purposes.
A HTTP Handler that can be used for testing purposes.
Uses the WSGI interface to compose requests, but returns
the raw HttpResponse object
"""
@ -24,7 +24,7 @@ class ClientHandler(BaseHandler):
dispatcher.send(signal=signals.request_started)
try:
request = WSGIRequest(environ)
response = self.get_response(request.path, request)
response = self.get_response(request)
# Apply response middleware
for middleware_method in self._response_middleware:
@ -32,7 +32,7 @@ class ClientHandler(BaseHandler):
finally:
dispatcher.send(signal=signals.request_finished)
return response
def store_rendered_templates(store, signal, sender, template, context):
@ -44,7 +44,7 @@ def encode_multipart(boundary, data):
"""
A simple method for encoding multipart POST data from a dictionary of
form values.
The key will be used as the form data name; the value will be transmitted
as content. If the value is a file, the contents of the file will be sent
as an application/octet-stream; otherwise, str(value) will be sent.
@ -69,7 +69,7 @@ def encode_multipart(boundary, data):
'',
str(value)
])
lines.extend([
'--' + boundary + '--',
'',
@ -78,8 +78,8 @@ def encode_multipart(boundary, data):
class Client:
"""
A class that can act as a client for testing purposes.
A class that can act as a client for testing purposes.
It allows the user to compose GET and POST requests, and
obtain the response that the server gave to those requests.
The server Response objects are annotated with the details
@ -88,7 +88,7 @@ class Client:
Client objects are stateful - they will retain cookie (and
thus session) details for the lifetime of the Client instance.
This is not intended as a replacement for Twill/Selenium or
the like - it is here to allow testing against the
contexts and templates produced by a view, rather than the
@ -98,10 +98,10 @@ class Client:
self.handler = ClientHandler()
self.defaults = defaults
self.cookie = SimpleCookie()
def request(self, **request):
"""
The master request method. Composes the environment dictionary
The master request method. Composes the environment dictionary
and passes to the handler, returning the result of the handler.
Assumes defaults for the query environment, which can be overridden
using the arguments to the request.
@ -112,24 +112,24 @@ class Client:
'PATH_INFO': '/',
'QUERY_STRING': '',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': None,
'SCRIPT_NAME': None,
'SERVER_NAME': 'testserver',
'SERVER_PORT': 80,
'SERVER_PROTOCOL': 'HTTP/1.1',
}
}
environ.update(self.defaults)
environ.update(request)
environ.update(request)
# Curry a data dictionary into an instance of
# the template renderer callback function
data = {}
on_template_render = curry(store_rendered_templates, data)
dispatcher.connect(on_template_render, signal=signals.template_rendered)
response = self.handler(environ)
# Add any rendered template detail to the response
# If there was only one template rendered (the most likely case),
# If there was only one template rendered (the most likely case),
# flatten the list to a single element
for detail in ('template', 'context'):
if data.get(detail):
@ -139,12 +139,12 @@ class Client:
setattr(response, detail, data[detail])
else:
setattr(response, detail, None)
if response.cookies:
self.cookie.update(response.cookies)
return response
def get(self, path, data={}, **extra):
"Request a response from the server using GET."
r = {
@ -155,12 +155,12 @@ class Client:
'REQUEST_METHOD': 'GET',
}
r.update(extra)
return self.request(**r)
def post(self, path, data={}, **extra):
"Request a response from the server using POST."
BOUNDARY = 'BoUnDaRyStRiNg'
encoded = encode_multipart(BOUNDARY, data)
@ -173,25 +173,25 @@ class Client:
'wsgi.input': stream,
}
r.update(extra)
return self.request(**r)
def login(self, path, username, password, **extra):
"""
A specialized sequence of GET and POST to log into a view that
is protected by a @login_required access decorator.
path should be the URL of the page that is login protected.
Returns the response from GETting the requested URL after
Returns the response from GETting the requested URL after
login is complete. Returns False if login process failed.
"""
# First, GET the page that is login protected.
# First, GET the page that is login protected.
# This page will redirect to the login page.
response = self.get(path)
if response.status_code != 302:
return False
login_path, data = response['Location'].split('?')
next = data.split('=')[1]
@ -199,7 +199,7 @@ class Client:
response = self.get(login_path, **extra)
if response.status_code != 200:
return False
# Last, POST the login data.
form_data = {
'username': username,

View File

@ -0,0 +1,31 @@
"""
Providing iterator functions that are not in all version of Python we support.
Where possible, we try to use the system-native version and only fall back to
these implementations if necessary.
"""
import itertools
def compat_tee(iterable):
"""Return two independent iterators from a single iterable.
Based on http://www.python.org/doc/2.3.5/lib/itertools-example.html
"""
# Note: Using a dictionary and a list as the default arguments here is
# deliberate and safe in this instance.
def gen(next, data={}, cnt=[0]):
dpop = data.pop
for i in itertools.count():
if i == cnt[0]:
item = data[i] = next()
cnt[0] += 1
else:
item = dpop(i)
yield item
next = iter(iterable).next
return gen(next), gen(next)
if hasattr(itertools, 'tee'):
tee = itertools.tee
else:
tee = compat_tee

View File

@ -102,7 +102,7 @@ def update_object(request, model, object_id=None, slug=None,
except ObjectDoesNotExist:
raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs)
manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.name), follow=follow)
manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow)
if request.POST:
new_data = request.POST.copy()
@ -142,7 +142,7 @@ def update_object(request, model, object_id=None, slug=None,
else:
c[key] = value
response = HttpResponse(t.render(c))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.name))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
return response
def delete_object(request, model, post_delete_redirect,
@ -196,5 +196,5 @@ def delete_object(request, model, post_delete_redirect,
else:
c[key] = value
response = HttpResponse(t.render(c))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.name))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
return response

View File

@ -82,7 +82,7 @@ There are also a few styles for styling text.
.help
This is a custom class for blocks of inline help text explaining the
function of form elements. It makes text smaller and gray, and when applied
to ``p`` elements withing ``.form-row`` elements (see Form Styles below),
to ``p`` elements within ``.form-row`` elements (see Form Styles below),
it will offset the text to align with the form field. Use this for help
text, instead of ``small quiet``. It works on other elements, but try to
put the class on a ``p`` whenever you can.
@ -170,4 +170,4 @@ Labels
Form labels should always precede the field, except in the case
of checkboxes and radio buttons, where the ``input`` should come first. Any
explanation or help text should follow the ``label`` in a ``p`` with class
``.help``.
``.help``.

View File

@ -6,7 +6,7 @@ Since keeping multiple authentication databases in sync is a common problem when
dealing with Apache, you can configuring Apache to authenticate against Django's
`authentication system`_ directly. For example, you could:
* Serve media files directly from Apache only to authenticated users.
* Serve static/media files directly from Apache only to authenticated users.
* Authenticate access to a Subversion_ repository against Django users with
a certain permission.

View File

@ -82,7 +82,7 @@ that 90% of Django can be considered forwards-compatible at this point.
That said, these APIs should *not* be considered stable, and are likely to
change:
- `Forms and validation`_ will most likely be compeltely rewritten to
- `Forms and validation`_ will most likely be completely rewritten to
deemphasize Manipulators in favor of validation-aware models.
- `Serialization`_ is under heavy development; changes are likely.
@ -91,7 +91,7 @@ change:
API changes may be necessary.
- Generic relations will most likely be moved out of core and into the
content-types contrib package to avoid core dependacies on optional
content-types contrib package to avoid core dependancies on optional
components.
- The comments framework, which is yet undocumented, will likely get a complete

View File

@ -66,8 +66,8 @@ Fields
long and can contain any character. See the "Passwords" section below.
* ``is_staff`` -- Boolean. Designates whether this user can access the
admin site.
* ``is_active`` -- Boolean. Designates whether this user can log into the
Django admin. Set this to ``False`` instead of deleting accounts.
* ``is_active`` -- Boolean. Designates whether this account can be used
to log in. Set this flag to ``False`` instead of deleting accounts.
* ``is_superuser`` -- Boolean. Designates that this user has all permissions
without explicitly assigning them.
* ``last_login`` -- A datetime of the user's last login. Is set to the
@ -99,7 +99,9 @@ custom methods:
should prefer using ``is_authenticated()`` to this method.
* ``is_authenticated()`` -- Always returns ``True``. This is a way to
tell if the user has been authenticated.
tell if the user has been authenticated. This does not imply any
permissions, and doesn't check if the user is active - it only indicates
that the user has provided a valid username and password.
* ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``,
with a space in between.
@ -120,13 +122,16 @@ custom methods:
* ``has_perm(perm)`` -- Returns ``True`` if the user has the specified
permission, where perm is in the format ``"package.codename"``.
If the user is inactive, this method will always return ``False``.
* ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the
specified permissions, where each perm is in the format
``"package.codename"``.
``"package.codename"``. If the user is inactive, this method will
always return ``False``.
* ``has_module_perms(package_name)`` -- Returns ``True`` if the user has
any permissions in the given package (the Django app label).
If the user is inactive, this method will always return ``False``.
* ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in
the user's queue and deletes the messages from the queue.
@ -283,7 +288,10 @@ password is invalid, ``authenticate()`` returns ``None``. Example::
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
print "You provided a correct username and password!"
if user.is_active:
print "You provided a correct username and password!"
else:
print "Your account has been disabled!"
else:
print "Your username and password were incorrect."
@ -301,10 +309,13 @@ This example shows how you might use both ``authenticate()`` and ``login()``::
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an error message.
# Return an 'invalid login' error message.
How to log a user out
---------------------
@ -456,9 +467,9 @@ 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.
We're using this particular test as a relatively simple example. However, if
you just want to test whether a permission is available to a user, you can use
the ``permission_required()`` decorator, described later in this document.
Here's the same thing, using Python 2.4's decorator syntax::
@ -495,20 +506,30 @@ Example in Python 2.4 syntax::
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::
**New in Django development version**
It's a relatively common task to check whether a user has a particular
permission. For that reason, Django provides a shortcut for that 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.
parameter. Example::
from django.contrib.auth.decorators import permission_required
def my_view(request):
# ...
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
As in the ``login_required`` decorator, ``login_url`` defaults to
``'/accounts/login/'``.
Limiting access to generic views
--------------------------------
@ -633,7 +654,7 @@ The currently logged-in user, either a ``User`` instance or an``AnonymousUser``
instance, is stored in the template variable ``{{ user }}``::
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}

View File

@ -259,10 +259,10 @@ The tests cover:
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
testing applications. See `Testing Django applications`_ for an explanation of
how to write new tests.
.. _Testing Django Applications: http://www.djangoproject.com/documentation/testing/
.. _Testing Django applications: http://www.djangoproject.com/documentation/testing/
Running the unit tests
----------------------
@ -273,7 +273,7 @@ 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
You will also need a ``ROOT_URLCONF`` setting (its 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.

View File

@ -876,15 +876,18 @@ The database API supports the following lookup types:
exact
~~~~~
Exact match.
Exact match. If the value provided for comparison is ``None``, it will
be interpreted as an SQL ``NULL`` (See isnull_ for more details).
Example::
Examples::
Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)
SQL equivalent::
SQL equivalents::
SELECT ... WHERE id = 14;
SELECT ... WHERE id = NULL;
iexact
~~~~~~
@ -1103,8 +1106,8 @@ such as January 3, July 3, etc.
isnull
~~~~~~
``NULL`` or ``IS NOT NULL`` match. Takes either ``True`` or ``False``, which
correspond to ``IS NULL`` and ``IS NOT NULL``, respectively.
Takes either ``True`` or ``False``, which correspond to SQL queries of
``IS NULL`` and ``IS NOT NULL``, respectively.
Example::
@ -1114,6 +1117,14 @@ SQL equivalent::
SELECT ... WHERE pub_date IS NULL;
.. admonition:: ``__isnull=True`` vs ``__exact=None``
There is an important difference between ``__isnull=True`` and
``__exact=None``. ``__exact=None`` will *always* return an empty result
set, because SQL requires that no value is equal to ``NULL``.
``__isnull`` determines if the field is currently holding the value
of ``NULL`` without performing a comparison.
search
~~~~~~

View File

@ -392,10 +392,10 @@ and `2` is verbose output.
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.
Tells Django where to find the various CSS and JavaScript files for the admin
interface when running the development server. Normally these files are served
out of the Django source tree, but because some designers customize these files
for their site, this option allows you to test against custom versions.
Extra niceties
==============

View File

@ -227,9 +227,7 @@ When will you release Django 1.0?
Short answer: When we're comfortable with Django's APIs, have added all
features that we feel are necessary to earn a "1.0" status, and are ready to
begin maintaining backwards compatibility. This should happen in a couple of
months or so, although it's entirely possible that it could happen earlier.
That translates into summer 2006.
begin maintaining backwards compatibility.
The merging of Django's `magic-removal branch`_ went a long way toward Django
1.0.
@ -313,6 +311,18 @@ PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported.
.. _MySQL: http://www.mysql.com/
.. _`SQLite 3`: http://www.sqlite.org/
Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
----------------------------------------------------------------------------------------
No. Django itself is guaranteed to work with any version of Python from 2.3
and higher.
If you use a Python version newer than 2.3, you will, of course, be able to
take advantage of newer Python features in your own code, along with the speed
improvements and other optimizations that have been made to the Python language
itself. But the Django framework itself should work equally well on 2.3 as it
does on 2.4 or 2.5.
Do I have to use mod_python?
----------------------------
@ -487,7 +497,7 @@ specify an object to edit or delete.
How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
------------------------------------------------------------------------------------------------------------------
We try to avoid adding special cases in the Django code to accomodate all the
We try to avoid adding special cases in the Django code to accommodate all the
database-specific options such as table type, etc. If you'd like to use any of
these options, create an `SQL initial data file`_ that contains ``ALTER TABLE``
statements that do what you want to do. The initial data files are executed in

View File

@ -211,7 +211,7 @@ Below is the finished view::
def create_place(request):
manipulator = Place.AddManipulator()
if request.POST:
if request.method == 'POST':
# If data was POSTed, we're trying to create a new Place.
new_data = request.POST.copy()
@ -309,7 +309,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
# Grab the Place object in question for future use.
place = manipulator.original_object
if request.POST:
if request.method == 'POST':
new_data = request.POST.copy()
errors = manipulator.get_validation_errors(new_data)
if not errors:
@ -337,8 +337,8 @@ The only real differences are:
object being edited.
* We set ``new_data`` based upon ``flatten_data()`` from the manipulator.
``flatten_data()`` takes the data from the original object under
manipulation, and converts it into a data dictionary that can be used
``flatten_data()`` takes the data from the original object under
manipulation, and converts it into a data dictionary that can be used
to populate form elements with the existing values for the object.
* The above example uses a different template, so create and edit can be
@ -391,7 +391,7 @@ Here's a simple function that might drive the above form::
def contact_form(request):
manipulator = ContactManipulator()
if request.POST:
if request.method == 'POST':
new_data = request.POST.copy()
errors = manipulator.get_validation_errors(new_data)
if not errors:
@ -404,7 +404,7 @@ Here's a simple function that might drive the above form::
errors = new_data = {}
form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('contact_form.html', {'form': form})
``FileField`` and ``ImageField`` special cases
==============================================
@ -481,15 +481,15 @@ 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?
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
validators for that field are called in turn. The emphasized 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
contains no data -- which is normal HTML behavior), the validators are not
run against the field.
This feature is particularly important for models using
@ -497,18 +497,17 @@ This feature is particularly important for models using
``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::
If you would like your validator to run *always*, regardless of whether its
attached field 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
Ready-made validators
---------------------
Writing your own validator is not difficult, but there are some situations
@ -580,7 +579,7 @@ fails. If no message is passed in, a default message is used.
``ValidateIfOtherFieldEquals``
Takes three parameters: ``other_field``, ``other_value`` and
``validator_list``, in that order. If ``other_field`` has a value of
``other_vaue``, then the validators in ``validator_list`` are all run
``other_value``, then the validators in ``validator_list`` are all run
against the current field.
``RequiredIfOtherFieldNotGiven``

View File

@ -184,7 +184,7 @@ a date in the *future* are not included unless you set ``allow_future`` to
the view's template. See the `RequestContext docs`_.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -270,7 +270,7 @@ to ``True``.
this is ``False``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -357,7 +357,7 @@ date in the *future* are not displayed unless you set ``allow_future`` to
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -438,7 +438,7 @@ in the *future* are not displayed unless you set ``allow_future`` to ``True``.
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -523,7 +523,7 @@ you set ``allow_future`` to ``True``.
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -633,7 +633,7 @@ future, the view will throw a 404 error by default, unless you set
to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
@ -707,7 +707,7 @@ A page representing a list of objects.
determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
**Template name:**
@ -819,7 +819,7 @@ A page representing an individual object.
to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting.
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
**Template name:**

View File

@ -84,9 +84,12 @@ Installing the official version
Note that the last command will automatically download and install setuptools_
if you don't already have it installed. This requires a working Internet
connection and may cause problems on Python 2.5. If you run into problems,
try using our development version by following the instructions below. The
development version no longer uses setuptools nor requires an Internet
connection.
This will install Django in your Python installation's ``site-packages``
The command will install Django in your Python installation's ``site-packages``
directory.
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
@ -94,19 +97,34 @@ directory.
Installing the development version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Make sure you have Subversion_ installed.
2. ``svn co http://code.djangoproject.com/svn/django/trunk/ django_src``
3. Symlink ``django_src/django`` so that ``django`` is within your Python
``site-packages`` directory:
If you'd like to be able to update your Django code occasionally with the
latest bug fixes and improvements, follow these instructions:
``ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django``
1. Make sure you have Subversion_ installed.
2. Check out the Django code into your Python ``site-packages`` directory.
On Linux / Mac OSX / Unix, do this::
svn co http://code.djangoproject.com/svn/django/trunk/ django_src
ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django
(In the above line, change ``python2.3`` to match your current Python version.)
You don't have to run ``python setup.py install``.
On Windows, do this::
When you want to update your code, just run the command ``svn update`` from
within the ``django_src`` directory.
svn co http://code.djangoproject.com/svn/django/trunk/django c:\Python24\lib\site-packages\django
4. Copy the file ``django_src/django/bin/django-admin.py`` to somewhere on your
system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
(Windows). This step simply lets you type ``django-admin.py`` from within
any directory, rather than having to qualify the command with the full path
to the file.
You *don't* have to run ``python setup.py install``, because that command
takes care of steps 3 and 4 for you.
When you want to update your copy of the Django source code, just run the
command ``svn update`` from within the ``django`` directory. When you do this,
Subversion will automatically download any changes.
.. _`download page`: http://www.djangoproject.com/download/
.. _Subversion: http://subversion.tigris.org/

View File

@ -188,7 +188,8 @@ JavaScript shortcuts.
~~~~~~~~~~~~~~
A ``CharField`` that checks that the value is a valid e-mail address.
This doesn't accept ``maxlength``.
This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to
75.
``FileField``
~~~~~~~~~~~~~
@ -545,7 +546,7 @@ The default value for the field.
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``.
classes. Default is ``True``.
``help_text``
~~~~~~~~~~~~~

View File

@ -110,7 +110,7 @@ many common questions appear with some regularity, and any particular problem
may already have been answered.
Finally, for those who prefer the more immediate feedback offered by IRC,
there's a #django channel or irc.freenode.net that is regularly populated by
there's a #django channel on irc.freenode.net that is regularly populated by
Django users and developers from around the world. Friendly people are usually
available at any hour of the day -- to help, or just to chat.

View File

@ -341,9 +341,9 @@ hard-coded strings. If you use this technique, follow these guidelines:
Methods
-------
``__init__(content='', mimetype=DEFAULT_MIME_TYPE)``
``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)``
Instantiates an ``HttpResponse`` object with the given page content (a
string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``'text/html'``.
string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``.
``content`` can be an iterator or a string. If it's an iterator, it should
return strings, and those strings will be joined together to form the

View File

@ -3,12 +3,12 @@ Serializing Django objects
==========================
.. note::
This API is currently under heavy development and may change --
perhaps drastically -- in the future.
You have been warned.
Django's serialization framework provides a mechanism for "translating" Django
objects into other formats. Usually these other formats will be text-based and
used for sending Django objects over a wire, but it's possible for a
@ -21,7 +21,7 @@ At the highest level, serializing data is a very simple operation::
from django.core import serializers
data = serializers.serialize("xml", SomeModel.objects.all())
The arguments to the ``serialize`` function are the format to serialize the
data to (see `Serialization formats`_) and a QuerySet_ to serialize.
(Actually, the second argument can be any iterator that yields Django objects,
@ -34,7 +34,7 @@ You can also use a serializer object directly::
xml_serializer = serializers.get_serializer("xml")
xml_serializer.serialize(queryset)
data = xml_serializer.getvalue()
This is useful if you want to serialize data directly to a file-like object
(which includes a HTTPResponse_)::
@ -50,7 +50,7 @@ Deserializing data is also a fairly simple operation::
for obj in serializers.deserialize("xml", data):
do_something_with(obj)
As you can see, the ``deserialize`` function takes the same format argument as
``serialize``, a string or stream of data, and returns an iterator.
@ -69,7 +69,7 @@ something like::
for deserialized_object in serializers.deserialize("xml", data):
if object_should_be_saved(deserialized_object):
obj.save()
In other words, the usual use is to examine the deserialized objects to make
sure that they are "appropriate" for saving before doing so. Of course, if you trust your data source you could just save the object and move on.
@ -89,22 +89,22 @@ Django "ships" with a few included serializers:
bundled with Django).
``python`` Translates to and from "simple" Python objects (lists, dicts,
strings, etc.). Not really all that useful on its own, but
strings, etc.). Not really all that useful on its own, but
used as a base for other serializers.
========== ==============================================================
.. _json: http://json.org/
.. _simplejson: http://undefined.org/python/#simplejson
Notes For Specific Serialization Formats
Notes for specific serialization formats
----------------------------------------
json
~~~~
If you are using UTF-8 (or any other non-ASCII encoding) data with the JSON
If you're 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.
``serialize()`` call. Otherwise, the output won't be encoded correctly.
For example::

View File

@ -401,15 +401,6 @@ Subject-line prefix for e-mail messages sent with ``django.core.mail.mail_admins
or ``django.core.mail.mail_managers``. You'll probably want to include the
trailing space.
ENABLE_PSYCO
------------
Default: ``False``
Whether to enable Psyco, which optimizes Python code. Requires Psyco_.
.. _Psyco: http://psyco.sourceforge.net/
IGNORABLE_404_ENDS
------------------
@ -599,8 +590,11 @@ See also ``APPEND_SLASH``.
PROFANITIES_LIST
----------------
A list of profanities that will trigger a validation error when the
``hasNoProfanities`` validator is called.
A tuple of profanities, as strings, that will trigger a validation error when
the ``hasNoProfanities`` validator is called.
We don't list the default values here, because that would be profane. To see
the default values, see the file ``django/conf/global_settings.py``.
ROOT_URLCONF
------------

View File

@ -540,6 +540,11 @@ The arguments can be hard-coded strings, so the following is valid::
...
{% endifequal %}
It is only possible to compare an argument to template variables or strings.
You cannot check for equality with Python objects such as ``True`` or
``False``. If you need to test if something is true or false, use the ``if``
and ``ifnot`` tags instead.
ifnotequal
~~~~~~~~~~
@ -1051,7 +1056,7 @@ Formats a date as the time since that date (i.e. "4 days, 6 hours").
Takes an optional argument that is a variable containing the date to use as
the comparison point (without the argument, the comparison point is *now*).
For example, if ``blog_date`` is a date instance representing midnight on 1
June 2006, and ``comment_date`` is a date instanace for 08:00 on 1 June 2006,
June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006,
then ``{{ comment_date|timesince:blog_date }}`` would return "8 hours".
timeuntil

View File

@ -212,6 +212,21 @@ template tags. If an invalid variable is provided to one of these template
tags, the variable will be interpreted as ``None``. Filters are always
applied to invalid variables within these template tags.
.. admonition:: For debug purposes only!
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
it is a bad idea to turn it on as a 'development default'.
Many templates, including those in the Admin site, rely upon the
silence of the template system when a non-existent variable is
encountered. If you assign a value other than ``''`` to
``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
problems with these templates and sites.
Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
in order to debug a specific template problem, then cleared
once debugging is complete.
Playing with Context objects
----------------------------
@ -296,6 +311,20 @@ optional, third positional argument, ``processors``. In this example, the
'foo': 'bar',
}, [ip_address_processor])
Note::
If you are using Django's ``render_to_response()`` shortcut to populate a
template with the contents of a dictionary, your template will be passed a
``Context`` instance by default (not a ``RequestContext``). If you wish to
use a ``RequestContext`` in your template rendering, you need to pass an
optional third argument to ``render_to_response()``: a ``RequestContext``
instance. Your code might look like this::
def some_view(request):
# ...
return render_to_response('my_template'html',
my_data_dictionary,
context_instance = RequestContext(request))
Here's what each of the default processors does:
.. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects
@ -366,6 +395,18 @@ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
`HttpRequest object`_. Note that this processor is not enabled by default;
you'll have to activate it.
Writing your own context processors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A context processor has a very simple interface: It's just a Python function
that takes one argument, an ``HttpRequest`` object, and returns a dictionary
that gets added to the template context. Each context processor *must* return
a dictionary.
Custom context processors can live anywhere in your code base. All Django cares
about is that your custom context processors are pointed-to by your
``TEMPLATE_CONTEXT_PROCESSORS`` setting.
Loading templates
-----------------
@ -805,7 +846,7 @@ Inclusion tags
Another common type of template tag is the type that displays some data by
rendering *another* template. For example, Django's admin interface uses custom
template tags to display the buttons along the botton of the "add/change" form
template tags to display the buttons along the bottom of the "add/change" form
pages. Those buttons always look the same, but the link targets change depending
on the object being edited -- so they're a perfect case for using a small
template that is filled with details from the current object. (In the admin's

View File

@ -389,7 +389,7 @@ an alternative framework as if they were normal Django tests.
When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER``
setting to determine what to do. By default, ``TEST_RUNNER`` points to ``django.test.simple.run_tests``. This method defines the default Django
testing behaviour. This behaviour involves:
testing behavior. This behavior involves:
#. Performing global pre-test setup
#. Creating the test database
@ -435,7 +435,7 @@ a number of utility methods in the ``django.test.utils`` module.
``create_test_db(verbosity=1, autoclobber=False)``
Creates a new test database, and run ``syncdb`` against it.
``verbosity`` has the same behaviour as in the test runner.
``verbosity`` has the same behavior as in the test runner.
``Autoclobber`` describes the behavior that will occur if a database with
the same name as the test database is discovered. If ``autoclobber`` is False,
@ -450,4 +450,4 @@ a number of utility methods in the ``django.test.utils`` module.
Destroys the database with the name ``settings.DATABASE_NAME`` matching,
and restores the value of ``settings.DATABASE_NAME`` to the provided name.
``verbosity`` has the same behaviour as in the test runner.
``verbosity`` has the same behavior as in the test runner.

View File

@ -377,7 +377,7 @@ By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
Django where our templates live::
TEMPLATE_DIRS = (
"/home/mytemplates", # Change this to your own directory.
"/home/my_username/mytemplates", # Change this to your own directory.
)
Now copy the template ``admin/base_site.html`` from within the default Django

View File

@ -91,7 +91,7 @@ Finally, it calls that ``detail()`` function like so::
The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
pattern "captures" the text matched by that pattern and sends it as an argument
to the view function; the ``?P<poll_id>`` defines the name that will be used to
identify the matched pattern; and ``\d+`` is a regular experession to match a sequence of
identify the matched pattern; and ``\d+`` is a regular expression to match a sequence of
digits (i.e., a number).
Because the URL patterns are regular expressions, there really is no limit on
@ -257,7 +257,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
from mysite.polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``loader``, ``Context`` or

View File

@ -207,7 +207,7 @@ for the polls app, we manually specify a template name for the results view:
template. Note that we use ``dict()`` to return an altered dictionary in place.
In previous parts of the tutorial, the templates have been provided with a context
that contains the ``poll` and ``latest_poll_list`` context variables. However,
that contains the ``poll`` and ``latest_poll_list`` context variables. However,
the generic views provide the variables ``object`` and ``object_list`` as context.
Therefore, you need to change your templates to match the new context variables.
Go through your templates, and modify any reference to ``latest_poll_list`` to

View File

@ -1,217 +0,0 @@
#!python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c1"
DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
}
import sys, os
def _validate_md5(egg_name, data):
if egg_name in md5_data:
from md5 import md5
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
try:
import setuptools
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
except ImportError:
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
import pkg_resources
try:
pkg_resources.require("setuptools>="+version)
except pkg_resources.VersionConflict:
# XXX could we install in a subprocess here?
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first."
) % version
sys.exit(2)
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
import tempfile, shutil
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
try:
egg = download_setuptools(version, to_dir=tmpdir, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
shutil.rmtree(tmpdir)
else:
if setuptools.__version__ == '0.0.1':
# tell the user to uninstall obsolete version
use_setuptools(version)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
from md5 import md5
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])

View File

@ -1,7 +1,25 @@
import ez_setup # From http://peak.telecommunity.com/DevCenter/setuptools
ez_setup.use_setuptools()
from distutils.core import setup
from distutils.command.install import INSTALL_SCHEMES
import os
from setuptools import setup, find_packages
# Tell distutils to put the data_files in platform-specific installation
# locations. See here for an explanation:
# http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb
for scheme in INSTALL_SCHEMES.values():
scheme['data'] = scheme['purelib']
# Compile the list of packages available, because distutils doesn't have
# an easy way to do this.
packages, data_files = [], []
root_dir = os.path.join(os.path.dirname(__file__), 'django')
for dirpath, dirnames, filenames in os.walk(root_dir):
# Ignore dirnames that start with '.'
for i, dirname in enumerate(dirnames):
if dirname.startswith('.'): del dirnames[i]
if '__init__.py' in filenames:
packages.append(dirpath.replace('/', '.'))
else:
data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames]))
setup(
name = "Django",
@ -10,24 +28,7 @@ setup(
author = 'Lawrence Journal-World',
author_email = 'holovaty@gmail.com',
description = 'A high-level Python Web framework that encourages rapid development and clean, pragmatic design.',
license = 'BSD',
packages = find_packages(exclude=['examples', 'examples.*']),
package_data = {
'': ['*.TXT'],
'django.conf': ['locale/*/LC_MESSAGES/*'],
'django.contrib.admin': ['templates/admin/*.html',
'templates/admin/auth/user/*.html',
'templates/admin_doc/*.html',
'templates/registration/*.html',
'templates/widget/*.html',
'media/css/*.css',
'media/img/admin/*.gif',
'media/img/admin/*.png',
'media/js/*.js',
'media/js/admin/*js'],
'django.contrib.comments': ['templates/comments/*.html'],
'django.contrib.sitemaps': ['templates/*.xml'],
},
packages = packages,
data_files = data_files,
scripts = ['django/bin/django-admin.py'],
zip_safe = False,
)

View File

@ -30,6 +30,14 @@ class Waiter(models.Model):
def __str__(self):
return "%s the waiter at %s" % (self.name, self.restaurant)
class ManualPrimaryKey(models.Model):
primary_key = models.CharField(maxlength=10, primary_key=True)
name = models.CharField(maxlength = 50)
class RelatedModel(models.Model):
link = models.OneToOneField(ManualPrimaryKey)
name = models.CharField(maxlength = 50)
__test__ = {'API_TESTS':"""
# Create a couple of Places.
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
@ -151,4 +159,10 @@ DoesNotExist: Restaurant matching query does not exist.
# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
# One-to-one fields still work if you create your own primary key
>>> o1 = ManualPrimaryKey(primary_key="abc123", name="primary")
>>> o1.save()
>>> o2 = RelatedModel(link=o1, name="secondary")
>>> o2.save()
"""}

View File

@ -21,22 +21,22 @@ r"""
'7'
>>> format(my_birthday, 'N')
'July'
>>> format(my_birthday, 'O')
'+0100'
>>> no_tz or format(my_birthday, 'O') == '+0100'
True
>>> format(my_birthday, 'P')
'10 p.m.'
>>> format(my_birthday, 'r')
'Sun, 8 Jul 1979 22:00:00 +0100'
>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100'
True
>>> format(my_birthday, 's')
'00'
>>> format(my_birthday, 'S')
'th'
>>> format(my_birthday, 't')
'31'
>>> format(my_birthday, 'T')
'CET'
>>> format(my_birthday, 'U')
'300531600'
>>> no_tz or format(my_birthday, 'T') == 'CET'
True
>>> no_tz or format(my_birthday, 'U') == '300531600'
True
>>> format(my_birthday, 'w')
'0'
>>> format(my_birthday, 'W')
@ -47,17 +47,17 @@ r"""
'1979'
>>> format(my_birthday, 'z')
'189'
>>> format(my_birthday, 'Z')
'3600'
>>> no_tz or format(my_birthday, 'Z') == '3600'
True
>>> format(summertime, 'I')
'1'
>>> format(summertime, 'O')
'+0200'
>>> format(wintertime, 'I')
'0'
>>> format(wintertime, 'O')
'+0100'
>>> no_tz or format(summertime, 'I') == '1'
True
>>> no_tz or format(summertime, 'O') == '+0200'
True
>>> no_tz or format(wintertime, 'I') == '0'
True
>>> no_tz or format(wintertime, 'O') == '+0100'
True
>>> format(my_birthday, r'Y z \C\E\T')
'1979 189 CET'
@ -73,7 +73,11 @@ format = dateformat.format
os.environ['TZ'] = 'Europe/Copenhagen'
translation.activate('en-us')
time.tzset()
try:
time.tzset()
no_tz = False
except AttributeError:
no_tz = True
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
summertime = datetime.datetime(2005, 10, 30, 1, 00)

View File

@ -0,0 +1,54 @@
from django.db import models
class Poll(models.Model):
question = models.CharField(maxlength=200)
def __str__(self):
return "Q: %s " % self.question
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(maxlength=200)
def __str__(self):
return "Choice: %s in poll %s" % (self.choice, self.poll)
__test__ = {'API_TESTS':"""
# Regression test for the use of None as a query value. None is interpreted as
# an SQL NULL, but only in __exact queries.
# Set up some initial polls and choices
>>> p1 = Poll(question='Why?')
>>> p1.save()
>>> c1 = Choice(poll=p1, choice='Because.')
>>> c1.save()
>>> c2 = Choice(poll=p1, choice='Why Not?')
>>> c2.save()
# Exact query with value None returns nothing (=NULL in sql)
>>> Choice.objects.filter(id__exact=None)
[]
# Valid query, but fails because foo isn't a keyword
>>> Choice.objects.filter(foo__exact=None)
Traceback (most recent call last):
...
TypeError: Cannot resolve keyword 'foo' into field
# Can't use None on anything other than __exact
>>> Choice.objects.filter(id__gt=None)
Traceback (most recent call last):
...
ValueError: Cannot use None as a query value
# Can't use None on anything other than __exact
>>> Choice.objects.filter(foo__gt=None)
Traceback (most recent call last):
...
ValueError: Cannot use None as a query value
# Related managers use __exact=None implicitly if the object hasn't been saved.
>>> p2 = Poll(question="How?")
>>> p2.choice_set.all()
[]
"""}

View File

@ -170,6 +170,9 @@ class Templates(unittest.TestCase):
# Escaped backslash using known escape char
'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),
# Empty strings can be passed as arguments to filters
'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),
### COMMENT TAG ###########################################################
'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),