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:
parent
659d99b7af
commit
d34639b09b
2
AUTHORS
2
AUTHORS
@ -142,6 +142,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Joseph Kocherhans
|
||||
konrad@gwu.edu
|
||||
lakin.wecker@gmail.com
|
||||
Nick Lane <nick.lane.au@gmail.com>
|
||||
Stuart Langridge <http://www.kryogenix.org/>
|
||||
Nicola Larosa <nico@teknico.net>
|
||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||
@ -230,6 +231,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
viestards.lists@gmail.com
|
||||
Milton Waddams
|
||||
wam-djangobug@wamber.net
|
||||
wangchun <yaohua2000@gmail.com>
|
||||
Dan Watson <http://theidioteque.net/>
|
||||
Chris Wesseling <Chris.Wesseling@cwi.nl>
|
||||
charly.wilhelm@gmail.com
|
||||
|
@ -7,13 +7,13 @@ Can be run as a cronjob to clean out old data from the database (only expired
|
||||
sessions at the moment).
|
||||
"""
|
||||
|
||||
from django.db import backend, connection, transaction
|
||||
import datetime
|
||||
from django.db import transaction
|
||||
from django.contrib.sessions.models import Session
|
||||
|
||||
def clean_up():
|
||||
# Clean up old database records
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \
|
||||
(backend.quote_name('django_session'), backend.quote_name('expire_date')))
|
||||
"""Clean up expired sessions."""
|
||||
Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -144,6 +144,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.auth',
|
||||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
# '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
|
||||
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 #
|
||||
############
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -113,8 +113,8 @@ msgstr "Demà"
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||
msgid "Show"
|
||||
msgstr ""
|
||||
msgstr "Mostrar"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||
msgid "Hide"
|
||||
msgstr ""
|
||||
msgstr "Ocultar"
|
||||
|
Binary file not shown.
@ -481,8 +481,8 @@ msgid ""
|
||||
"database tables have been created, and make sure the database is readable by "
|
||||
"the appropriate user."
|
||||
msgstr ""
|
||||
"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, das "
|
||||
"die richtigen Datenbanktabellen angelegt wurden und bitte sicherstellen, das "
|
||||
"Etwas stimmt nicht mit der Datenbankkonfiguration. Bitte sicherstellen, dass "
|
||||
"die richtigen Datenbanktabellen angelegt wurden und "
|
||||
"die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist."
|
||||
|
||||
#: contrib/admin/templates/admin/login.html:17
|
||||
|
@ -38,8 +38,9 @@ USE_I18N = True
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT.
|
||||
# Example: "http://media.lawrence.com"
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||
|
@ -1,4 +1,5 @@
|
||||
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
__all__ = ['handler404', 'handler500', 'include', 'patterns', 'url']
|
||||
|
||||
@ -22,7 +23,10 @@ def url(regex, view, kwargs=None, name=None, prefix=''):
|
||||
# For include(...) processing.
|
||||
return RegexURLResolver(regex, view[0], kwargs)
|
||||
else:
|
||||
if prefix and isinstance(view, basestring):
|
||||
if isinstance(view, basestring):
|
||||
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)
|
||||
|
||||
|
@ -23,16 +23,19 @@ class LatestFreeCommentsFeed(Feed):
|
||||
self._site = Site.objects.get_current()
|
||||
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):
|
||||
return self.comments_class.objects.filter(site__pk=settings.SITE_ID, is_public=True)[:40]
|
||||
return self.get_query_set()[:40]
|
||||
|
||||
class LatestCommentsFeed(LatestFreeCommentsFeed):
|
||||
"""Feed of latest free comments on the current site"""
|
||||
|
||||
comments_class = Comment
|
||||
|
||||
def items(self):
|
||||
qs = LatestFreeCommentsFeed.items(self)
|
||||
def get_query_set(self):
|
||||
qs = super(LatestCommentsFeed, self).get_query_set()
|
||||
qs = qs.filter(is_removed=False)
|
||||
if settings.COMMENTS_BANNED_USERS_GROUP:
|
||||
where = ['user_id NOT IN (SELECT user_id FROM auth_users_group WHERE group_id = %s)']
|
||||
|
@ -42,6 +42,13 @@ def i18n(request):
|
||||
|
||||
return context_extras
|
||||
|
||||
def media(request):
|
||||
"""
|
||||
Adds media-related context variables to the context.
|
||||
|
||||
"""
|
||||
return {'MEDIA_URL': settings.MEDIA_URL}
|
||||
|
||||
def request(request):
|
||||
return {'request': request}
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ def validate(outfile=sys.stdout, silent_success=False):
|
||||
return
|
||||
outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
|
||||
except ImproperlyConfigured:
|
||||
outfile.write("Skipping validation because things aren't configured properly.")
|
||||
outfile.write("Skipping validation because things aren't configured properly.\n")
|
||||
validate.args = ''
|
||||
|
||||
def _check_for_validation_errors(app=None):
|
||||
|
@ -21,6 +21,8 @@ class Serializer(PythonSerializer):
|
||||
Convert a queryset to JSON.
|
||||
"""
|
||||
def end_serialization(self):
|
||||
self.options.pop('stream', None)
|
||||
self.options.pop('fields', None)
|
||||
simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options)
|
||||
|
||||
def getvalue(self):
|
||||
|
@ -37,6 +37,11 @@ class Serializer(base.Serializer):
|
||||
def handle_fk_field(self, obj, field):
|
||||
related = getattr(obj, field.name)
|
||||
if related is not None:
|
||||
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
|
||||
|
||||
|
@ -18,6 +18,8 @@ class Serializer(PythonSerializer):
|
||||
Convert a queryset to YAML.
|
||||
"""
|
||||
def end_serialization(self):
|
||||
self.options.pop('stream', None)
|
||||
self.options.pop('fields', None)
|
||||
yaml.dump(self.objects, self.stream, **self.options)
|
||||
|
||||
def getvalue(self):
|
||||
|
@ -82,7 +82,13 @@ class Serializer(base.Serializer):
|
||||
self._start_relational_field(field)
|
||||
related = getattr(obj, field.name)
|
||||
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:
|
||||
self.xml.addQuickElement("None")
|
||||
self.xml.endElement("field")
|
||||
|
@ -12,6 +12,9 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
def complain(*args, **kwargs):
|
||||
raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet."
|
||||
|
||||
def ignore(*args, **kwargs):
|
||||
pass
|
||||
|
||||
class DatabaseError(Exception):
|
||||
pass
|
||||
|
||||
@ -21,7 +24,7 @@ class IntegrityError(DatabaseError):
|
||||
class DatabaseWrapper:
|
||||
cursor = complain
|
||||
_commit = complain
|
||||
_rollback = complain
|
||||
_rollback = ignore
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
@ -554,9 +554,8 @@ class QuerySet(object):
|
||||
class ValuesQuerySet(QuerySet):
|
||||
def __init__(self, *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 = {}
|
||||
|
||||
def iterator(self):
|
||||
try:
|
||||
@ -566,13 +565,28 @@ class ValuesQuerySet(QuerySet):
|
||||
|
||||
# self._fields is a list of field names to fetch.
|
||||
if 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
|
||||
else: # Default to all fields.
|
||||
columns = [f.column 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]
|
||||
|
||||
# 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.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||
while 1:
|
||||
|
@ -75,7 +75,7 @@ class CommonMiddleware(object):
|
||||
# Use ETags, if requested.
|
||||
if settings.USE_ETAGS:
|
||||
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()
|
||||
else:
|
||||
response['ETag'] = etag
|
||||
|
@ -63,7 +63,7 @@ class BaseForm(StrAndUnicode):
|
||||
self.auto_id = auto_id
|
||||
self.prefix = prefix
|
||||
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
|
||||
# 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)
|
||||
return BoundField(self, field, name)
|
||||
|
||||
def _errors(self):
|
||||
def _get_errors(self):
|
||||
"Returns an ErrorDict for self.data"
|
||||
if self.__errors is None:
|
||||
if self._errors is None:
|
||||
self.full_clean()
|
||||
return self.__errors
|
||||
errors = property(_errors)
|
||||
return self._errors
|
||||
errors = property(_get_errors)
|
||||
|
||||
def is_valid(self):
|
||||
"""
|
||||
@ -189,11 +189,11 @@ class BaseForm(StrAndUnicode):
|
||||
|
||||
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.
|
||||
self.__errors = errors
|
||||
return
|
||||
self.cleaned_data = {}
|
||||
for name, field in self.fields.items():
|
||||
@ -208,14 +208,15 @@ class BaseForm(StrAndUnicode):
|
||||
value = getattr(self, 'clean_%s' % name)()
|
||||
self.cleaned_data[name] = value
|
||||
except ValidationError, e:
|
||||
errors[name] = e.messages
|
||||
self._errors[name] = e.messages
|
||||
if name in self.cleaned_data:
|
||||
del self.cleaned_data[name]
|
||||
try:
|
||||
self.cleaned_data = self.clean()
|
||||
except ValidationError, e:
|
||||
errors[NON_FIELD_ERRORS] = e.messages
|
||||
if errors:
|
||||
self._errors[NON_FIELD_ERRORS] = e.messages
|
||||
if self._errors:
|
||||
delattr(self, 'cleaned_data')
|
||||
self.__errors = errors
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
|
@ -782,7 +782,7 @@ class DecimalField(TextField):
|
||||
try:
|
||||
import decimal
|
||||
except ImportError:
|
||||
from django.utils import decimal
|
||||
from django.utils import _decimal as decimal
|
||||
try:
|
||||
return decimal.Decimal(data)
|
||||
except decimal.InvalidOperation, e:
|
||||
|
@ -479,7 +479,7 @@ class TokenParser(object):
|
||||
while i < len(subject) and subject[i] != c:
|
||||
i += 1
|
||||
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
|
||||
s = subject[p:i]
|
||||
while i < len(subject) and subject[i] in (' ', '\t'):
|
||||
|
@ -237,7 +237,7 @@ class RegroupNode(Node):
|
||||
return ''
|
||||
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
|
||||
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?
|
||||
if output and repr(output[-1]['grouper']) == repr(grouper):
|
||||
output[-1]['list'].append(obj)
|
||||
@ -847,7 +847,7 @@ def regroup(parser, token):
|
||||
if lastbits_reversed[1][::-1] != '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]
|
||||
return RegroupNode(target, expression, var_name)
|
||||
|
@ -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.
|
||||
# Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org).
|
||||
# Major enhancements and refactoring by:
|
@ -1,5 +1,6 @@
|
||||
import unittest, doctest
|
||||
import unittest
|
||||
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 create_test_db, destroy_test_db
|
||||
from django.test.testcases import OutputChecker, DocTestRunner
|
||||
|
@ -1,8 +1,9 @@
|
||||
import re, doctest, unittest
|
||||
import re, unittest
|
||||
from urlparse import urlparse
|
||||
from django.db import transaction
|
||||
from django.core import management, mail
|
||||
from django.db.models import get_apps
|
||||
from django.test import _doctest as doctest
|
||||
from django.test.client import Client
|
||||
|
||||
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
|
||||
|
@ -73,6 +73,20 @@ def _set_autocommit(connection):
|
||||
elif hasattr(connection.connection, "set_isolation_level"):
|
||||
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):
|
||||
if verbosity >= 1:
|
||||
print "Creating test database..."
|
||||
@ -81,6 +95,12 @@ def create_test_db(verbosity=1, autoclobber=False):
|
||||
if settings.DATABASE_ENGINE == "sqlite3":
|
||||
TEST_DATABASE_NAME = ":memory:"
|
||||
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:
|
||||
TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
|
||||
else:
|
||||
@ -92,7 +112,7 @@ def create_test_db(verbosity=1, autoclobber=False):
|
||||
cursor = connection.cursor()
|
||||
_set_autocommit(connection)
|
||||
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:
|
||||
sys.stderr.write("Got an error creating the test database: %s\n" % e)
|
||||
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))
|
||||
if verbosity >= 1:
|
||||
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:
|
||||
sys.stderr.write("Got an error recreating the test database: %s\n" % e)
|
||||
sys.exit(2)
|
||||
|
@ -168,6 +168,8 @@ class Rss201rev2Feed(RssFeed):
|
||||
(item['author_email'], item['author_name']))
|
||||
elif 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:
|
||||
handler.addQuickElement(u"pubDate", rfc2822_date(item['pubdate']).decode('ascii'))
|
||||
|
@ -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
|
||||
problems.
|
||||
|
||||
This code lives in ``django/contrib`` in the Django distribution. Here's a
|
||||
rundown of the packages in ``contrib``:
|
||||
This code lives in ``django/contrib`` in the Django distribution. This document
|
||||
gives a rundown of the packages in ``contrib``, along with any dependencies
|
||||
those packages have.
|
||||
|
||||
.. admonition:: Note
|
||||
|
||||
@ -26,6 +27,8 @@ The automatic Django administrative interface. For more information, see
|
||||
|
||||
.. _Tutorial 2: ../tutorial02/
|
||||
|
||||
Requires the auth_ and contenttypes_ contrib packages to be installed.
|
||||
|
||||
auth
|
||||
====
|
||||
|
||||
@ -144,6 +147,8 @@ See the `flatpages documentation`_.
|
||||
|
||||
.. _flatpages documentation: ../flatpages/
|
||||
|
||||
Requires the sites_ contrib package to be installed as well.
|
||||
|
||||
localflavor
|
||||
===========
|
||||
|
||||
|
@ -134,6 +134,15 @@ the database until you explicitly call ``save()``.
|
||||
|
||||
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
|
||||
-------------------------------------
|
||||
|
||||
@ -1229,8 +1238,8 @@ whose ``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``,
|
||||
``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``
|
||||
@ -1748,7 +1757,8 @@ Shortcuts
|
||||
|
||||
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
|
||||
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()
|
||||
-------------------
|
||||
|
@ -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
|
||||
(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`_
|
||||
documentation.
|
||||
|
||||
@ -403,9 +403,10 @@ this command to install the default apps.
|
||||
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
|
||||
give you the option of creating a superuser immediately.
|
||||
|
||||
``syncdb`` will also search for and install any fixture named ``initial_data``.
|
||||
See the documentation for ``loaddata`` for details on the specification of
|
||||
fixture data files.
|
||||
``syncdb`` will also search for and install any fixture named ``initial_data``
|
||||
with an appropriate extension (e.g. ``json`` or ``xml``). See the
|
||||
documentation for ``loaddata`` for details on the specification of fixture
|
||||
data files.
|
||||
|
||||
test
|
||||
----
|
||||
|
@ -203,7 +203,7 @@ This is probably the most common case, if you're using Django's admin site::
|
||||
DocumentRoot /home/user/public_html
|
||||
Alias /media /home/user/python/django/contrib/admin/media
|
||||
RewriteEngine On
|
||||
RewriteRule ^/(media.*)$ /$1 [QSA,L]
|
||||
RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
|
||||
</VirtualHost>
|
||||
|
@ -99,6 +99,9 @@ which is a dictionary of the parameters captured in the URL.
|
||||
dictionary is callable, the generic view will call it
|
||||
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:**
|
||||
|
||||
Given the following URL patterns::
|
||||
|
@ -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 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
|
||||
=======================
|
||||
|
@ -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
|
||||
``/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
|
||||
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
|
||||
@ -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 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`_.
|
||||
|
||||
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
||||
.. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width
|
||||
|
||||
``IntegerField``
|
||||
~~~~~~~~~~~~~~~~
|
||||
@ -463,8 +475,10 @@ If ``True``, Django will store empty values as ``NULL`` in the database.
|
||||
Default is ``False``.
|
||||
|
||||
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,
|
||||
booleans and dates.
|
||||
as ``NULL``. Only use ``null=True`` for non-string fields such as integers,
|
||||
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
|
||||
``TextField`` unless you have an excellent reason. If a string-based field
|
||||
@ -1846,14 +1860,15 @@ rows. Example::
|
||||
row = cursor.fetchone()
|
||||
return row
|
||||
|
||||
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If
|
||||
you're not familiar with the Python DB-API, note that the SQL statement in
|
||||
``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters
|
||||
directly within the SQL. If you use this technique, the underlying database
|
||||
library will automatically add quotes and escaping to your parameter(s) as
|
||||
necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the
|
||||
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
||||
the sake of consistency and sanity.)
|
||||
``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
|
||||
(except when it comes to `transaction handling`_). If you're not familiar with
|
||||
the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses
|
||||
placeholders, ``"%s"``, rather than adding parameters directly within the SQL.
|
||||
If you use this technique, the underlying database library will automatically
|
||||
add quotes and escaping to your parameter(s) as necessary. (Also note that
|
||||
Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is
|
||||
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
|
||||
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
|
||||
.. _Other lookup options: ../db-api/#extra-params-select-where-tables
|
||||
.. _transaction handling: ../transactions/
|
||||
|
||||
Overriding default model methods
|
||||
--------------------------------
|
||||
|
@ -51,9 +51,17 @@ whereas ``<Location>`` points at places in the URL structure of a Web site.
|
||||
``<Directory>`` would be meaningless here.
|
||||
|
||||
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::
|
||||
|
||||
@ -211,6 +219,41 @@ Here are two recommended approaches:
|
||||
2. Or, copy the admin media files so that they live within your Apache
|
||||
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
|
||||
==============
|
||||
|
||||
@ -256,3 +299,5 @@ as necessary.
|
||||
.. _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
|
||||
.. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html
|
||||
|
||||
|
||||
|
@ -686,13 +686,13 @@ For example::
|
||||
|
||||
<form method="post">
|
||||
<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>
|
||||
{% 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>
|
||||
{% 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>
|
||||
|
@ -44,6 +44,25 @@ This is useful if you want to serialize data directly to a file-like object
|
||||
|
||||
.. _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
|
||||
------------------
|
||||
|
||||
@ -92,10 +111,14 @@ Django "ships" with a few included serializers:
|
||||
``python`` Translates to and from "simple" Python objects (lists, dicts,
|
||||
strings, etc.). Not really all that useful on its own, but
|
||||
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/
|
||||
.. _simplejson: http://undefined.org/python/#simplejson
|
||||
.. _PyYAML: http://www.pyyaml.org/
|
||||
|
||||
Notes for specific serialization formats
|
||||
----------------------------------------
|
||||
|
@ -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
|
||||
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
|
||||
-------------
|
||||
|
||||
@ -771,7 +776,8 @@ Default::
|
||||
|
||||
("django.core.context_processors.auth",
|
||||
"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``.
|
||||
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
|
||||
|
||||
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
|
||||
`Testing Django Applications`_.
|
||||
Default: ``None``
|
||||
|
||||
.. _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
|
||||
------------------
|
||||
@ -840,6 +867,16 @@ The name of database to use when running the test suite. If a value of
|
||||
|
||||
.. _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
|
||||
-----------
|
||||
|
||||
|
@ -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,
|
||||
then converting line breaks to ``<p>`` tags.
|
||||
|
||||
Some filters take arguments. A filter argument looks like this:
|
||||
``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the
|
||||
``bio`` variable. Filter arguments always are in double quotes.
|
||||
Some filters take arguments. A filter argument looks like this: ``{{
|
||||
bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio``
|
||||
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.
|
||||
|
||||
@ -112,7 +115,7 @@ know how to write Python code.
|
||||
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'``::
|
||||
|
||||
@ -122,6 +125,12 @@ A comment can contain any template code, invalid or not. For example::
|
||||
|
||||
{# {% 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
|
||||
====================
|
||||
|
||||
@ -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
|
||||
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
|
||||
a client ID. The URLconf line might look like this::
|
||||
For example, suppose you have a view, ``app_views.client``, whose URLconf
|
||||
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
|
||||
such as this::
|
||||
@ -855,7 +865,7 @@ such as 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/``.
|
||||
|
||||
|
@ -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.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
|
||||
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
|
||||
.. _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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -4,7 +4,7 @@ Testing Django applications
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
"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
|
||||
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
|
||||
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,
|
||||
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.
|
||||
This user needs to have sufficient privileges to create a new database on the
|
||||
system.
|
||||
|
@ -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 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
|
||||
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'
|
||||
|
||||
|
@ -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.http import HttpResponseRedirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from mysite.polls.models import Choice, Poll
|
||||
# ...
|
||||
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
|
||||
# with POST data. This prevents data from being posted twice if a
|
||||
# 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:
|
||||
|
||||
@ -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
|
||||
``HttpResponseRedirect`` rather than a normal ``HttpResponse``.
|
||||
``HttpResponseRedirect`` takes a single argument: the URL to which the
|
||||
user will be redirected. You should leave off the "http://" and domain
|
||||
name if you can. That helps your app become portable across domains.
|
||||
user will be redirected (see the following point for how we construct
|
||||
the URL in this case).
|
||||
|
||||
As the Python comment above points out, you should always return an
|
||||
``HttpResponseRedirect`` after successfully dealing with POST data. This
|
||||
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
|
||||
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.
|
||||
|
||||
.. _request and response documentation: ../request_response/
|
||||
.. _URL dispatcher: ../url_dispatch#reverse
|
||||
|
||||
Use generic views: Less code is better
|
||||
======================================
|
||||
@ -256,4 +274,8 @@ installments:
|
||||
* Advanced admin features: Permissions
|
||||
* 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/
|
||||
.. _Django documentation: http://www.djangoproject.com/documentation/
|
||||
|
@ -551,3 +551,38 @@ not restricted to valid Python names.
|
||||
Putting a prefix on your URL names, perhaps derived from the application
|
||||
name, will decrease the chances of collision. We recommend something like
|
||||
``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
|
||||
|
||||
|
@ -131,6 +131,27 @@ True
|
||||
[('headline', 'Article 7'), ('id', 7)]
|
||||
[('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
|
||||
>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
|
||||
True
|
||||
|
@ -159,4 +159,8 @@ __test__ = {'API_TESTS':"""
|
||||
>>> article.author
|
||||
<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"}}]
|
||||
|
||||
"""}
|
||||
|
@ -3656,6 +3656,25 @@ u' id="header"'
|
||||
u' class="news" title="Read this"'
|
||||
>>> flatatt({})
|
||||
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__ = {
|
||||
|
@ -129,6 +129,9 @@ class M2MSelfData(models.Model):
|
||||
class FKDataToField(models.Model):
|
||||
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
|
||||
# deserialization of objects that use a user-defined
|
||||
# field as the primary key.
|
||||
@ -202,3 +205,7 @@ class USStatePKData(models.Model):
|
||||
# class XMLPKData(models.Model):
|
||||
# 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)
|
||||
|
@ -9,6 +9,7 @@ forward, backwards and self references.
|
||||
|
||||
|
||||
import unittest, datetime
|
||||
from cStringIO import StringIO
|
||||
|
||||
from django.utils.functional import curry
|
||||
from django.core import serializers
|
||||
@ -197,6 +198,8 @@ The end."""),
|
||||
(fk_obj, 451, FKDataToField, "UAnchor 2"),
|
||||
(fk_obj, 452, FKDataToField, None),
|
||||
|
||||
(fk_obj, 460, FKDataToO2O, 300),
|
||||
|
||||
(data_obj, 500, Anchor, "Anchor 3"),
|
||||
(data_obj, 501, Anchor, "Anchor 4"),
|
||||
(data_obj, 502, UniqueAnchor, "UAnchor 2"),
|
||||
@ -276,5 +279,41 @@ def serializerTest(format, self):
|
||||
for (func, pk, klass, datum) in test_data:
|
||||
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():
|
||||
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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user