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:
parent
b43a018032
commit
dfe05d94b8
4
AUTHORS
4
AUTHORS
@ -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
@ -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 ""
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
13
django/contrib/comments/tests.py
Normal file
13
django/contrib/comments/tests.py
Normal 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: â...
|
||||
"""
|
||||
|
1
django/contrib/formtools/models.py
Normal file
1
django/contrib/formtools/models.py
Normal file
@ -0,0 +1 @@
|
||||
""" models.py (even empty) currently required by the runtests.py to enable unit tests """
|
12
django/contrib/formtools/test_urls.py
Normal file
12
django/contrib/formtools/test_urls.py
Normal 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)),
|
||||
)
|
93
django/contrib/formtools/tests.py
Normal file
93
django/contrib/formtools/tests.py
Normal 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()
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()``
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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``.
|
||||
|
||||
|
@ -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
|
||||
===============================
|
||||
|
@ -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
|
||||
"""}
|
||||
|
@ -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>
|
||||
"""}
|
||||
|
@ -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)
|
||||
|
@ -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\\\''
|
||||
|
@ -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')])
|
||||
|
@ -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):
|
||||
...
|
||||
|
@ -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()
|
||||
|
@ -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 > 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 < b"),
|
||||
'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a < b"),
|
||||
|
||||
# Filters decorated with stringfilter still respect is_safe.
|
||||
'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You & me'),
|
||||
'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
|
||||
'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You > me'),
|
||||
'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You > me'),
|
||||
}
|
||||
|
||||
|
@ -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 & me'),
|
||||
'autoescape-tag10': (r'{{ safe }}', {'safe': filters.SafeClass()}, 'you > me'),
|
||||
|
||||
# The "safe" and "escape" filters cannot work due to internal
|
||||
# implementation details (fortunately, the (no)autoescape block
|
||||
|
51
tests/regressiontests/utils/datastructures.py
Normal file
51
tests/regressiontests/utils/datastructures.py
Normal 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']
|
||||
"""
|
@ -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()
|
||||
|
@ -1,4 +1,4 @@
|
||||
timesince_tests = """
|
||||
"""
|
||||
>>> from datetime import datetime, timedelta
|
||||
>>> from django.utils.timesince import timesince
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user