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
|
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
|
||||||
|
@ -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__":
|
||||||
|
@ -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 #
|
||||||
############
|
############
|
||||||
|
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: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"
|
||||||
|
Binary file not shown.
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)']
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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:
|
||||||
|
@ -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'):
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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'))
|
||||||
|
@ -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
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -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()
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -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
|
||||||
----
|
----
|
||||||
|
@ -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>
|
||||||
|
@ -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::
|
||||||
|
@ -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
|
||||||
=======================
|
=======================
|
||||||
|
@ -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
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -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
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -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/``.
|
||||||
|
|
||||||
|
@ -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
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
@ -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/
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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"}}]
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
@ -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__ = {
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user