1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

newforms-admin: Merged to [5439]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5440 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-06-07 21:49:06 +00:00
parent 659d99b7af
commit d34639b09b
52 changed files with 3250 additions and 2809 deletions

View File

@ -142,6 +142,7 @@ answer newbie questions, and generally made Django that much better:
Joseph Kocherhans Joseph Kocherhans
konrad@gwu.edu konrad@gwu.edu
lakin.wecker@gmail.com lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
Stuart Langridge <http://www.kryogenix.org/> Stuart Langridge <http://www.kryogenix.org/>
Nicola Larosa <nico@teknico.net> Nicola Larosa <nico@teknico.net>
Eugene Lazutkin <http://lazutkin.com/blog/> Eugene Lazutkin <http://lazutkin.com/blog/>
@ -230,6 +231,7 @@ answer newbie questions, and generally made Django that much better:
viestards.lists@gmail.com viestards.lists@gmail.com
Milton Waddams Milton Waddams
wam-djangobug@wamber.net wam-djangobug@wamber.net
wangchun <yaohua2000@gmail.com>
Dan Watson <http://theidioteque.net/> Dan Watson <http://theidioteque.net/>
Chris Wesseling <Chris.Wesseling@cwi.nl> Chris Wesseling <Chris.Wesseling@cwi.nl>
charly.wilhelm@gmail.com charly.wilhelm@gmail.com

View File

@ -7,13 +7,13 @@ Can be run as a cronjob to clean out old data from the database (only expired
sessions at the moment). sessions at the moment).
""" """
from django.db import backend, connection, transaction import datetime
from django.db import transaction
from django.contrib.sessions.models import Session
def clean_up(): def clean_up():
# Clean up old database records """Clean up expired sessions."""
cursor = connection.cursor() Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
(backend.quote_name('django_session'), backend.quote_name('expire_date')))
transaction.commit_unless_managed() transaction.commit_unless_managed()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -144,6 +144,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth', 'django.core.context_processors.auth',
'django.core.context_processors.debug', 'django.core.context_processors.debug',
'django.core.context_processors.i18n', 'django.core.context_processors.i18n',
'django.core.context_processors.media',
# 'django.core.context_processors.request', # 'django.core.context_processors.request',
) )
@ -331,6 +332,13 @@ TEST_RUNNER = 'django.test.simple.run_tests'
# If None, a name of 'test_' + DATABASE_NAME will be assumed # If None, a name of 'test_' + DATABASE_NAME will be assumed
TEST_DATABASE_NAME = None TEST_DATABASE_NAME = None
# Strings used to set the character set and collation order for the test
# database. These values are passed literally to the server, so they are
# backend-dependent. If None, no special settings are sent (system defaults are
# used).
TEST_DATABASE_CHARSET = None
TEST_DATABASE_COLLATION = None
############ ############
# FIXTURES # # FIXTURES #
############ ############

File diff suppressed because it is too large Load Diff

View File

@ -113,8 +113,8 @@ msgstr "Demà"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34 #: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72 #: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show" msgid "Show"
msgstr "" msgstr "Mostrar"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63 #: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide" msgid "Hide"
msgstr "" msgstr "Ocultar"

View File

@ -481,8 +481,8 @@ msgid ""
"database tables have been created, and make sure the database is readable by " "database tables have been created, and make sure the database is readable by "
"the appropriate user." "the appropriate user."
msgstr "" msgstr ""
"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, das " "Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
"die richtigen Datenbanktabellen angelegt wurden und bitte sicherstellen, das " "die richtigen Datenbanktabellen angelegt wurden und "
"die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist." "die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist."
#: contrib/admin/templates/admin/login.html:17 #: contrib/admin/templates/admin/login.html:17

View File

@ -38,8 +38,9 @@ USE_I18N = True
# Example: "/home/media/media.lawrence.com/" # Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = '' MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. # URL that handles the media served from MEDIA_ROOT. Make sure to use a
# Example: "http://media.lawrence.com" # trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '' MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a

View File

@ -1,4 +1,5 @@
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
from django.core.exceptions import ImproperlyConfigured
__all__ = ['handler404', 'handler500', 'include', 'patterns', 'url'] __all__ = ['handler404', 'handler500', 'include', 'patterns', 'url']
@ -22,7 +23,10 @@ def url(regex, view, kwargs=None, name=None, prefix=''):
# For include(...) processing. # For include(...) processing.
return RegexURLResolver(regex, view[0], kwargs) return RegexURLResolver(regex, view[0], kwargs)
else: else:
if prefix and isinstance(view, basestring): if isinstance(view, basestring):
view = prefix + '.' + view if not view:
raise ImproperlyConfigured('Empty URL pattern view name not permitted (for pattern %r)' % regex)
if prefix:
view = prefix + '.' + view
return RegexURLPattern(regex, view, kwargs, name) return RegexURLPattern(regex, view, kwargs, name)

View File

@ -23,16 +23,19 @@ class LatestFreeCommentsFeed(Feed):
self._site = Site.objects.get_current() self._site = Site.objects.get_current()
return "Latest comments on %s" % self._site.name return "Latest comments on %s" % self._site.name
def get_query_set(self):
return self.comments_class.objects.filter(site__pk=settings.SITE_ID, is_public=True)
def items(self): def items(self):
return self.comments_class.objects.filter(site__pk=settings.SITE_ID, is_public=True)[:40] return self.get_query_set()[:40]
class LatestCommentsFeed(LatestFreeCommentsFeed): class LatestCommentsFeed(LatestFreeCommentsFeed):
"""Feed of latest free comments on the current site""" """Feed of latest free comments on the current site"""
comments_class = Comment comments_class = Comment
def items(self): def get_query_set(self):
qs = LatestFreeCommentsFeed.items(self) qs = super(LatestCommentsFeed, self).get_query_set()
qs = qs.filter(is_removed=False) qs = qs.filter(is_removed=False)
if settings.COMMENTS_BANNED_USERS_GROUP: if settings.COMMENTS_BANNED_USERS_GROUP:
where = ['user_id NOT IN (SELECT user_id FROM auth_users_group WHERE group_id = %s)'] where = ['user_id NOT IN (SELECT user_id FROM auth_users_group WHERE group_id = %s)']

View File

@ -42,6 +42,13 @@ def i18n(request):
return context_extras return context_extras
def media(request):
"""
Adds media-related context variables to the context.
"""
return {'MEDIA_URL': settings.MEDIA_URL}
def request(request): def request(request):
return {'request': request} return {'request': request}

View File

@ -1141,7 +1141,7 @@ def validate(outfile=sys.stdout, silent_success=False):
return return
outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or '')) outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
except ImproperlyConfigured: except ImproperlyConfigured:
outfile.write("Skipping validation because things aren't configured properly.") outfile.write("Skipping validation because things aren't configured properly.\n")
validate.args = '' validate.args = ''
def _check_for_validation_errors(app=None): def _check_for_validation_errors(app=None):

View File

@ -21,6 +21,8 @@ class Serializer(PythonSerializer):
Convert a queryset to JSON. Convert a queryset to JSON.
""" """
def end_serialization(self): def end_serialization(self):
self.options.pop('stream', None)
self.options.pop('fields', None)
simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options) simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options)
def getvalue(self): def getvalue(self):

View File

@ -37,7 +37,12 @@ class Serializer(base.Serializer):
def handle_fk_field(self, obj, field): def handle_fk_field(self, obj, field):
related = getattr(obj, field.name) related = getattr(obj, field.name)
if related is not None: if related is not None:
related = getattr(related, field.rel.field_name) if field.rel.field_name == related._meta.pk.name:
# Related to remote object via primary key
related = related._get_pk_val()
else:
# Related to remote object via other field
related = getattr(related, field.rel.field_name)
self._current[field.name] = related self._current[field.name] = related
def handle_m2m_field(self, obj, field): def handle_m2m_field(self, obj, field):

View File

@ -18,6 +18,8 @@ class Serializer(PythonSerializer):
Convert a queryset to YAML. Convert a queryset to YAML.
""" """
def end_serialization(self): def end_serialization(self):
self.options.pop('stream', None)
self.options.pop('fields', None)
yaml.dump(self.objects, self.stream, **self.options) yaml.dump(self.objects, self.stream, **self.options)
def getvalue(self): def getvalue(self):

View File

@ -82,7 +82,13 @@ class Serializer(base.Serializer):
self._start_relational_field(field) self._start_relational_field(field)
related = getattr(obj, field.name) related = getattr(obj, field.name)
if related is not None: if related is not None:
self.xml.characters(str(getattr(related, field.rel.field_name))) if field.rel.field_name == related._meta.pk.name:
# Related to remote object via primary key
related = related._get_pk_val()
else:
# Related to remote object via other field
related = getattr(related, field.rel.field_name)
self.xml.characters(str(related))
else: else:
self.xml.addQuickElement("None") self.xml.addQuickElement("None")
self.xml.endElement("field") self.xml.endElement("field")

View File

@ -12,6 +12,9 @@ from django.core.exceptions import ImproperlyConfigured
def complain(*args, **kwargs): def complain(*args, **kwargs):
raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet."
def ignore(*args, **kwargs):
pass
class DatabaseError(Exception): class DatabaseError(Exception):
pass pass
@ -21,7 +24,7 @@ class IntegrityError(DatabaseError):
class DatabaseWrapper: class DatabaseWrapper:
cursor = complain cursor = complain
_commit = complain _commit = complain
_rollback = complain _rollback = ignore
def __init__(self, **kwargs): def __init__(self, **kwargs):
pass pass

View File

@ -554,9 +554,8 @@ class QuerySet(object):
class ValuesQuerySet(QuerySet): class ValuesQuerySet(QuerySet):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ValuesQuerySet, self).__init__(*args, **kwargs) super(ValuesQuerySet, self).__init__(*args, **kwargs)
# select_related and select aren't supported in values(). # select_related isn't supported in values().
self._select_related = False self._select_related = False
self._select = {}
def iterator(self): def iterator(self):
try: try:
@ -566,13 +565,28 @@ class ValuesQuerySet(QuerySet):
# self._fields is a list of field names to fetch. # self._fields is a list of field names to fetch.
if self._fields: if self._fields:
columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields] #columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
if not self._select:
columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
else:
columns = []
for f in self._fields:
if f in [field.name for field in self.model._meta.fields]:
columns.append( self.model._meta.get_field(f, many_to_many=False).column )
elif not self._select.has_key( f ):
raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f )
field_names = self._fields field_names = self._fields
else: # Default to all fields. else: # Default to all fields.
columns = [f.column for f in self.model._meta.fields] columns = [f.column for f in self.model._meta.fields]
field_names = [f.attname for f in self.model._meta.fields] field_names = [f.attname for f in self.model._meta.fields]
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
# Add any additional SELECTs.
if self._select:
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
while 1: while 1:

View File

@ -75,7 +75,7 @@ class CommonMiddleware(object):
# Use ETags, if requested. # Use ETags, if requested.
if settings.USE_ETAGS: if settings.USE_ETAGS:
etag = md5.new(response.content).hexdigest() etag = md5.new(response.content).hexdigest()
if request.META.get('HTTP_IF_NONE_MATCH') == etag: if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
response = http.HttpResponseNotModified() response = http.HttpResponseNotModified()
else: else:
response['ETag'] = etag response['ETag'] = etag

View File

@ -63,7 +63,7 @@ class BaseForm(StrAndUnicode):
self.auto_id = auto_id self.auto_id = auto_id
self.prefix = prefix self.prefix = prefix
self.initial = initial or {} self.initial = initial or {}
self.__errors = None # Stores the errors after clean() has been called. self._errors = None # Stores the errors after clean() has been called.
# The base_fields class attribute is the *class-wide* definition of # The base_fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to # fields. Because a particular *instance* of the class might want to
@ -87,12 +87,12 @@ class BaseForm(StrAndUnicode):
raise KeyError('Key %r not found in Form' % name) raise KeyError('Key %r not found in Form' % name)
return BoundField(self, field, name) return BoundField(self, field, name)
def _errors(self): def _get_errors(self):
"Returns an ErrorDict for self.data" "Returns an ErrorDict for self.data"
if self.__errors is None: if self._errors is None:
self.full_clean() self.full_clean()
return self.__errors return self._errors
errors = property(_errors) errors = property(_get_errors)
def is_valid(self): def is_valid(self):
""" """
@ -189,11 +189,11 @@ class BaseForm(StrAndUnicode):
def full_clean(self): def full_clean(self):
""" """
Cleans all of self.data and populates self.__errors and self.cleaned_data. Cleans all of self.data and populates self._errors and
self.cleaned_data.
""" """
errors = ErrorDict() self._errors = ErrorDict()
if not self.is_bound: # Stop further processing. if not self.is_bound: # Stop further processing.
self.__errors = errors
return return
self.cleaned_data = {} self.cleaned_data = {}
for name, field in self.fields.items(): for name, field in self.fields.items():
@ -206,16 +206,17 @@ class BaseForm(StrAndUnicode):
self.cleaned_data[name] = value self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name): if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)() value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value self.cleaned_data[name] = value
except ValidationError, e: except ValidationError, e:
errors[name] = e.messages self._errors[name] = e.messages
if name in self.cleaned_data:
del self.cleaned_data[name]
try: try:
self.cleaned_data = self.clean() self.cleaned_data = self.clean()
except ValidationError, e: except ValidationError, e:
errors[NON_FIELD_ERRORS] = e.messages self._errors[NON_FIELD_ERRORS] = e.messages
if errors: if self._errors:
delattr(self, 'cleaned_data') delattr(self, 'cleaned_data')
self.__errors = errors
def clean(self): def clean(self):
""" """

View File

@ -782,7 +782,7 @@ class DecimalField(TextField):
try: try:
import decimal import decimal
except ImportError: except ImportError:
from django.utils import decimal from django.utils import _decimal as decimal
try: try:
return decimal.Decimal(data) return decimal.Decimal(data)
except decimal.InvalidOperation, e: except decimal.InvalidOperation, e:

View File

@ -479,7 +479,7 @@ class TokenParser(object):
while i < len(subject) and subject[i] != c: while i < len(subject) and subject[i] != c:
i += 1 i += 1
if i >= len(subject): if i >= len(subject):
raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % subject raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject)
i += 1 i += 1
s = subject[p:i] s = subject[p:i]
while i < len(subject) and subject[i] in (' ', '\t'): while i < len(subject) and subject[i] in (' ', '\t'):

View File

@ -237,7 +237,7 @@ class RegroupNode(Node):
return '' return ''
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
for obj in obj_list: for obj in obj_list:
grouper = self.expression.resolve(Context({'var': obj}), True) grouper = self.expression.resolve(obj, True)
# TODO: Is this a sensible way to determine equality? # TODO: Is this a sensible way to determine equality?
if output and repr(output[-1]['grouper']) == repr(grouper): if output and repr(output[-1]['grouper']) == repr(grouper):
output[-1]['list'].append(obj) output[-1]['list'].append(obj)
@ -847,7 +847,7 @@ def regroup(parser, token):
if lastbits_reversed[1][::-1] != 'as': if lastbits_reversed[1][::-1] != 'as':
raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'" raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'"
expression = parser.compile_filter('var.%s' % lastbits_reversed[2][::-1]) expression = parser.compile_filter(lastbits_reversed[2][::-1])
var_name = lastbits_reversed[0][::-1] var_name = lastbits_reversed[0][::-1]
return RegroupNode(target, expression, var_name) return RegroupNode(target, expression, var_name)

View File

@ -1,3 +1,8 @@
# This is a slightly modified version of the doctest.py that shipped with Python 2.4
# It incorporates changes that have been submitted the the Python ticket tracker
# as ticket #1521051. These changes allow for a DoctestRunner and Doctest base
# class to be specified when constructing a DoctestSuite.
# Module doctest. # Module doctest.
# Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org). # Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org).
# Major enhancements and refactoring by: # Major enhancements and refactoring by:

View File

@ -1,5 +1,6 @@
import unittest, doctest import unittest
from django.conf import settings from django.conf import settings
from django.test import _doctest as doctest
from django.test.utils import setup_test_environment, teardown_test_environment from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.utils import create_test_db, destroy_test_db from django.test.utils import create_test_db, destroy_test_db
from django.test.testcases import OutputChecker, DocTestRunner from django.test.testcases import OutputChecker, DocTestRunner

View File

@ -1,8 +1,9 @@
import re, doctest, unittest import re, unittest
from urlparse import urlparse from urlparse import urlparse
from django.db import transaction from django.db import transaction
from django.core import management, mail from django.core import management, mail
from django.db.models import get_apps from django.db.models import get_apps
from django.test import _doctest as doctest
from django.test.client import Client from django.test.client import Client
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)

View File

@ -73,6 +73,20 @@ def _set_autocommit(connection):
elif hasattr(connection.connection, "set_isolation_level"): elif hasattr(connection.connection, "set_isolation_level"):
connection.connection.set_isolation_level(0) connection.connection.set_isolation_level(0)
def get_mysql_create_suffix():
suffix = []
if settings.TEST_DATABASE_CHARSET:
suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)
if settings.TEST_DATABASE_COLLATION:
suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)
return ' '.join(suffix)
def get_postgresql_create_suffix():
assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
if settings.TEST_DATABASE_CHARSET:
return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
return ''
def create_test_db(verbosity=1, autoclobber=False): def create_test_db(verbosity=1, autoclobber=False):
if verbosity >= 1: if verbosity >= 1:
print "Creating test database..." print "Creating test database..."
@ -81,6 +95,12 @@ def create_test_db(verbosity=1, autoclobber=False):
if settings.DATABASE_ENGINE == "sqlite3": if settings.DATABASE_ENGINE == "sqlite3":
TEST_DATABASE_NAME = ":memory:" TEST_DATABASE_NAME = ":memory:"
else: else:
suffix = {
'postgresql': get_postgresql_create_suffix,
'postgresql_psycopg2': get_postgresql_create_suffix,
'mysql': get_mysql_create_suffix,
'mysql_old': get_mysql_create_suffix,
}.get(settings.DATABASE_ENGINE, lambda: '')()
if settings.TEST_DATABASE_NAME: if settings.TEST_DATABASE_NAME:
TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
else: else:
@ -92,7 +112,7 @@ def create_test_db(verbosity=1, autoclobber=False):
cursor = connection.cursor() cursor = connection.cursor()
_set_autocommit(connection) _set_autocommit(connection)
try: try:
cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
except Exception, e: except Exception, e:
sys.stderr.write("Got an error creating the test database: %s\n" % e) sys.stderr.write("Got an error creating the test database: %s\n" % e)
if not autoclobber: if not autoclobber:
@ -104,7 +124,7 @@ def create_test_db(verbosity=1, autoclobber=False):
cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME))
if verbosity >= 1: if verbosity >= 1:
print "Creating test database..." print "Creating test database..."
cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
except Exception, e: except Exception, e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e) sys.stderr.write("Got an error recreating the test database: %s\n" % e)
sys.exit(2) sys.exit(2)

View File

@ -168,6 +168,8 @@ class Rss201rev2Feed(RssFeed):
(item['author_email'], item['author_name'])) (item['author_email'], item['author_name']))
elif item["author_email"]: elif item["author_email"]:
handler.addQuickElement(u"author", item["author_email"]) handler.addQuickElement(u"author", item["author_email"])
elif item["author_name"]:
handler.addQuickElement(u"dc:creator", item["author_name"], {"xmlns:dc": u"http://purl.org/dc/elements/1.1/"})
if item['pubdate'] is not None: if item['pubdate'] is not None:
handler.addQuickElement(u"pubDate", rfc2822_date(item['pubdate']).decode('ascii')) handler.addQuickElement(u"pubDate", rfc2822_date(item['pubdate']).decode('ascii'))

View File

@ -6,8 +6,9 @@ Django aims to follow Python's `"batteries included" philosophy`_. It ships
with a variety of extra, optional tools that solve common Web-development with a variety of extra, optional tools that solve common Web-development
problems. problems.
This code lives in ``django/contrib`` in the Django distribution. Here's a This code lives in ``django/contrib`` in the Django distribution. This document
rundown of the packages in ``contrib``: gives a rundown of the packages in ``contrib``, along with any dependencies
those packages have.
.. admonition:: Note .. admonition:: Note
@ -26,6 +27,8 @@ The automatic Django administrative interface. For more information, see
.. _Tutorial 2: ../tutorial02/ .. _Tutorial 2: ../tutorial02/
Requires the auth_ and contenttypes_ contrib packages to be installed.
auth auth
==== ====
@ -144,6 +147,8 @@ See the `flatpages documentation`_.
.. _flatpages documentation: ../flatpages/ .. _flatpages documentation: ../flatpages/
Requires the sites_ contrib package to be installed as well.
localflavor localflavor
=========== ===========

View File

@ -134,6 +134,15 @@ the database until you explicitly call ``save()``.
The ``save()`` method has no return value. The ``save()`` method has no return value.
Updating ``ForeignKey`` fields works exactly the same way; simply assign an
object of the right type to the field in question::
joe = Author.objects.create(name="Joe")
entry.author = joe
entry.save()
Django will complain if you try to assign an object of the wrong type.
How Django knows to UPDATE vs. INSERT How Django knows to UPDATE vs. INSERT
------------------------------------- -------------------------------------
@ -1229,8 +1238,8 @@ whose ``headline`` contains ``'Lennon'``::
Blog.objects.filter(entry__headline__contains='Lennon') Blog.objects.filter(entry__headline__contains='Lennon')
Escaping parenthesis and underscores in LIKE statements Escaping percent signs and underscores in LIKE statements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The field lookups that equate to ``LIKE`` SQL statements (``iexact``, The field lookups that equate to ``LIKE`` SQL statements (``iexact``,
``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith`` ``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``
@ -1748,7 +1757,8 @@ Shortcuts
As you develop views, you will discover a number of common idioms in the As you develop views, you will discover a number of common idioms in the
way you use the database API. Django encodes some of these idioms as way you use the database API. Django encodes some of these idioms as
shortcuts that can be used to simplify the process of writing views. shortcuts that can be used to simplify the process of writing views. These
functions are in the ``django.shortcuts`` module.
get_object_or_404() get_object_or_404()
------------------- -------------------

View File

@ -295,7 +295,7 @@ Serving static files with the development server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, the development server doesn't serve any static files for your site By default, the development server doesn't serve any static files for your site
(such as CSS files, images, things under ``MEDIA_ROOT_URL`` and so forth). If (such as CSS files, images, things under ``MEDIA_URL`` and so forth). If
you want to configure Django to serve static media, read the `serving static files`_ you want to configure Django to serve static media, read the `serving static files`_
documentation. documentation.
@ -403,9 +403,10 @@ this command to install the default apps.
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
give you the option of creating a superuser immediately. give you the option of creating a superuser immediately.
``syncdb`` will also search for and install any fixture named ``initial_data``. ``syncdb`` will also search for and install any fixture named ``initial_data``
See the documentation for ``loaddata`` for details on the specification of with an appropriate extension (e.g. ``json`` or ``xml``). See the
fixture data files. documentation for ``loaddata`` for details on the specification of fixture
data files.
test test
---- ----

View File

@ -203,7 +203,7 @@ This is probably the most common case, if you're using Django's admin site::
DocumentRoot /home/user/public_html DocumentRoot /home/user/public_html
Alias /media /home/user/python/django/contrib/admin/media Alias /media /home/user/python/django/contrib/admin/media
RewriteEngine On RewriteEngine On
RewriteRule ^/(media.*)$ /$1 [QSA,L] RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost> </VirtualHost>

View File

@ -99,6 +99,9 @@ which is a dictionary of the parameters captured in the URL.
dictionary is callable, the generic view will call it dictionary is callable, the generic view will call it
just before rendering the template. just before rendering the template.
* ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
**Example:** **Example:**
Given the following URL patterns:: Given the following URL patterns::

View File

@ -97,7 +97,9 @@ This file should also be located in your ``site-packages`` directory.
* If you're using Windows: ``C:\Python2.X\lib\site-packages`` * If you're using Windows: ``C:\Python2.X\lib\site-packages``
* If you're using MacOSX: ``/Library/Python2.X/site-packages`` * If you're using MacOSX: ``/Library/Python2.X/site-packages`` or
``/Library/Frameworks/Python.framework/Versions/2.X/lib/python2.X/site-packages/``
(in later releases).
Install the Django code Install the Django code
======================= =======================

View File

@ -269,6 +269,13 @@ For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and
upload a file on Jan. 15, 2007, it will be saved in the directory upload a file on Jan. 15, 2007, it will be saved in the directory
``/home/media/photos/2007/01/15``. ``/home/media/photos/2007/01/15``.
If you want to retrieve the upload file's on-disk filename, or a URL that
refers to that file, or the file's size, you can use the
``get_FOO_filename()``, ``get_FOO_url()`` and ``get_FOO_size()`` methods.
They are all documented here__.
__ ../db-api/#get-foo-filename
Note that whenever you deal with uploaded files, you should pay close attention Note that whenever you deal with uploaded files, you should pay close attention
to where you're uploading them and what type of files they are, to avoid to where you're uploading them and what type of files they are, to avoid
security holes. *Validate all uploaded files* so that you're sure the files are security holes. *Validate all uploaded files* so that you're sure the files are
@ -338,9 +345,14 @@ image. Has two extra optional arguments, ``height_field`` and
``width_field``, which, if set, will be auto-populated with the height and ``width_field``, which, if set, will be auto-populated with the height and
width of the image each time a model instance is saved. width of the image each time a model instance is saved.
In addition to the special ``get_FOO_*`` methods that are available for
``FileField``, an ``ImageField`` also has ``get_FOO_height()`` and
``get_FOO_width()`` methods. These are documented elsewhere_.
Requires the `Python Imaging Library`_. Requires the `Python Imaging Library`_.
.. _Python Imaging Library: http://www.pythonware.com/products/pil/ .. _Python Imaging Library: http://www.pythonware.com/products/pil/
.. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width
``IntegerField`` ``IntegerField``
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
@ -463,8 +475,10 @@ If ``True``, Django will store empty values as ``NULL`` in the database.
Default is ``False``. Default is ``False``.
Note that empty string values will always get stored as empty strings, not Note that empty string values will always get stored as empty strings, not
as ``NULL`` -- so use ``null=True`` for non-string fields such as integers, as ``NULL``. Only use ``null=True`` for non-string fields such as integers,
booleans and dates. booleans and dates. For both types of fields, you will also need to set
``blank=True`` if you wish to permit empty values in forms, as the ``null``
parameter only affects database storage (see blank_, below).
Avoid using ``null`` on string-based fields such as ``CharField`` and Avoid using ``null`` on string-based fields such as ``CharField`` and
``TextField`` unless you have an excellent reason. If a string-based field ``TextField`` unless you have an excellent reason. If a string-based field
@ -1846,14 +1860,15 @@ rows. Example::
row = cursor.fetchone() row = cursor.fetchone()
return row return row
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If ``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
you're not familiar with the Python DB-API, note that the SQL statement in (except when it comes to `transaction handling`_). If you're not familiar with
``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses
directly within the SQL. If you use this technique, the underlying database placeholders, ``"%s"``, rather than adding parameters directly within the SQL.
library will automatically add quotes and escaping to your parameter(s) as If you use this technique, the underlying database library will automatically
necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the add quotes and escaping to your parameter(s) as necessary. (Also note that
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is
the sake of consistency and sanity.) used by the SQLite Python bindings. This is for the sake of consistency and
sanity.)
A final note: If all you want to do is a custom ``WHERE`` clause, you can just A final note: If all you want to do is a custom ``WHERE`` clause, you can just
just the ``where``, ``tables`` and ``params`` arguments to the standard lookup just the ``where``, ``tables`` and ``params`` arguments to the standard lookup
@ -1861,6 +1876,7 @@ API. See `Other lookup options`_.
.. _Python DB-API: http://www.python.org/peps/pep-0249.html .. _Python DB-API: http://www.python.org/peps/pep-0249.html
.. _Other lookup options: ../db-api/#extra-params-select-where-tables .. _Other lookup options: ../db-api/#extra-params-select-where-tables
.. _transaction handling: ../transactions/
Overriding default model methods Overriding default model methods
-------------------------------- --------------------------------

View File

@ -51,9 +51,17 @@ whereas ``<Location>`` points at places in the URL structure of a Web site.
``<Directory>`` would be meaningless here. ``<Directory>`` would be meaningless here.
Also, if you've manually altered your ``PYTHONPATH`` to put your Django project Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
on it, you'll need to tell mod_python:: on it, you'll need to tell mod_python:
PythonPath "['/path/to/project'] + sys.path" .. parsed-literal::
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
**PythonPath "['/path/to/project'] + sys.path"**
</Location>
.. caution:: .. caution::
@ -211,6 +219,41 @@ Here are two recommended approaches:
2. Or, copy the admin media files so that they live within your Apache 2. Or, copy the admin media files so that they live within your Apache
document root. document root.
Using eggs with mod_python
==========================
If you installed Django from a Python egg_ or are using eggs in your Django
project, some extra configuration is required. Create an extra file in your
project (or somewhere else) that contains something like the following::
import os
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
Here, ``/some/directory`` is a directory that the Apache webserver process can
write to. It will be used as the location for any unpacking of code the eggs
need to do.
Then you have to tell mod_python to import this file before doing anything
else. This is done using the PythonImport_ directive to mod_python. You need
to ensure that you have specified the ``PythonInterpreter`` directive to
mod_python as described above__ (you need to do this even if you aren't
serving multiple installations in this case). Then add the ``PythonImport``
line inside the ``Location`` or ``VirtualHost`` section. For example::
PythonInterpreter my_django
PythonImport /path/to/my/project/file.py my_django
Note that you can use an absolute path here (or a normal dotted import path),
as described in the `mod_python manual`_. We use an absolute path in the
above example because if any Python path modifications are required to access
your project, they will not have been done at the time the ``PythonImport``
line is processed.
.. _Egg: http://peak.telecommunity.com/DevCenter/PythonEggs
.. _PythonImport: http://www.modpython.org/live/current/doc-html/dir-other-pimp.html
.. _mod_python manual: PythonImport_
__ `Multiple Django installations on the same Apache`_
Error handling Error handling
============== ==============
@ -256,3 +299,5 @@ as necessary.
.. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html .. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html
.. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp .. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp
.. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html .. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html

View File

@ -686,13 +686,13 @@ For example::
<form method="post"> <form method="post">
<ul class="myformclass"> <ul class="myformclass">
<li>{{ form.sender.label }} {{ form.sender.label }}</li> <li>{{ form.sender.label }} {{ form.sender }}</li>
<li class="helptext">{{ form.sender.help_text }}</li> <li class="helptext">{{ form.sender.help_text }}</li>
{% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</dd>{% endif %} {% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %}
<li>{{ form.subject.label }} {{ form.subject.label }}</li> <li>{{ form.subject.label }} {{ form.subject }}</li>
<li class="helptext">{{ form.subject.help_text }}</li> <li class="helptext">{{ form.subject.help_text }}</li>
{% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</dd>{% endif %} {% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %}
... ...
</ul> </ul>

View File

@ -44,6 +44,25 @@ This is useful if you want to serialize data directly to a file-like object
.. _HTTPResponse: ../request_response/#httpresponse-objects .. _HTTPResponse: ../request_response/#httpresponse-objects
Subset of fields
~~~~~~~~~~~~~~~~
If you only want a subset of fields to be serialized, you can
specify a `fields` argument to the serializer::
from django.core import serializers
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))
In this example, only the `name` and `size` attributes of each model will
be serialized.
.. note::
Depending on your model, you may find that it is not possible to deserialize
a model that only serializes a subset of its fields. If a serialized object
doesn't specify all the fields that are required by a model, the deserializer
will not be able to save deserialized instances.
Deserializing data Deserializing data
------------------ ------------------
@ -92,10 +111,14 @@ Django "ships" with a few included serializers:
``python`` Translates to and from "simple" Python objects (lists, dicts, ``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. used as a base for other serializers.
``yaml`` Serializes to YAML (Yet Another Markup Lanuage). This
serializer is only available if PyYAML_ is installed.
========== ============================================================== ========== ==============================================================
.. _json: http://json.org/ .. _json: http://json.org/
.. _simplejson: http://undefined.org/python/#simplejson .. _simplejson: http://undefined.org/python/#simplejson
.. _PyYAML: http://www.pyyaml.org/
Notes for specific serialization formats Notes for specific serialization formats
---------------------------------------- ----------------------------------------

View File

@ -264,6 +264,11 @@ MySQL will connect via a Unix socket to the specified socket. For example::
If you're using MySQL and this value *doesn't* start with a forward slash, then If you're using MySQL and this value *doesn't* start with a forward slash, then
this value is assumed to be the host. this value is assumed to be the host.
If you're using PostgreSQL, an empty string means to use a Unix domain socket
for the connection, rather than a network connection to localhost. If you
explictly need to use a TCP/IP connection on the local machine with
PostgreSQL, specify ``localhost`` here.
DATABASE_NAME DATABASE_NAME
------------- -------------
@ -771,7 +776,8 @@ Default::
("django.core.context_processors.auth", ("django.core.context_processors.auth",
"django.core.context_processors.debug", "django.core.context_processors.debug",
"django.core.context_processors.i18n") "django.core.context_processors.i18n",
"django.core.context_processors.media")
A tuple of callables that are used to populate the context in ``RequestContext``. A tuple of callables that are used to populate the context in ``RequestContext``.
These callables take a request object as their argument and return a dictionary These callables take a request object as their argument and return a dictionary
@ -820,15 +826,36 @@ misspelled) variables. See `How invalid variables are handled`_.
.. _How invalid variables are handled: ../templates_python/#how-invalid-variables-are-handled .. _How invalid variables are handled: ../templates_python/#how-invalid-variables-are-handled
TEST_RUNNER TEST_DATABASE_CHARSET
----------- ---------------------
Default: ``'django.test.simple.run_tests'`` **New in Django development version**
The name of the method to use for starting the test suite. See Default: ``None``
`Testing Django Applications`_.
.. _Testing Django Applications: ../testing/ The character set encoding used to create the test database. The value of this
string is passed directly through to the database, so its format is
backend-specific.
Supported for the PostgreSQL_ (``postgresql``, ``postgresql_psycopg2``) and MySQL_ (``mysql``, ``mysql_old``) backends.
.. _PostgreSQL: http://www.postgresql.org/docs/8.2/static/multibyte.html
.. _MySQL: http://www.mysql.org/doc/refman/5.0/en/charset-database.html
TEST_DATABASE_COLLATION
------------------------
**New in Django development version**
Default: ``None``
The collation order to use when creating the test database. This value is
passed directly to the backend, so its format is backend-specific.
Only supported for ``mysql`` and ``mysql_old`` backends (see `section 10.3.2`_
of the MySQL manual for details).
.. _section 10.3.2: http://www.mysql.org/doc/refman/5.0/en/charset-database.html
TEST_DATABASE_NAME TEST_DATABASE_NAME
------------------ ------------------
@ -840,6 +867,16 @@ The name of database to use when running the test suite. If a value of
.. _Testing Django Applications: ../testing/ .. _Testing Django Applications: ../testing/
TEST_RUNNER
-----------
Default: ``'django.test.simple.run_tests'``
The name of the method to use for starting the test suite. See
`Testing Django Applications`_.
.. _Testing Django Applications: ../testing/
TIME_FORMAT TIME_FORMAT
----------- -----------

View File

@ -91,9 +91,12 @@ Filters can be "chained." The output of one filter is applied to the next.
``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents, ``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents,
then converting line breaks to ``<p>`` tags. then converting line breaks to ``<p>`` tags.
Some filters take arguments. A filter argument looks like this: Some filters take arguments. A filter argument looks like this: ``{{
``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio``
``bio`` variable. Filter arguments always are in double quotes. variable.
Filter arguments that contain spaces must be quoted; for example, to join a list
with commas and spaced you'd use ``{{ list|join:", " }}``.
The `Built-in filter reference`_ below describes all the built-in filters. The `Built-in filter reference`_ below describes all the built-in filters.
@ -112,7 +115,7 @@ know how to write Python code.
Comments Comments
======== ========
To comment-out part of a template, use the comment syntax: ``{# #}``. To comment-out part of a line in a template, use the comment syntax: ``{# #}``.
For example, this template would render as ``'hello'``:: For example, this template would render as ``'hello'``::
@ -122,6 +125,12 @@ A comment can contain any template code, invalid or not. For example::
{# {% if foo %}bar{% else %} #} {# {% if foo %}bar{% else %} #}
This syntax can only be used for single-line comments (no newlines are
permitted between the ``{#`` and ``#}`` delimiters). If you need to comment
out a multiline portion of the template, see the ``comment`` tag, below__.
__ comment_
Template inheritance Template inheritance
==================== ====================
@ -843,10 +852,11 @@ The first argument is a path to a view function in the format
should be comma-separated values that will be used as positional and keyword should be comma-separated values that will be used as positional and keyword
arguments in the URL. All arguments required by the URLconf should be present. arguments in the URL. All arguments required by the URLconf should be present.
For example, suppose you have a view, ``app_name.client``, whose URLconf takes For example, suppose you have a view, ``app_views.client``, whose URLconf
a client ID. The URLconf line might look like this:: takes a client ID (here, ``client()`` is a method inside the views file
``app_views.py``). The URLconf line might look like this::
('^client/(\d+)/$', 'app_name.client') ('^client/(\d+)/$', 'app_views.client')
If this app's URLconf is included into the project's URLconf under a path If this app's URLconf is included into the project's URLconf under a path
such as this:: such as this::
@ -855,7 +865,7 @@ such as this::
...then, in a template, you can create a link to this view like this:: ...then, in a template, you can create a link to this view like this::
{% url app_name.client client.id %} {% url app_views.client client.id %}
The template tag will output the string ``/clients/client/123/``. The template tag will output the string ``/clients/client/123/``.

View File

@ -294,7 +294,8 @@ return a dictionary of items to be merged into the context. By default,
("django.core.context_processors.auth", ("django.core.context_processors.auth",
"django.core.context_processors.debug", "django.core.context_processors.debug",
"django.core.context_processors.i18n") "django.core.context_processors.i18n",
"django.core.context_processors.media")
Each processor is applied in order. That means, if one processor adds a Each processor is applied in order. That means, if one processor adds a
variable to the context and a second processor adds a variable with the same variable to the context and a second processor adds a variable with the same
@ -390,6 +391,15 @@ See the `internationalization docs`_ for more.
.. _LANGUAGE_CODE setting: ../settings/#language-code .. _LANGUAGE_CODE setting: ../settings/#language-code
.. _internationalization docs: ../i18n/ .. _internationalization docs: ../i18n/
django.core.context_processors.media
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
value of the `MEDIA_URL setting`_.
.. _MEDIA_URL setting: ../settings/#media-url
django.core.context_processors.request django.core.context_processors.request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -4,7 +4,7 @@ Testing Django applications
Automated testing is an extremely useful bug-killing tool for the modern Automated testing is an extremely useful bug-killing tool for the modern
Web developer. You can use a collection of tests -- a **test suite** -- to Web developer. You can use a collection of tests -- a **test suite** -- to
to solve, or avoid, a number of problems: solve, or avoid, a number of problems:
* When you're writing new code, you can use tests to validate your code * When you're writing new code, you can use tests to validate your code
works as expected. works as expected.
@ -147,7 +147,7 @@ doctests or unit tests are right for you.
If you've been using Python for a while, ``doctest`` will probably feel more If you've been using Python for a while, ``doctest`` will probably feel more
"pythonic". It's designed to make writing tests as easy as possible, so "pythonic". It's designed to make writing tests as easy as possible, so
there's no overhead of writing classes or methods; you simply put tests in there's no overhead of writing classes or methods; you simply put tests in
docstrings. This gives the added advantage of given your modules automatic docstrings. This gives the added advantage of giving your modules automatic
documentation -- well-written doctests can kill both the documentation and the documentation -- well-written doctests can kill both the documentation and the
testing bird with a single stone. testing bird with a single stone.
@ -571,6 +571,14 @@ database settings will the same as they would be for the project normally.
If you wish to use a name other than the default for the test database, If you wish to use a name other than the default for the test database,
you can use the ``TEST_DATABASE_NAME`` setting to provide a name. you can use the ``TEST_DATABASE_NAME`` setting to provide a name.
**New in Django development version:** For fine-grained control over the
character encoding of your database, use the ``TEST_DATABASE_CHARSET`` setting.
If you're using MySQL, you can also use the ``TEST_DATABASE_COLLATION`` setting
to control the particular collation used by the test database. See the
settings_ documentation for details of these advanced settings.
.. _settings: ../settings/
The test database is created by the user in the ``DATABASE_USER`` setting. The test database is created by the user in the ``DATABASE_USER`` setting.
This user needs to have sufficient privileges to create a new database on the This user needs to have sufficient privileges to create a new database on the
system. system.

View File

@ -60,9 +60,10 @@ arguments from the dictionary (an optional third item in the tuple).
For more on ``HTTPRequest`` objects, see the `request and response documentation`_. For more on ``HTTPRequest`` objects, see the `request and response documentation`_.
For more details on URLconfs, see the `URLconf documentation`_. For more details on URLconfs, see the `URLconf documentation`_.
When you ran ``python manage.py startproject mysite`` at the beginning of When you ran ``python django-admin.py startproject mysite`` at the beginning of
Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
automatically set your ``ROOT_URLCONF`` setting to point at that file:: automatically set your ``ROOT_URLCONF`` setting (in ``settings.py``) to point
at that file::
ROOT_URLCONF = 'mysite.urls' ROOT_URLCONF = 'mysite.urls'

View File

@ -48,6 +48,7 @@ So let's create a ``vote()`` function in ``mysite/polls/views.py``::
from django.shortcuts import get_object_or_404, render_to_response from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from mysite.polls.models import Choice, Poll from mysite.polls.models import Choice, Poll
# ... # ...
def vote(request, poll_id): def vote(request, poll_id):
@ -66,7 +67,7 @@ So let's create a ``vote()`` function in ``mysite/polls/views.py``::
# Always return an HttpResponseRedirect after successfully dealing # Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a # with POST data. This prevents data from being posted twice if a
# user hits the Back button. # user hits the Back button.
return HttpResponseRedirect('/polls/%s/results/' % p.id) return HttpResponseRedirect(reverse('mysite.polls.views.results', args=(p.id,)))
This code includes a few things we haven't covered yet in this tutorial: This code includes a few things we haven't covered yet in this tutorial:
@ -86,13 +87,29 @@ This code includes a few things we haven't covered yet in this tutorial:
* After incrementing the choice count, the code returns an * After incrementing the choice count, the code returns an
``HttpResponseRedirect`` rather than a normal ``HttpResponse``. ``HttpResponseRedirect`` rather than a normal ``HttpResponse``.
``HttpResponseRedirect`` takes a single argument: the URL to which the ``HttpResponseRedirect`` takes a single argument: the URL to which the
user will be redirected. You should leave off the "http://" and domain user will be redirected (see the following point for how we construct
name if you can. That helps your app become portable across domains. the URL in this case).
As the Python comment above points out, you should always return an As the Python comment above points out, you should always return an
``HttpResponseRedirect`` after successfully dealing with POST data. This ``HttpResponseRedirect`` after successfully dealing with POST data. This
tip isn't specific to Django; it's just good Web development practice. tip isn't specific to Django; it's just good Web development practice.
* We are using the ``reverse()`` function in the ``HttpResponseRedirect``
constructor in this example. This function helps avoid having to
hardcode a URL in the view function. It is given the name of the view
that we want to pass control to and the variable portion of the URL
pattern that points to that view. In this case, using the URLConf we set
up in Tutorial 3, this ``reverse()`` call will return a string like ::
'/polls/3/results/'
... where the ``3`` is the value of ``p.id``. This redirected URL will
then call the ``'results'`` view to display the final page. Note that
you need to use the full name of the view here (including the prefix).
For more information about ``reverse()``, see the `URL dispatcher`_
documentation.
As mentioned in Tutorial 3, ``request`` is a ``HTTPRequest`` object. For more As mentioned in Tutorial 3, ``request`` is a ``HTTPRequest`` object. For more
on ``HTTPRequest`` objects, see the `request and response documentation`_. on ``HTTPRequest`` objects, see the `request and response documentation`_.
@ -121,6 +138,7 @@ results page that gets updated each time you vote. If you submit the form
without having chosen a choice, you should see the error message. without having chosen a choice, you should see the error message.
.. _request and response documentation: ../request_response/ .. _request and response documentation: ../request_response/
.. _URL dispatcher: ../url_dispatch#reverse
Use generic views: Less code is better Use generic views: Less code is better
====================================== ======================================
@ -256,4 +274,8 @@ installments:
* Advanced admin features: Permissions * Advanced admin features: Permissions
* Advanced admin features: Custom JavaScript * Advanced admin features: Custom JavaScript
In the meantime, you can read through the rest of the `Django documentation`_
and start writing your own applications.
.. _Tutorial 3: ../tutorial03/ .. _Tutorial 3: ../tutorial03/
.. _Django documentation: http://www.djangoproject.com/documentation/

View File

@ -551,3 +551,38 @@ not restricted to valid Python names.
Putting a prefix on your URL names, perhaps derived from the application Putting a prefix on your URL names, perhaps derived from the application
name, will decrease the chances of collision. We recommend something like name, will decrease the chances of collision. We recommend something like
``myapp-comment`` instead of ``comment``. ``myapp-comment`` instead of ``comment``.
Utility methods
===============
reverse()
---------
If you need to use something similar to the ``{% url %}`` template tag in your
code, Django provides the ``django.core.urlresolvers.reverse()``. The
``reverse()`` function has the following signature::
reverse(viewname, urlconf=None, args=None, kwargs=None)
``viewname`` is either the function name (either a function reference, or the
string version of the name, if you used that form in ``urlpatterns``) or the
`URL pattern name`_. Normally, you won't need to worry about the
``urlconf`` parameter and will only pass in the positional and keyword
arguments to use in the URL matching. For example::
from django.core.urlresolvers import reverse
def myview(request):
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
.. _URL pattern name: `Naming URL patterns`_
permalink()
-----------
The ``permalink()`` decorator is useful for writing short methods that return
a full URL path. For example, a model's ``get_absolute_url()`` method. Refer
to the `model API documentation`_ for more information about ``permalink()``.
.. _model API documentation: ../model-api/#the-permalink-decorator

View File

@ -131,6 +131,27 @@ True
[('headline', 'Article 7'), ('id', 7)] [('headline', 'Article 7'), ('id', 7)]
[('headline', 'Article 1'), ('id', 1)] [('headline', 'Article 1'), ('id', 1)]
# you can use values() even on extra fields
>>> for d in Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_one'):
... i = d.items()
... i.sort()
... i
[('id', 5), ('id_plus_one', 6)]
[('id', 6), ('id_plus_one', 7)]
[('id', 4), ('id_plus_one', 5)]
[('id', 2), ('id_plus_one', 3)]
[('id', 3), ('id_plus_one', 4)]
[('id', 7), ('id_plus_one', 8)]
[('id', 1), ('id_plus_one', 2)]
# however, an exception FieldDoesNotExist will still be thrown
# if you try to access non-existent field (field that is neither on the model nor extra)
>>> Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_two')
Traceback (most recent call last):
...
FieldDoesNotExist: Article has no field named 'id_plus_two'
# if you don't specify which fields, all are returned # if you don't specify which fields, all are returned
>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}] >>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
True True

View File

@ -159,4 +159,8 @@ __test__ = {'API_TESTS':"""
>>> article.author >>> article.author
<Author: Agnes> <Author: Agnes>
# Serializer output can be restricted to a subset of fields
>>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date'))
[{"pk": "1", "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": "2", "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": "3", "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}]
"""} """}

View File

@ -3656,6 +3656,25 @@ u' id="header"'
u' class="news" title="Read this"' u' class="news" title="Read this"'
>>> flatatt({}) >>> flatatt({})
u'' u''
####################################
# Test accessing errors in clean() #
####################################
>>> class UserForm(Form):
... username = CharField(max_length=10)
... password = CharField(widget=PasswordInput)
... def clean(self):
... data = self.cleaned_data
... if not self.errors:
... data['username'] = data['username'].lower()
... return data
>>> f = UserForm({'username': 'SirRobin', 'password': 'blue'})
>>> f.is_valid()
True
>>> f.cleaned_data['username']
u'sirrobin'
""" """
__test__ = { __test__ = {

View File

@ -129,6 +129,9 @@ class M2MSelfData(models.Model):
class FKDataToField(models.Model): class FKDataToField(models.Model):
data = models.ForeignKey(UniqueAnchor, null=True, to_field='data') data = models.ForeignKey(UniqueAnchor, null=True, to_field='data')
class FKDataToO2O(models.Model):
data = models.ForeignKey(O2OData, null=True)
# The following test classes are for validating the # The following test classes are for validating the
# deserialization of objects that use a user-defined # deserialization of objects that use a user-defined
# field as the primary key. # field as the primary key.
@ -202,3 +205,7 @@ class USStatePKData(models.Model):
# class XMLPKData(models.Model): # class XMLPKData(models.Model):
# data = models.XMLField(primary_key=True) # data = models.XMLField(primary_key=True)
class ComplexModel(models.Model):
field1 = models.CharField(maxlength=10)
field2 = models.CharField(maxlength=10)
field3 = models.CharField(maxlength=10)

View File

@ -9,6 +9,7 @@ forward, backwards and self references.
import unittest, datetime import unittest, datetime
from cStringIO import StringIO
from django.utils.functional import curry from django.utils.functional import curry
from django.core import serializers from django.core import serializers
@ -197,6 +198,8 @@ The end."""),
(fk_obj, 451, FKDataToField, "UAnchor 2"), (fk_obj, 451, FKDataToField, "UAnchor 2"),
(fk_obj, 452, FKDataToField, None), (fk_obj, 452, FKDataToField, None),
(fk_obj, 460, FKDataToO2O, 300),
(data_obj, 500, Anchor, "Anchor 3"), (data_obj, 500, Anchor, "Anchor 3"),
(data_obj, 501, Anchor, "Anchor 4"), (data_obj, 501, Anchor, "Anchor 4"),
(data_obj, 502, UniqueAnchor, "UAnchor 2"), (data_obj, 502, UniqueAnchor, "UAnchor 2"),
@ -276,5 +279,41 @@ def serializerTest(format, self):
for (func, pk, klass, datum) in test_data: for (func, pk, klass, datum) in test_data:
func[1](self, pk, klass, datum) func[1](self, pk, klass, datum)
def fieldsTest(format, self):
# Clear the database first
management.flush(verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
obj.save()
# Serialize then deserialize the test database
serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3'))
result = serializers.deserialize(format, serialized_data).next()
# Check that the deserialized object contains data in only the serialized fields.
self.assertEqual(result.object.field1, 'first')
self.assertEqual(result.object.field2, '')
self.assertEqual(result.object.field3, 'third')
def streamTest(format, self):
# Clear the database first
management.flush(verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
obj.save()
# Serialize the test database to a stream
stream = StringIO()
serializers.serialize(format, [obj], indent=2, stream=stream)
# Serialize normally for a comparison
string_data = serializers.serialize(format, [obj], indent=2)
# Check that the two are the same
self.assertEqual(string_data, stream.buffer())
stream.close()
for format in serializers.get_serializer_formats(): for format in serializers.get_serializer_formats():
setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format)) setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))
setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format))
setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(fieldsTest, format))