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

queryset-refactor: Merged from trunk up to [6752].

git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6753 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-11-29 20:38:41 +00:00
parent b43a018032
commit dfe05d94b8
47 changed files with 3797 additions and 2231 deletions

View File

@ -71,6 +71,7 @@ answer newbie questions, and generally made Django that much better:
Jonathan Buchanan <jonathan.buchanan@gmail.com>
Trevor Caira <trevor@caira.com>
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
Graham Carlyle <graham.carlyle@maplecroft.net>
Antonio Cavedoni <http://cavedoni.com/>
C8E
cedric@terramater.net
@ -100,6 +101,7 @@ answer newbie questions, and generally made Django that much better:
Alex Dedul
deric@monowerks.com
Max Derkachev <mderk@yandex.ru>
Rajesh Dhawan <rajesh.dhawan@gmail.com>
Sander Dijkhuis <sander.dijkhuis@gmail.com>
Jordan Dimov <s3x3y1@gmail.com>
dne@mayonnaise.net
@ -187,6 +189,7 @@ answer newbie questions, and generally made Django that much better:
krzysiek.pawlik@silvermedia.pl
Joseph Kocherhans
konrad@gwu.edu
knox <christobzr@gmail.com>
kurtiss@meetro.com
lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
@ -273,6 +276,7 @@ answer newbie questions, and generally made Django that much better:
Vinay Sajip <vinay_sajip@yahoo.co.uk>
David Schein
scott@staplefish.com
Ilya Semenov <semenov@inetss.com>
serbaut@gmail.com
John Shaffer <jshaffer2112@gmail.com>
Pete Shinners <pete@shinners.org>

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,12 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
"POT-Creation-Date: 2007-11-29 10:58-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: contrib/admin/media/js/SelectFilter2.js:33
@ -45,64 +45,73 @@ msgstr ""
msgid "Clear all"
msgstr ""
#: contrib/admin/media/js/dateparse.js:26
#: contrib/admin/media/js/calendar.js:24
#: contrib/admin/media/js/dateparse.js:32
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
#: contrib/admin/media/js/dateparse.js:27
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
#: contrib/admin/media/js/calendar.js:25
msgid "S M T W T F S"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
msgid "Show"
msgstr ""
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
msgid "Hide"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr ""
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr ""

View File

@ -13,7 +13,7 @@
{% for library in filter_libraries %}
<div class="module">
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
{% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
{% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr />{% endif %}
{% for filter in library.list|dictsort:"name" %}
<h3 id="{{ filter.name }}">{{ filter.name }}</h3>
<p>{{ filter.title }}</p>

View File

@ -13,7 +13,7 @@
{% for library in tag_libraries %}
<div class="module">
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
{% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
{% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr />{% endif %}
{% for tag in library.list|dictsort:"name" %}
<h3 id="{{ tag.name }}">{{ tag.name }}</h3>
<h4>{{ tag.title }}</h4>

View File

@ -29,10 +29,10 @@
{% for view in site_views.list|dictsort:"url" %}
{% ifchanged %}
<h3><a href="{{ view.module }}.{{ view.name }}/"/>{{ view.url|escape }}</a></h3>
<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url|escape }}</a></h3>
<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
<p>{{ view.title }}</p>
<hr>
<hr />
{% endifchanged %}
{% endfor %}
</div>

View File

@ -102,7 +102,7 @@ class Comment(models.Model):
date_hierarchy = 'submit_date'
search_fields = ('comment', 'user__username')
def __repr__(self):
def __unicode__(self):
return "%s: %s..." % (self.user.username, self.comment[:100])
def get_absolute_url(self):
@ -190,7 +190,7 @@ class FreeComment(models.Model):
date_hierarchy = 'submit_date'
search_fields = ('comment', 'person_name')
def __repr__(self):
def __unicode__(self):
return "%s: %s..." % (self.person_name, self.comment[:100])
def get_absolute_url(self):
@ -244,7 +244,7 @@ class KarmaScore(models.Model):
verbose_name_plural = _('karma scores')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("%(score)d rating by %(user)s") % {'score': self.score, 'user': self.user}
class UserFlagManager(models.Manager):
@ -275,7 +275,7 @@ class UserFlag(models.Model):
verbose_name_plural = _('user flags')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("Flag by %r") % self.user
class ModeratorDeletion(models.Model):
@ -287,5 +287,5 @@ class ModeratorDeletion(models.Model):
verbose_name_plural = _('moderator deletions')
unique_together = (('user', 'comment'),)
def __repr__(self):
def __unicode__(self):
return _("Moderator deletion by %r") % self.user

View File

@ -0,0 +1,13 @@
# coding: utf-8
r"""
>>> from django.contrib.comments.models import Comment
>>> from django.contrib.auth.models import User
>>> u = User.objects.create_user('commenttestuser', 'commenttest@example.com', 'testpw')
>>> c = Comment(user=u, comment=u'\xe2')
>>> c
<Comment: commenttestuser: â...>
>>> print c
commenttestuser: â...
"""

View File

@ -0,0 +1 @@
""" models.py (even empty) currently required by the runtests.py to enable unit tests """

View File

@ -0,0 +1,12 @@
"""
This is a urlconf to be loaded by tests.py. Add any urls needed
for tests only.
"""
from django.conf.urls.defaults import *
from django.contrib.formtools.tests import *
urlpatterns = patterns('',
(r'^test1/', TestFormPreview(TestForm)),
)

View File

@ -0,0 +1,93 @@
from django import newforms as forms
from django.contrib.formtools import preview
from django import http
from django.conf import settings
from django.test import TestCase
from django.test.client import Client
success_string = "Done was called!"
test_data = {'field1': u'foo',
'field1_': u'asdf'}
class TestFormPreview(preview.FormPreview):
def done(self, request, cleaned_data):
return http.HttpResponse(success_string)
class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
class PreviewTests(TestCase):
def setUp(self):
settings.ROOT_URLCONF = 'django.contrib.formtools.test_urls'
# Create a FormPreview instance to share between tests
self.preview = preview.FormPreview(TestForm)
input_template = '<input type="hidden" name="%s" value="%s" />'
self.input = input_template % (self.preview.unused_name('stage'), "%d")
def test_unused_name(self):
"""
Verifies name mangling to get uniue field name.
"""
self.assertEqual(self.preview.unused_name('field1'), 'field1__')
def test_form_get(self):
"""
Test contrib.formtools.preview form retrieval.
Use the client library to see if we can sucessfully retrieve
the form (mostly testing the setup ROOT_URLCONF
process). Verify that an additional hidden input field
is created to manage the stage.
"""
response = self.client.get('/test1/')
stage = self.input % 1
self.assertContains(response, stage, 1)
def test_form_preview(self):
"""
Test contrib.formtools.preview form preview rendering.
Use the client library to POST to the form to see if a preview
is returned. If we do get a form back check that the hidden
value is correctly managing the state of the form.
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
test_data.update({'stage': 1})
response = self.client.post('/test1/', test_data)
# Check to confirm stage is set to 2 in output form.
stage = self.input % 2
self.assertContains(response, stage, 1)
def test_form_submit(self):
"""
Test contrib.formtools.preview form submittal.
Use the client library to POST to the form with stage set to 3
to see if our forms done() method is called. Check first
without the security hash, verify failure, retry with security
hash and verify sucess.
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
test_data.update({'stage': 2})
response = self.client.post('/test1/', test_data)
self.failIfEqual(response.content, success_string)
hash = self.preview.security_hash(None, TestForm(test_data))
test_data.update({'hash': hash})
response = self.client.post('/test1/', test_data)
self.assertEqual(response.content, success_string)
if __name__ == '__main__':
unittest.main()

View File

@ -33,6 +33,8 @@ PROVINCES_NORMALIZED = {
'british columbia': 'BC',
'mb': 'MB',
'manitoba': 'MB',
'nb': 'NB',
'new brunswick': 'NB',
'nf': 'NF',
'newfoundland': 'NF',
'newfoundland and labrador': 'NF',

View File

@ -471,5 +471,5 @@ def method_get_order(ordered_obj, self):
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
##############################################
def get_absolute_url(opts, func, self):
return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self)
def get_absolute_url(opts, func, self, *args, **kwargs):
return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self, *args, **kwargs)

View File

@ -399,7 +399,7 @@ class Field(object):
"Returns a django.newforms.Field instance for this database Field."
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
if self.choices:
defaults['widget'] = forms.Select(choices=self.get_choices())
defaults['widget'] = forms.Select(choices=self.get_choices(include_blank=self.blank or not (self.has_default() or 'initial' in kwargs)))
if self.has_default():
defaults['initial'] = self.get_default()
defaults.update(kwargs)

View File

@ -28,10 +28,10 @@ class Creator(object):
def __get__(self, obj, type=None):
if obj is None:
raise AttributeError('Can only be accessed via an instance.')
return self.value
return obj.__dict__[self.field.name]
def __set__(self, obj, value):
self.value = self.field.to_python(value)
obj.__dict__[self.field.name] = self.field.to_python(value)
def make_contrib(func=None):
"""

View File

@ -1,14 +1,18 @@
from django.conf import settings
from django.core.cache import cache
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
class CacheMiddleware(object):
"""
Cache middleware. If this is enabled, each Django-powered page will be
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs.
cached (based on URLs).
Only parameter-less GET or HEAD-requests with status code 200 are cached.
The number of seconds each page is stored for is set by the
"max-age" section of the response's "Cache-Control" header, falling back to
the CACHE_MIDDLEWARE_SECONDS setting if the section was not found.
If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
(i.e., those not made by a logged-in user) will be cached. This is a
simple and effective way of avoiding the caching of the Django admin (and
@ -78,7 +82,16 @@ class CacheMiddleware(object):
return response
if not response.status_code == 200:
return response
patch_response_headers(response, self.cache_timeout)
cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix)
cache.set(cache_key, response, self.cache_timeout)
# Try to get the timeout from the "max-age" section of the "Cache-
# Control" header before reverting to using the default cache_timeout
# length.
timeout = get_max_age(response)
if timeout == None:
timeout = self.cache_timeout
elif timeout == 0:
# max-age was set to 0, don't bother caching.
return response
patch_response_headers(response, timeout)
cache_key = learn_cache_key(request, response, timeout, self.key_prefix)
cache.set(cache_key, response, timeout)
return response

View File

@ -17,7 +17,7 @@ except NameError:
from sets import Set as set
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import StrAndUnicode, smart_unicode
from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
from util import ErrorList, ValidationError
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
@ -235,7 +235,7 @@ class DecimalField(Field):
super(DecimalField, self).clean(value)
if not self.required and value in EMPTY_VALUES:
return None
value = str(value).strip()
value = smart_str(value).strip()
try:
value = Decimal(value)
except DecimalException:
@ -536,11 +536,12 @@ class BooleanField(Field):
widget = CheckboxInput
def clean(self, value):
"Returns a Python boolean object."
"""Returns a Python boolean object."""
super(BooleanField, self).clean(value)
# Explicitly check for the string '0', which is what as hidden field
# will submit for False.
if value == '0':
# Explicitly check for the string 'False', which is what a hidden field
# will submit for False (since bool("True") == True we don't need to
# handle that explicitly).
if value == 'False':
return False
return bool(value)

View File

@ -25,8 +25,8 @@ def stringfilter(func):
if args:
args = list(args)
args[0] = force_unicode(args[0])
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
return mark_safe(func(*args, **kwargs))
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
return mark_safe(func(*args, **kwargs))
return func(*args, **kwargs)
# Include a reference to the real function (used to check original
@ -91,7 +91,7 @@ def floatformat(text, arg=-1):
"""
try:
f = float(text)
except ValueError:
except (ValueError, TypeError):
return u''
try:
d = int(arg)

View File

@ -74,6 +74,21 @@ def patch_cache_control(response, **kwargs):
cc = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc
def get_max_age(response):
"""
Returns the max-age from the response Cache-Control header as an integer
(or ``None`` if it wasn't found or wasn't an integer.
"""
if not response.has_header('Cache-Control'):
return
cc = dict([_to_tuple(el) for el in
cc_delim_re.split(response['Cache-Control'])])
if 'max-age' in cc:
try:
return int(cc['max-age'])
except (ValueError, TypeError):
pass
def patch_response_headers(response, cache_timeout=None):
"""
Adds some useful headers to the given HttpResponse object:
@ -180,3 +195,10 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
# for the request.path
cache.set(cache_key, [], cache_timeout)
return _generate_cache_key(request, [], key_prefix)
def _to_tuple(s):
t = s.split('=',1)
if len(t) == 2:
return t[0].lower(), t[1]
return t[0].lower(), True

View File

@ -60,7 +60,10 @@ class SortedDict(dict):
if isinstance(data, dict):
self.keyOrder = data.keys()
else:
self.keyOrder = [key for key, value in data]
self.keyOrder = []
for key, value in data:
if key not in self.keyOrder:
self.keyOrder.append(key)
def __deepcopy__(self, memo):
from copy import deepcopy

View File

@ -54,6 +54,12 @@ class LocalTimezone(tzinfo):
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
stamp = time.mktime(tt)
try:
stamp = time.mktime(tt)
except OverflowError:
# 32 bit systems can't handle dates after Jan 2038, so we fake it
# in that case (since we only care about the DST flag here).
tt = (2037,) + tt[1:]
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0

View File

@ -120,8 +120,12 @@ def javascript_catalog(request, domain='djangojs', packages=None):
p = __import__(package, {}, {}, [''])
path = os.path.join(os.path.dirname(p.__file__), 'locale')
paths.append(path)
catalog = gettext_module.translation(domain, path, ['en'])
t.update(catalog._catalog)
try:
catalog = gettext_module.translation(domain, path, ['en'])
t.update(catalog._catalog)
except IOError:
# 'en' catalog was missing. This is harmless.
pass
# next load the settings.LANGUAGE_CODE translations if it isn't english
if default_locale != 'en':
for path in paths:

View File

@ -33,6 +33,7 @@ def serve(request, path, document_root=None, show_indexes=False):
# Clean up given path to only allow serving files below document_root.
path = posixpath.normpath(urllib.unquote(path))
path = path.lstrip('/')
newpath = ''
for part in path.split('/'):
if not part:

View File

@ -170,7 +170,7 @@ The ``User`` model has a custom manager that has the following helper functions:
If no password is provided, ``set_unusable_password()`` will be called.
See _`Creating users` for example usage.
See `Creating users`_ for example usage.
* ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')``
Returns a random password with the given length and given string of

View File

@ -263,6 +263,18 @@ See the `middleware documentation`_ for more on middleware.
.. _`middleware documentation`: ../middleware/
**New in Django development version**
If a view sets its own cache expiry time (i.e. it has a ``max-age`` section in
its ``Cache-Control`` header) then the page will be cached until the expiry
time, rather than ``CACHE_MIDDLEWARE_SECONDS``. Using the decorators in
``django.views.decorators.cache`` you can easily set a view's expiry time
(using the ``cache_control`` decorator) or disable caching for a view (using
the ``never_cache`` decorator). See the `using other headers`__ section for
more on these decorators.
__ `Controlling cache: Using other headers`_
The per-view cache
==================
@ -566,7 +578,7 @@ the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
precedence, and the header values will be merged correctly.)
If you want to use headers to disable caching altogether,
``django.views.decorators.never_cache`` is a view decorator that adds
``django.views.decorators.cache.never_cache`` is a view decorator that adds
headers to ensure the response won't be cached by browsers or other caches. Example::
from django.views.decorators.cache import never_cache

View File

@ -184,9 +184,9 @@ is being executed as an unattended, automated script.
Use ``--verbosity`` to specify the amount of notification and debug information
that ``django-admin.py`` should print to the console.
* ``0`` means no input.
* ``1`` means normal input (default).
* ``2`` means verbose input.
* ``0`` means no output.
* ``1`` means normal output (default).
* ``2`` means verbose output.
Example usage::
@ -651,7 +651,7 @@ To run the test server on port 7000 with ``fixture1`` and ``fixture2``::
that it doesn't matter whether the options come before or after the fixture
arguments.)
To run on 1.2.3.4:7000 with a `test` fixture::
To run on 1.2.3.4:7000 with a ``test`` fixture::
django-admin.py testserver --addrport 1.2.3.4:7000 test

View File

@ -187,10 +187,10 @@ latest bug fixes and improvements, follow these instructions:
"Where are my ``site-packages`` stored?" section above.)
Alternatively, you can define your ``PYTHONPATH`` environment variable
so that it includes the ``django`` subdirectory of ``django-trunk``.
This is perhaps the most convenient solution on Windows systems, which
don't support symbolic links. (Environment variables can be defined on
Windows systems `from the Control Panel`_.)
so that it includes the ``django-trunk`` directory. This is perhaps the
most convenient solution on Windows systems, which don't support symbolic
links. (Environment variables can be defined on Windows systems `from the
Control Panel`_.)
.. admonition:: What about Apache and mod_python?
@ -204,11 +204,18 @@ latest bug fixes and improvements, follow these instructions:
.. _How to use Django with mod_python: ../modpython/
4. Copy the file ``django-trunk/django/bin/django-admin.py`` to somewhere on
your system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
(Windows). This step simply lets you type ``django-admin.py`` from within
any directory, rather than having to qualify the command with the full path
to the file.
4. On Unix-like systems, create a symbolic link to the file
``django-trunk/django/bin/django-admin.py`` in a directory on your system
path, such as ``/usr/local/bin``. For example::
ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin
This simply lets you type ``django-admin.py`` from within any directory,
rather than having to qualify the command with the full path to the file.
On Windows systems, the same result can be achieved by copying the file
``django-trunk/django/bin/django-admin.py`` to somewhere on your system
path, for example ``C:\Python24\Scripts``.
You *don't* have to run ``python setup.py install``, because you've already
carried out the equivalent actions in steps 3 and 4.

View File

@ -50,7 +50,7 @@ The above ``Person`` model would create a database table like this::
Some technical notes:
* The name of the table, ``myapp_person``, is automatically derived from
some model metadata but can be overridden. See _`Table names` below.
some model metadata but can be overridden. See `Table names`_ below.
* An ``id`` field is added automatically, but this behavior can be
overriden. See `Automatic primary key fields`_ below.
* The ``CREATE TABLE`` SQL in this example is formatted using PostgreSQL
@ -1664,7 +1664,7 @@ Adding extra Manager methods
Adding extra ``Manager`` methods is the preferred way to add "table-level"
functionality to your models. (For "row-level" functionality -- i.e., functions
that act on a single instance of a model object -- use _`Model methods`, not
that act on a single instance of a model object -- use `Model methods`_, not
custom ``Manager`` methods.)
A custom ``Manager`` method can return anything you want. It doesn't have to

View File

@ -753,6 +753,30 @@ For example::
</ul>
</form>
Highlighting required fields in templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You may wish to show a visitor which fields are required. Here is the above
example modified to insert an asterix after the label of each required field::
<form method="post" action="">
<dl>
{% for field in form %}
<dt>{{ field.label_tag }}{{ field.label }}{% if field.field.required %}*{% endif %}</dt>
<dd>{{ field }}</dd>
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
{% endfor %}
</dl>
<input type="submit" />
</form>
The ``{% if field.field.required %}*{% endif %}`` fragment is the relevant
addition here. It adds the asterix only if the field is required. Note that we
check ``field.field.required`` and not ``field.required``. In the template,
``field`` is a ``newforms.forms.BoundField`` instance, which holds the actual
``Field`` instance in its ``field`` attribute.
Binding uploaded files to a form
--------------------------------
@ -1849,7 +1873,11 @@ In addition, each generated form field has attributes set as follows:
* If the model field has ``choices`` set, then the form field's ``widget``
will be set to ``Select``, with choices coming from the model field's
``choices``.
``choices``. The choices will normally include the blank choice which is
selected by default. If the field is required, this forces the user to
make a selection. The blank choice will not be included if the model
field has ``blank=False`` and an explicit ``default`` value (the
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
field. See "Overriding the default field types" below.
@ -2095,10 +2123,14 @@ instance instead of a model class::
# Instantiate the form.
>>> f = AuthorForm()
When a form created by ``form_for_instance()`` is created, the initial
data values for the form fields are drawn from the instance. However,
this data is not bound to the form. You will need to bind data to the
form before the form can be saved.
When a form created by ``form_for_instance()`` is created, the initial data
values for the form fields are drawn from the instance. However, this data is
not bound to the form. You will need to bind data to the form before the form
can be saved.
Unlike ``form_for_model()``, a choice field in form created by
``form_for_instance()`` will not include the blank choice if the respective
model field has ``blank=False``. The initial choice is drawn from the instance.
When you call ``save()`` on a form created by ``form_for_instance()``,
the database instance will be updated. As in ``form_for_model()``, ``save()``

View File

@ -44,7 +44,7 @@ to this::
DATABASE_ENGINE = "mysql_old"
However, we strongly encourage MySQL users to upgrade to a more recent
version of `MySQLdb` as soon as possible, The "mysql_old" backend is
version of ``MySQLdb`` as soon as possible, The "mysql_old" backend is
provided only to ease this transition, and is considered deprecated;
aside from any necessary security fixes, it will not be actively
maintained, and it will be removed in a future release of Django.

View File

@ -201,6 +201,8 @@ the feed.
An example makes this clear. Here's the code for these beat-specific feeds::
from django.contrib.syndication import FeedDoesNotExist
class BeatFeed(Feed):
def get_object(self, bits):
# In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter,
@ -213,6 +215,8 @@ An example makes this clear. Here's the code for these beat-specific feeds::
return "Chicagocrime.org: Crimes for beat %s" % obj.beat
def link(self, obj):
if not obj:
raise FeedDoesNotExist
return obj.get_absolute_url()
def description(self, obj):
@ -246,11 +250,18 @@ request to the URL ``/rss/beats/0613/``:
each of ``title``, ``link`` and ``description``, Django follows this
algorithm:
* First, it tries to call a method, passing the ``obj`` argument, where
``obj`` is the object returned by ``get_object()``.
* First, it tries to call a method, passing the ``obj`` argument,
where ``obj`` is the object returned by ``get_object()``.
* Failing that, it tries to call a method with no arguments.
* Failing that, it uses the class attribute.
Inside the ``link()`` method, we handle the possibility that ``obj``
might be ``None``, which can occur when the URL isn't fully specified. In
some cases, you might want to do something else in this case, which would
mean you'd need to check for ``obj`` existing in other methods as well
(the ``link()`` method is called very early in the feed generation
process, so is a good place to bail out early).
* Finally, note that ``items()`` in this example also takes the ``obj``
argument. The algorithm for ``items`` is the same as described in the
previous step -- first, it tries ``items(obj)``, then ``items()``, then

View File

@ -1183,7 +1183,7 @@ on the object being edited -- so they're a perfect case for using a small
template that is filled with details from the current object. (In the admin's
case, this is the ``submit_row`` tag.)
These sorts of tags are called `inclusion tags`.
These sorts of tags are called "inclusion tags".
Writing inclusion tags is probably best demonstrated by example. Let's write a
tag that outputs a list of choices for a given ``Poll`` object, such as was

View File

@ -47,7 +47,7 @@ will create a ``mysite`` directory in your current directory.
denied" when you try to run ``django-admin.py startproject``. This
is because, on Unix-based systems like OS X, a file must be marked
as "executable" before it can be run as a program. To do this, open
Terminal.app and navigate (using the `cd` command) to the directory
Terminal.app and navigate (using the ``cd`` command) to the directory
where ``django-admin.py`` is installed, then run the command
``chmod +x django-admin.py``.

View File

@ -237,7 +237,7 @@ include
-------
A function that takes a full Python import path to another URLconf that should
be "included" in this place. See _`Including other URLconfs` below.
be "included" in this place. See `Including other URLconfs`_ below.
Notes on capturing text in URLs
===============================

View File

@ -103,4 +103,14 @@ TypeError: Invalid lookup type: 'lt'
>>> obj = list(serializers.deserialize("json", stream))[0]
>>> obj.object == m
True
# Test retrieving custom field data
>>> m.delete()
>>> m1 = MyModel(name="1", data=Small(1, 2))
>>> m1.save()
>>> m2 = MyModel(name="2", data=Small(2, 3))
>>> m2.save()
>>> for m in MyModel.objects.all(): print unicode(m.data)
12
23
"""}

View File

@ -30,6 +30,23 @@ ARTICLE_STATUS = (
(3, 'Live'),
)
STEERING_TYPE = (
('left', 'Left steering wheel'),
('right', 'Right steering wheel'),
)
FUEL_TYPE = (
('gas', 'Gasoline'),
('diesel', 'Diesel'),
('other', 'Other'),
)
TRANSMISSION_TYPE = (
('at', 'Automatic'),
('mt', 'Manual'),
('cvt', 'CVT'),
)
class Category(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(max_length=20)
@ -70,6 +87,12 @@ class PhoneNumber(models.Model):
def __unicode__(self):
return self.phone
class Car(models.Model):
name = models.CharField(max_length=50)
steering = models.CharField(max_length=5, choices=STEERING_TYPE, default='left')
fuel = models.CharField(max_length=10, choices=FUEL_TYPE)
transmission = models.CharField(max_length=3, choices=TRANSMISSION_TYPE, blank=True, help_text='Leave empty if not applicable.')
__test__ = {'API_TESTS': """
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
>>> import datetime
@ -592,4 +615,54 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
True
>>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'}
# form_for_* blank choices ####################################################
Show the form for a new Car. Note that steering field doesn't include the blank choice,
because the field is obligatory and has an explicit default.
>>> CarForm = form_for_model(Car)
>>> f = CarForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left" selected="selected">Left steering wheel</option>
<option value="right">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="" selected="selected">---------</option>
<option value="gas">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="" selected="selected">---------</option>
<option value="at">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
Create a Car, and display the form for modifying it. Note that now the fuel
selector doesn't include the blank choice as well, since the field is
obligatory and can not be changed to be blank.
>>> honda = Car(name='Honda Accord Wagon', steering='right', fuel='gas', transmission='at')
>>> honda.save()
>>> HondaForm = form_for_instance(honda)
>>> f = HondaForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Honda Accord Wagon" maxlength="50" /></td></tr>
<tr><th>Steering:</th><td><select name="steering">
<option value="left">Left steering wheel</option>
<option value="right" selected="selected">Right steering wheel</option>
</select></td></tr>
<tr><th>Fuel:</th><td><select name="fuel">
<option value="gas" selected="selected">Gasoline</option>
<option value="diesel">Diesel</option>
<option value="other">Other</option>
</select></td></tr>
<tr><th>Transmission:</th><td><select name="transmission">
<option value="">---------</option>
<option value="at" selected="selected">Automatic</option>
<option value="mt">Manual</option>
<option value="cvt">CVT</option>
</select><br />Leave empty if not applicable.</td></tr>
"""}

View File

@ -66,6 +66,9 @@ u'1979 189 CET'
>>> format(my_birthday, r'jS o\f F')
u'8th of July'
>>> format(the_future, r'Y')
u'2100'
"""
from django.utils import dateformat, translation
@ -84,3 +87,4 @@ except AttributeError:
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
summertime = datetime.datetime(2005, 10, 30, 1, 00)
wintertime = datetime.datetime(2005, 10, 30, 4, 00)
the_future = datetime.datetime(2100, 10, 25, 0, 00)

View File

@ -37,6 +37,8 @@ u''
u'13.1031'
>>> floatformat(u'foo', u'bar')
u''
>>> floatformat(None)
u''
>>> addslashes(u'"double quotes" and \'single quotes\'')
u'\\"double quotes\\" and \\\'single quotes\\\''

View File

@ -323,6 +323,10 @@ Decimal("3.14")
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean(u'łąść')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean('1.0 ')
Decimal("1.0")
>>> f.clean(' 1.0')
@ -914,6 +918,11 @@ False
>>> f.clean('Django rocks')
True
>>> f.clean('True')
True
>>> f.clean('False')
False
>>> f = BooleanField(required=False)
>>> f.clean('')
False
@ -930,6 +939,11 @@ False
>>> f.clean('Django rocks')
True
A form's BooleanField with a hidden widget will output the string 'False', so
that should clean to the boolean value False:
>>> f.clean('False')
False
# ChoiceField #################################################################
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])

View File

@ -147,6 +147,10 @@ u'BC'
u'NS'
>>> f.clean(' manitoba ')
u'MB'
>>> f.clean(' new brunswick ')
u'NB'
>>> f.clean('NB')
u'NB'
>>> f.clean('T2S 2H7')
Traceback (most recent call last):
...

View File

@ -129,6 +129,13 @@ u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u
>>> w.render('email', '', attrs={'class': 'special'})
u'<input type="hidden" class="special" name="email" />'
Boolean values are rendered to their string forms ("True" and "False").
>>> w = HiddenInput()
>>> w.render('get_spam', False)
u'<input type="hidden" name="get_spam" value="False" />'
>>> w.render('get_spam', True)
u'<input type="hidden" name="get_spam" value="True" />'
# MultipleHiddenInput Widget ##################################################
>>> w = MultipleHiddenInput()

View File

@ -12,6 +12,15 @@ from datetime import datetime, timedelta
from django.utils.tzinfo import LocalTimezone
from django.utils.safestring import mark_safe
# These two classes are used to test auto-escaping of __unicode__ output.
class UnsafeClass:
def __unicode__(self):
return u'you & me'
class SafeClass:
def __unicode__(self):
return mark_safe(u'you &gt; me')
# RESULT SYNTAX --
# 'template_name': ('template contents', 'context dict',
# 'expected string output' or Exception class)
@ -227,4 +236,11 @@ def get_filter_tests():
'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a &lt; b"),
'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
# Filters decorated with stringfilter still respect is_safe.
'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You &amp; me'),
'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You &gt; me'),
'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You &gt; me'),
}

View File

@ -899,7 +899,12 @@ class Templates(unittest.TestCase):
# Literal string arguments to filters, if used in the result, are
# safe.
'basic-syntax08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote" hah'),
'autoescape-tag08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote" hah'),
# Objects which return safe strings as their __unicode__ method
# won't get double-escaped.
'autoescape-tag09': (r'{{ unsafe }}', {'unsafe': filters.UnsafeClass()}, 'you &amp; me'),
'autoescape-tag10': (r'{{ safe }}', {'safe': filters.SafeClass()}, 'you &gt; me'),
# The "safe" and "escape" filters cannot work due to internal
# implementation details (fortunately, the (no)autoescape block

View File

@ -0,0 +1,51 @@
"""
>>> from django.utils.datastructures import SortedDict
>>> d = SortedDict()
>>> d[7] = 'seven'
>>> d[1] = 'one'
>>> d[9] = 'nine'
>>> d.keys()
[7, 1, 9]
>>> d.values()
['seven', 'one', 'nine']
>>> d.items()
[(7, 'seven'), (1, 'one'), (9, 'nine')]
# Overwriting an item keeps it's place.
>>> d[1] = 'ONE'
>>> d.values()
['seven', 'ONE', 'nine']
# New items go to the end.
>>> d[0] = 'nil'
>>> d.keys()
[7, 1, 9, 0]
# Deleting an item, then inserting the same key again will place it at the end.
>>> del d[7]
>>> d.keys()
[1, 9, 0]
>>> d[7] = 'lucky number 7'
>>> d.keys()
[1, 9, 0, 7]
# Changing the keys won't do anything, it's only a copy of the keys dict.
>>> k = d.keys()
>>> k.remove(9)
>>> d.keys()
[1, 9, 0, 7]
# Initialising a SortedDict with two keys will just take the first one. A real
# dict will actually take the second value so we will too, but we'll keep the
# ordering from the first key found.
>>> tuples = ((2, 'two'), (1, 'one'), (2, 'second-two'))
>>> d = SortedDict(tuples)
>>> d.keys()
[2, 1]
>>> real_dict = dict(tuples)
>>> real_dict.values()
['one', 'second-two']
>>> d.values()
['second-two', 'one']
"""

View File

@ -6,7 +6,14 @@ from unittest import TestCase
from django.utils import html, checksums
from timesince import timesince_tests
import timesince
import datastructures
# Extra tests
__test__ = {
'timesince': timesince,
'datastructures': datastructures,
}
class TestUtilsHtml(TestCase):
@ -142,10 +149,6 @@ class TestUtilsChecksums(TestCase):
for value, output in items:
self.check_output(f, value, output)
__test__ = {
'timesince_tests': timesince_tests,
}
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@ -1,4 +1,4 @@
timesince_tests = """
"""
>>> from datetime import datetime, timedelta
>>> from django.utils.timesince import timesince

View File

@ -13,3 +13,11 @@ class StaticTests(TestCase):
response = self.client.get('/views/site_media/%s' % filename)
file = open(path.join(media_dir, filename))
self.assertEquals(file.read(), response.content)
def test_copes_with_empty_path_component(self):
file_name = 'file.txt'
response = self.client.get('/views/site_media//%s' % file_name)
file = open(path.join(media_dir, file_name))
self.assertEquals(file.read(), response.content)