1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

[multi-db] Merged trunk to [3890]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@4152 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jason Pellerin 2006-12-04 18:16:40 +00:00
parent 261fb45ba8
commit e07dae7b77
20 changed files with 105 additions and 96 deletions

View File

@ -75,6 +75,7 @@ answer newbie questions, and generally made Django that much better:
Jeremy Dunck <http://dunck.us/> Jeremy Dunck <http://dunck.us/>
Andy Dustman <farcepest@gmail.com> Andy Dustman <farcepest@gmail.com>
Clint Ecker Clint Ecker
Enrico <rico.bl@gmail.com>
favo@exoweb.net favo@exoweb.net
gandalf@owca.info gandalf@owca.info
Baishampayan Ghose Baishampayan Ghose

View File

@ -226,10 +226,6 @@ YEAR_MONTH_FORMAT = 'F Y'
# http://www.djangoproject.com/documentation/templates/#now # http://www.djangoproject.com/documentation/templates/#now
MONTH_DAY_FORMAT = 'F j' 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? # Do you want to manage transactions manually?
# Hint: you really don't! # Hint: you really don't!
TRANSACTIONS_MANAGED = False TRANSACTIONS_MANAGED = False

View File

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

View File

@ -216,6 +216,8 @@ class User(models.Model):
def has_module_perms(self, app_label): def has_module_perms(self, app_label):
"Returns True if the user has any permissions in the given 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: if self.is_superuser:
return True return True
return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label])) return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))

View File

@ -89,7 +89,8 @@ class BaseHandler(object):
return response return response
except http.Http404, e: except http.Http404, e:
if settings.DEBUG: 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: else:
callback, param_dict = resolver.resolve404() callback, param_dict = resolver.resolve404()
return callback(request, **param_dict) return callback(request, **param_dict)
@ -99,7 +100,8 @@ class BaseHandler(object):
pass # See http://code.djangoproject.com/ticket/1023 pass # See http://code.djangoproject.com/ticket/1023
except: # Handle everything else, including SuspiciousOperation, etc. except: # Handle everything else, including SuspiciousOperation, etc.
if settings.DEBUG: 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: else:
# Get the exception info now, in case another exception is thrown later. # Get the exception info now, in case another exception is thrown later.
exc_info = sys.exc_info() exc_info = sys.exc_info()
@ -112,26 +114,9 @@ class BaseHandler(object):
request_repr = "Request repr() unavailable" request_repr = "Request repr() unavailable"
message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr) message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
mail_admins(subject, message, fail_silently=True) mail_admins(subject, message, fail_silently=True)
return self.get_friendly_error_response(request, resolver) # Return an HttpResponse that displays a friendly error message.
callback, param_dict = resolver.resolve500()
def get_friendly_error_response(self, request, resolver): return callback(request, **param_dict)
"""
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())
def _get_traceback(self, exc_info=None): def _get_traceback(self, exc_info=None):
"Helper function to return the traceback as a string" "Helper function to return the traceback as a string"

View File

@ -139,10 +139,6 @@ class ModPythonHandler(BaseHandler):
# that use settings now can work # that use settings now can work
from django.conf import settings 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 we need to set up middleware, now that settings works we can do it now.
if self._request_middleware is None: if self._request_middleware is None:
self.load_middleware() self.load_middleware()
@ -160,23 +156,20 @@ class ModPythonHandler(BaseHandler):
dispatcher.send(signal=signals.request_finished) dispatcher.send(signal=signals.request_finished)
# Convert our custom HttpResponse object back into the mod_python req. # Convert our custom HttpResponse object back into the mod_python req.
populate_apache_request(response, req) req.content_type = response['Content-Type']
return 0 # mod_python.apache.OK 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): return 0 # mod_python.apache.OK
"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()
def handler(req): def handler(req):
# mod_python hooks into this function. # mod_python hooks into this function.

View File

@ -174,10 +174,6 @@ class WSGIHandler(BaseHandler):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
from django.conf import settings 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 # Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available. # settings weren't available.
if self._request_middleware is None: if self._request_middleware is None:

View File

@ -230,7 +230,6 @@ def get_sql_indexes(app):
from django.db import model_connection_name from django.db import model_connection_name
from django.db.models import get_models from django.db.models import get_models
connection_output = {} connection_output = {}
for model in get_models(app): for model in get_models(app):
opts = model._meta opts = model._meta
connection_name = model_connection_name(model) connection_name = model_connection_name(model)
@ -242,6 +241,23 @@ def get_sql_indexes(app):
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)." get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
get_sql_indexes.args = APP_ARGS get_sql_indexes.args = APP_ARGS
def _get_sql_index(model):
"Returns the CREATE INDEX SQL statements for a specific 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): def get_sql_all(app):
"Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." "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) return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app)
@ -269,7 +285,7 @@ def _collate(connection_output, reverse=False):
connection_name) connection_name)
return map(str, final_output) return map(str, final_output)
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." "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
from django.conf import settings from django.conf import settings
from django.db import models, transaction from django.db import models, transaction
@ -296,8 +312,9 @@ def syncdb(verbosity=2, interactive=True):
for app in models.get_apps(): for app in models.get_apps():
# Install each application (models already installed will be skipped) # Install each application (models already installed will be skipped)
created, pending = _install(app, commit=False, initial_data=False, created, pending = _install(app, commit=False, initial_data=False,
pending_allowed=True, pending=pending) pending_allowed=True, pending=pending,
if verbosity >= 2: verbosity=verbosity)
if verbosity >= 1:
for model in created: for model in created:
print "Created table %s" % model._meta.db_table print "Created table %s" % model._meta.db_table
created_models.extend(created) created_models.extend(created)
@ -311,6 +328,8 @@ def syncdb(verbosity=2, interactive=True):
# Send the post_syncdb signal, so individual apps can do whatever they need # Send the post_syncdb signal, so individual apps can do whatever they need
# to do at this point. # to do at this point.
for app in models.get_apps(): for app in models.get_apps():
if verbosity >= 2:
print "Sending post-syncdb signal for application", app.__name__.split('.')[-2]
dispatcher.send(signal=signals.post_syncdb, sender=app, dispatcher.send(signal=signals.post_syncdb, sender=app,
app=app, created_models=created_models, app=app, created_models=created_models,
verbosity=verbosity, interactive=interactive) verbosity=verbosity, interactive=interactive)
@ -322,7 +341,7 @@ def syncdb(verbosity=2, interactive=True):
if model in created_models: if model in created_models:
try: try:
if (model._default_manager.load_initial_data() if (model._default_manager.load_initial_data()
and verbosity >= 2): and verbosity >= 1):
print "Installed initial data for %s model" % model._meta.object_name print "Installed initial data for %s model" % model._meta.object_name
except Exception, e: except Exception, e:
sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \ sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \
@ -391,7 +410,7 @@ def install(app):
_install(app) _install(app)
def _install(app, commit=True, initial_data=True, pending_allowed=False, def _install(app, commit=True, initial_data=True, pending_allowed=False,
pending=None): pending=None, verbosity=1):
from django.db import connection, models, transaction from django.db import connection, models, transaction
import sys import sys
@ -407,6 +426,9 @@ def _install(app, commit=True, initial_data=True, pending_allowed=False,
if pending is None: if pending is None:
pending = {} pending = {}
for model in models.get_models(app, creation_order=True): for model in models.get_models(app, creation_order=True):
if verbosity >= 2:
print "Processing %s.%s model" % (app_name,
model._meta.object_name)
manager = model._default_manager manager = model._default_manager
tables = manager.get_table_list() tables = manager.get_table_list()
models_installed = manager.get_installed_models(tables) models_installed = manager.get_installed_models(tables)
@ -445,7 +467,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.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
install.args = APP_ARGS install.args = APP_ARGS
def reset(app): def reset(app, interactive=True):
"Executes the equivalent of 'get_sql_reset' in the current database." "Executes the equivalent of 'get_sql_reset' in the current database."
from django.db import connection, transaction from django.db import connection, transaction
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
@ -456,21 +478,25 @@ def reset(app):
_check_for_validation_errors(app) _check_for_validation_errors(app)
sql_list = get_sql_reset(app) sql_list = get_sql_reset(app)
confirm = raw_input(""" if interactive:
confirm = raw_input("""
You have requested a database reset. You have requested a database reset.
This will IRREVERSIBLY DESTROY any data in your database. This will IRREVERSIBLY DESTROY any data in your database.
Are you sure you want to do this? Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: """) Type 'yes' to continue, or 'no' to cancel: """)
else:
confirm = 'yes'
if confirm == 'yes': if confirm == 'yes':
try: try:
cursor = connection.cursor() cursor = connection.cursor()
for sql in sql_list: for sql in sql_list:
cursor.execute(sql) cursor.execute(sql)
except Exception, e: 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. * 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. * 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. 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') The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
@ -1031,7 +1057,7 @@ def runfcgi(args):
runfastcgi(args) runfastcgi(args)
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' 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" "Runs the test suite for the specified applications"
from django.conf import settings from django.conf import settings
from django.db.models import get_app, get_apps from django.db.models import get_app, get_apps
@ -1133,7 +1159,7 @@ 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.') 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, 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.') 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'], type='choice', choices=['0', '1', '2'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'), parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'),
@ -1182,7 +1208,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
parser.print_usage_and_exit() parser.print_usage_and_exit()
elif action == 'test': elif action == 'test':
try: try:
action_mapping[action](int(options.verbosity), args[1:]) action_mapping[action](args[1:], int(options.verbosity))
except IndexError: except IndexError:
parser.print_usage_and_exit() parser.print_usage_and_exit()
elif action in ('startapp', 'startproject'): elif action in ('startapp', 'startproject'):
@ -1216,7 +1242,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
if action not in NO_SQL_TRANSACTION: if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("BEGIN;") print style.SQL_KEYWORD("BEGIN;")
for mod in mod_list: 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: if output:
print '\n'.join(output) print '\n'.join(output)
if action not in NO_SQL_TRANSACTION: if action not in NO_SQL_TRANSACTION:

View File

@ -82,7 +82,7 @@ There are also a few styles for styling text.
.help .help
This is a custom class for blocks of inline help text explaining the 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 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 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 text, instead of ``small quiet``. It works on other elements, but try to
put the class on a ``p`` whenever you can. 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 Form labels should always precede the field, except in the case
of checkboxes and radio buttons, where the ``input`` should come first. Any 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 explanation or help text should follow the ``label`` in a ``p`` with class
``.help``. ``.help``.

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 That said, these APIs should *not* be considered stable, and are likely to
change: 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. deemphasize Manipulators in favor of validation-aware models.
- `Serialization`_ is under heavy development; changes are likely. - `Serialization`_ is under heavy development; changes are likely.
@ -91,7 +91,7 @@ change:
API changes may be necessary. API changes may be necessary.
- Generic relations will most likely be moved out of core and into the - 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. components.
- The comments framework, which is yet undocumented, will likely get a complete - 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. long and can contain any character. See the "Passwords" section below.
* ``is_staff`` -- Boolean. Designates whether this user can access the * ``is_staff`` -- Boolean. Designates whether this user can access the
admin site. admin site.
* ``is_active`` -- Boolean. Designates whether this user can log into the * ``is_active`` -- Boolean. Designates whether this account can be used
Django admin. Set this to ``False`` instead of deleting accounts. to log in. Set this flag to ``False`` instead of deleting accounts.
* ``is_superuser`` -- Boolean. Designates that this user has all permissions * ``is_superuser`` -- Boolean. Designates that this user has all permissions
without explicitly assigning them. without explicitly assigning them.
* ``last_login`` -- A datetime of the user's last login. Is set to the * ``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. should prefer using ``is_authenticated()`` to this method.
* ``is_authenticated()`` -- Always returns ``True``. This is a way to * ``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``, * ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``,
with a space in between. with a space in between.
@ -120,13 +122,16 @@ custom methods:
* ``has_perm(perm)`` -- Returns ``True`` if the user has the specified * ``has_perm(perm)`` -- Returns ``True`` if the user has the specified
permission, where perm is in the format ``"package.codename"``. 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 * ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the
specified permissions, where each perm is in the format 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 * ``has_module_perms(package_name)`` -- Returns ``True`` if the user has
any permissions in the given package (the Django app label). 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 * ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in
the user's queue and deletes the messages from the queue. 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 from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret') user = authenticate(username='john', password='secret')
if user is not None: 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: else:
print "Your username and password were incorrect." 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'] password = request.POST['password']
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user is not None: if user is not None:
login(request, user) if user.is_active:
# Redirect to a success page. login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else: else:
# Return an error message. # Return an 'invalid login' error message.
How to log a user out How to log a user out
--------------------- ---------------------

View File

@ -499,7 +499,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? 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 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`` 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 statements that do what you want to do. The initial data files are executed in

View File

@ -489,7 +489,7 @@ 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 test *and if the form submission contained data* for that field, all the
validators for that field are called in turn. The emphasized 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 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. run against the field.
This feature is particularly important for models using This feature is particularly important for models using

View File

@ -110,7 +110,7 @@ many common questions appear with some regularity, and any particular problem
may already have been answered. may already have been answered.
Finally, for those who prefer the more immediate feedback offered by IRC, 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 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. available at any hour of the day -- to help, or just to chat.

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 or ``django.core.mail.mail_managers``. You'll probably want to include the
trailing space. trailing space.
ENABLE_PSYCO
------------
Default: ``False``
Whether to enable Psyco, which optimizes Python code. Requires Psyco_.
.. _Psyco: http://psyco.sourceforge.net/
IGNORABLE_404_ENDS IGNORABLE_404_ENDS
------------------ ------------------

View File

@ -540,6 +540,11 @@ The arguments can be hard-coded strings, so the following is valid::
... ...
{% endifequal %} {% 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 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 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*). the comparison point (without the argument, the comparison point is *now*).
For example, if ``blog_date`` is a date instance representing midnight on 1 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". then ``{{ comment_date|timesince:blog_date }}`` would return "8 hours".
timeuntil timeuntil

View File

@ -817,7 +817,7 @@ Inclusion tags
Another common type of template tag is the type that displays some data by 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 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 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 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 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`` 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 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 #. Performing global pre-test setup
#. Creating the test database #. 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)`` ``create_test_db(verbosity=1, autoclobber=False)``
Creates a new test database, and run ``syncdb`` against it. 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 ``Autoclobber`` describes the behavior that will occur if a database with
the same name as the test database is discovered. If ``autoclobber`` is False, 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, Destroys the database with the name ``settings.DATABASE_NAME`` matching,
and restores the value of ``settings.DATABASE_NAME`` to the provided name. 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

@ -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 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 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 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). digits (i.e., a number).
Because the URL patterns are regular expressions, there really is no limit on Because the URL patterns are regular expressions, there really is no limit on

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. 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 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. 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. 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 Go through your templates, and modify any reference to ``latest_poll_list`` to