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>
|
Jonathan Buchanan <jonathan.buchanan@gmail.com>
|
||||||
Trevor Caira <trevor@caira.com>
|
Trevor Caira <trevor@caira.com>
|
||||||
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
|
Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
|
||||||
|
Graham Carlyle <graham.carlyle@maplecroft.net>
|
||||||
Antonio Cavedoni <http://cavedoni.com/>
|
Antonio Cavedoni <http://cavedoni.com/>
|
||||||
C8E
|
C8E
|
||||||
cedric@terramater.net
|
cedric@terramater.net
|
||||||
@ -100,6 +101,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Alex Dedul
|
Alex Dedul
|
||||||
deric@monowerks.com
|
deric@monowerks.com
|
||||||
Max Derkachev <mderk@yandex.ru>
|
Max Derkachev <mderk@yandex.ru>
|
||||||
|
Rajesh Dhawan <rajesh.dhawan@gmail.com>
|
||||||
Sander Dijkhuis <sander.dijkhuis@gmail.com>
|
Sander Dijkhuis <sander.dijkhuis@gmail.com>
|
||||||
Jordan Dimov <s3x3y1@gmail.com>
|
Jordan Dimov <s3x3y1@gmail.com>
|
||||||
dne@mayonnaise.net
|
dne@mayonnaise.net
|
||||||
@ -187,6 +189,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
krzysiek.pawlik@silvermedia.pl
|
krzysiek.pawlik@silvermedia.pl
|
||||||
Joseph Kocherhans
|
Joseph Kocherhans
|
||||||
konrad@gwu.edu
|
konrad@gwu.edu
|
||||||
|
knox <christobzr@gmail.com>
|
||||||
kurtiss@meetro.com
|
kurtiss@meetro.com
|
||||||
lakin.wecker@gmail.com
|
lakin.wecker@gmail.com
|
||||||
Nick Lane <nick.lane.au@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>
|
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||||
David Schein
|
David Schein
|
||||||
scott@staplefish.com
|
scott@staplefish.com
|
||||||
|
Ilya Semenov <semenov@inetss.com>
|
||||||
serbaut@gmail.com
|
serbaut@gmail.com
|
||||||
John Shaffer <jshaffer2112@gmail.com>
|
John Shaffer <jshaffer2112@gmail.com>
|
||||||
Pete Shinners <pete@shinners.org>
|
Pete Shinners <pete@shinners.org>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,12 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
@ -45,64 +45,73 @@ msgstr ""
|
|||||||
msgid "Clear all"
|
msgid "Clear all"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:26
|
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
|
#: contrib/admin/media/js/dateparse.js:32
|
||||||
msgid ""
|
msgid ""
|
||||||
"January February March April May June July August September October November "
|
"January February March April May June July August September October November "
|
||||||
"December"
|
"December"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:27
|
|
||||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: contrib/admin/media/js/calendar.js:25
|
#: contrib/admin/media/js/calendar.js:25
|
||||||
msgid "S M T W T F S"
|
msgid "S M T W T F S"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
#: contrib/admin/media/js/dateparse.js:33
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
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"
|
msgid "Now"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||||
msgid "Clock"
|
msgid "Clock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||||
msgid "Choose a time"
|
msgid "Choose a time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||||
msgid "Midnight"
|
msgid "Midnight"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||||
msgid "6 a.m."
|
msgid "6 a.m."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||||
msgid "Noon"
|
msgid "Noon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||||
msgid "Today"
|
msgid "Today"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||||
msgid "Calendar"
|
msgid "Calendar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||||
msgid "Tomorrow"
|
msgid "Tomorrow"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
{% for library in filter_libraries %}
|
{% for library in filter_libraries %}
|
||||||
<div class="module">
|
<div class="module">
|
||||||
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
|
<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" %}
|
{% for filter in library.list|dictsort:"name" %}
|
||||||
<h3 id="{{ filter.name }}">{{ filter.name }}</h3>
|
<h3 id="{{ filter.name }}">{{ filter.name }}</h3>
|
||||||
<p>{{ filter.title }}</p>
|
<p>{{ filter.title }}</p>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
{% for library in tag_libraries %}
|
{% for library in tag_libraries %}
|
||||||
<div class="module">
|
<div class="module">
|
||||||
<h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
|
<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" %}
|
{% for tag in library.list|dictsort:"name" %}
|
||||||
<h3 id="{{ tag.name }}">{{ tag.name }}</h3>
|
<h3 id="{{ tag.name }}">{{ tag.name }}</h3>
|
||||||
<h4>{{ tag.title }}</h4>
|
<h4>{{ tag.title }}</h4>
|
||||||
|
@ -29,10 +29,10 @@
|
|||||||
|
|
||||||
{% for view in site_views.list|dictsort:"url" %}
|
{% for view in site_views.list|dictsort:"url" %}
|
||||||
{% ifchanged %}
|
{% 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 class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
|
||||||
<p>{{ view.title }}</p>
|
<p>{{ view.title }}</p>
|
||||||
<hr>
|
<hr />
|
||||||
{% endifchanged %}
|
{% endifchanged %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,7 +102,7 @@ class Comment(models.Model):
|
|||||||
date_hierarchy = 'submit_date'
|
date_hierarchy = 'submit_date'
|
||||||
search_fields = ('comment', 'user__username')
|
search_fields = ('comment', 'user__username')
|
||||||
|
|
||||||
def __repr__(self):
|
def __unicode__(self):
|
||||||
return "%s: %s..." % (self.user.username, self.comment[:100])
|
return "%s: %s..." % (self.user.username, self.comment[:100])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
@ -190,7 +190,7 @@ class FreeComment(models.Model):
|
|||||||
date_hierarchy = 'submit_date'
|
date_hierarchy = 'submit_date'
|
||||||
search_fields = ('comment', 'person_name')
|
search_fields = ('comment', 'person_name')
|
||||||
|
|
||||||
def __repr__(self):
|
def __unicode__(self):
|
||||||
return "%s: %s..." % (self.person_name, self.comment[:100])
|
return "%s: %s..." % (self.person_name, self.comment[:100])
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
@ -244,7 +244,7 @@ class KarmaScore(models.Model):
|
|||||||
verbose_name_plural = _('karma scores')
|
verbose_name_plural = _('karma scores')
|
||||||
unique_together = (('user', 'comment'),)
|
unique_together = (('user', 'comment'),)
|
||||||
|
|
||||||
def __repr__(self):
|
def __unicode__(self):
|
||||||
return _("%(score)d rating by %(user)s") % {'score': self.score, 'user': self.user}
|
return _("%(score)d rating by %(user)s") % {'score': self.score, 'user': self.user}
|
||||||
|
|
||||||
class UserFlagManager(models.Manager):
|
class UserFlagManager(models.Manager):
|
||||||
@ -275,7 +275,7 @@ class UserFlag(models.Model):
|
|||||||
verbose_name_plural = _('user flags')
|
verbose_name_plural = _('user flags')
|
||||||
unique_together = (('user', 'comment'),)
|
unique_together = (('user', 'comment'),)
|
||||||
|
|
||||||
def __repr__(self):
|
def __unicode__(self):
|
||||||
return _("Flag by %r") % self.user
|
return _("Flag by %r") % self.user
|
||||||
|
|
||||||
class ModeratorDeletion(models.Model):
|
class ModeratorDeletion(models.Model):
|
||||||
@ -287,5 +287,5 @@ class ModeratorDeletion(models.Model):
|
|||||||
verbose_name_plural = _('moderator deletions')
|
verbose_name_plural = _('moderator deletions')
|
||||||
unique_together = (('user', 'comment'),)
|
unique_together = (('user', 'comment'),)
|
||||||
|
|
||||||
def __repr__(self):
|
def __unicode__(self):
|
||||||
return _("Moderator deletion by %r") % self.user
|
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',
|
'british columbia': 'BC',
|
||||||
'mb': 'MB',
|
'mb': 'MB',
|
||||||
'manitoba': 'MB',
|
'manitoba': 'MB',
|
||||||
|
'nb': 'NB',
|
||||||
|
'new brunswick': 'NB',
|
||||||
'nf': 'NF',
|
'nf': 'NF',
|
||||||
'newfoundland': 'NF',
|
'newfoundland': 'NF',
|
||||||
'newfoundland and labrador': 'NF',
|
'newfoundland and labrador': 'NF',
|
||||||
|
@ -471,5 +471,5 @@ def method_get_order(ordered_obj, self):
|
|||||||
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
|
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
def get_absolute_url(opts, 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)
|
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."
|
"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}
|
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
|
||||||
if self.choices:
|
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():
|
if self.has_default():
|
||||||
defaults['initial'] = self.get_default()
|
defaults['initial'] = self.get_default()
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
|
@ -28,10 +28,10 @@ class Creator(object):
|
|||||||
def __get__(self, obj, type=None):
|
def __get__(self, obj, type=None):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
raise AttributeError('Can only be accessed via an instance.')
|
raise AttributeError('Can only be accessed via an instance.')
|
||||||
return self.value
|
return obj.__dict__[self.field.name]
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
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):
|
def make_contrib(func=None):
|
||||||
"""
|
"""
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
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):
|
class CacheMiddleware(object):
|
||||||
"""
|
"""
|
||||||
Cache middleware. If this is enabled, each Django-powered page will be
|
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.
|
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
|
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
|
(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
|
simple and effective way of avoiding the caching of the Django admin (and
|
||||||
@ -78,7 +82,16 @@ class CacheMiddleware(object):
|
|||||||
return response
|
return response
|
||||||
if not response.status_code == 200:
|
if not response.status_code == 200:
|
||||||
return response
|
return response
|
||||||
patch_response_headers(response, self.cache_timeout)
|
# Try to get the timeout from the "max-age" section of the "Cache-
|
||||||
cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix)
|
# Control" header before reverting to using the default cache_timeout
|
||||||
cache.set(cache_key, response, self.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
|
return response
|
||||||
|
@ -17,7 +17,7 @@ except NameError:
|
|||||||
from sets import Set as set
|
from sets import Set as set
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
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 util import ErrorList, ValidationError
|
||||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
|
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)
|
super(DecimalField, self).clean(value)
|
||||||
if not self.required and value in EMPTY_VALUES:
|
if not self.required and value in EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = str(value).strip()
|
value = smart_str(value).strip()
|
||||||
try:
|
try:
|
||||||
value = Decimal(value)
|
value = Decimal(value)
|
||||||
except DecimalException:
|
except DecimalException:
|
||||||
@ -536,11 +536,12 @@ class BooleanField(Field):
|
|||||||
widget = CheckboxInput
|
widget = CheckboxInput
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
"Returns a Python boolean object."
|
"""Returns a Python boolean object."""
|
||||||
super(BooleanField, self).clean(value)
|
super(BooleanField, self).clean(value)
|
||||||
# Explicitly check for the string '0', which is what as hidden field
|
# Explicitly check for the string 'False', which is what a hidden field
|
||||||
# will submit for False.
|
# will submit for False (since bool("True") == True we don't need to
|
||||||
if value == '0':
|
# handle that explicitly).
|
||||||
|
if value == 'False':
|
||||||
return False
|
return False
|
||||||
return bool(value)
|
return bool(value)
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ def stringfilter(func):
|
|||||||
if args:
|
if args:
|
||||||
args = list(args)
|
args = list(args)
|
||||||
args[0] = force_unicode(args[0])
|
args[0] = force_unicode(args[0])
|
||||||
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
|
if isinstance(args[0], SafeData) and getattr(func, 'is_safe', False):
|
||||||
return mark_safe(func(*args, **kwargs))
|
return mark_safe(func(*args, **kwargs))
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
# Include a reference to the real function (used to check original
|
# Include a reference to the real function (used to check original
|
||||||
@ -91,7 +91,7 @@ def floatformat(text, arg=-1):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
f = float(text)
|
f = float(text)
|
||||||
except ValueError:
|
except (ValueError, TypeError):
|
||||||
return u''
|
return u''
|
||||||
try:
|
try:
|
||||||
d = int(arg)
|
d = int(arg)
|
||||||
|
@ -74,6 +74,21 @@ def patch_cache_control(response, **kwargs):
|
|||||||
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
||||||
response['Cache-Control'] = cc
|
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):
|
def patch_response_headers(response, cache_timeout=None):
|
||||||
"""
|
"""
|
||||||
Adds some useful headers to the given HttpResponse object:
|
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
|
# for the request.path
|
||||||
cache.set(cache_key, [], cache_timeout)
|
cache.set(cache_key, [], cache_timeout)
|
||||||
return _generate_cache_key(request, [], key_prefix)
|
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):
|
if isinstance(data, dict):
|
||||||
self.keyOrder = data.keys()
|
self.keyOrder = data.keys()
|
||||||
else:
|
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):
|
def __deepcopy__(self, memo):
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
@ -54,6 +54,12 @@ class LocalTimezone(tzinfo):
|
|||||||
|
|
||||||
def _isdst(self, dt):
|
def _isdst(self, dt):
|
||||||
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
|
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)
|
tt = time.localtime(stamp)
|
||||||
return tt.tm_isdst > 0
|
return tt.tm_isdst > 0
|
||||||
|
@ -120,8 +120,12 @@ def javascript_catalog(request, domain='djangojs', packages=None):
|
|||||||
p = __import__(package, {}, {}, [''])
|
p = __import__(package, {}, {}, [''])
|
||||||
path = os.path.join(os.path.dirname(p.__file__), 'locale')
|
path = os.path.join(os.path.dirname(p.__file__), 'locale')
|
||||||
paths.append(path)
|
paths.append(path)
|
||||||
catalog = gettext_module.translation(domain, path, ['en'])
|
try:
|
||||||
t.update(catalog._catalog)
|
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
|
# next load the settings.LANGUAGE_CODE translations if it isn't english
|
||||||
if default_locale != 'en':
|
if default_locale != 'en':
|
||||||
for path in paths:
|
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.
|
# Clean up given path to only allow serving files below document_root.
|
||||||
path = posixpath.normpath(urllib.unquote(path))
|
path = posixpath.normpath(urllib.unquote(path))
|
||||||
|
path = path.lstrip('/')
|
||||||
newpath = ''
|
newpath = ''
|
||||||
for part in path.split('/'):
|
for part in path.split('/'):
|
||||||
if not part:
|
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.
|
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')``
|
* ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')``
|
||||||
Returns a random password with the given length and given string of
|
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/
|
.. _`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
|
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.)
|
precedence, and the header values will be merged correctly.)
|
||||||
|
|
||||||
If you want to use headers to disable caching altogether,
|
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::
|
headers to ensure the response won't be cached by browsers or other caches. Example::
|
||||||
|
|
||||||
from django.views.decorators.cache import never_cache
|
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
|
Use ``--verbosity`` to specify the amount of notification and debug information
|
||||||
that ``django-admin.py`` should print to the console.
|
that ``django-admin.py`` should print to the console.
|
||||||
|
|
||||||
* ``0`` means no input.
|
* ``0`` means no output.
|
||||||
* ``1`` means normal input (default).
|
* ``1`` means normal output (default).
|
||||||
* ``2`` means verbose input.
|
* ``2`` means verbose output.
|
||||||
|
|
||||||
Example usage::
|
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
|
that it doesn't matter whether the options come before or after the fixture
|
||||||
arguments.)
|
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
|
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.)
|
"Where are my ``site-packages`` stored?" section above.)
|
||||||
|
|
||||||
Alternatively, you can define your ``PYTHONPATH`` environment variable
|
Alternatively, you can define your ``PYTHONPATH`` environment variable
|
||||||
so that it includes the ``django`` subdirectory of ``django-trunk``.
|
so that it includes the ``django-trunk`` directory. This is perhaps the
|
||||||
This is perhaps the most convenient solution on Windows systems, which
|
most convenient solution on Windows systems, which don't support symbolic
|
||||||
don't support symbolic links. (Environment variables can be defined on
|
links. (Environment variables can be defined on Windows systems `from the
|
||||||
Windows systems `from the Control Panel`_.)
|
Control Panel`_.)
|
||||||
|
|
||||||
.. admonition:: What about Apache and mod_python?
|
.. 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/
|
.. _How to use Django with mod_python: ../modpython/
|
||||||
|
|
||||||
4. Copy the file ``django-trunk/django/bin/django-admin.py`` to somewhere on
|
4. On Unix-like systems, create a symbolic link to the file
|
||||||
your system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
|
``django-trunk/django/bin/django-admin.py`` in a directory on your system
|
||||||
(Windows). This step simply lets you type ``django-admin.py`` from within
|
path, such as ``/usr/local/bin``. For example::
|
||||||
any directory, rather than having to qualify the command with the full path
|
|
||||||
to the file.
|
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
|
You *don't* have to run ``python setup.py install``, because you've already
|
||||||
carried out the equivalent actions in steps 3 and 4.
|
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:
|
Some technical notes:
|
||||||
|
|
||||||
* The name of the table, ``myapp_person``, is automatically derived from
|
* 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
|
* An ``id`` field is added automatically, but this behavior can be
|
||||||
overriden. See `Automatic primary key fields`_ below.
|
overriden. See `Automatic primary key fields`_ below.
|
||||||
* The ``CREATE TABLE`` SQL in this example is formatted using PostgreSQL
|
* 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"
|
Adding extra ``Manager`` methods is the preferred way to add "table-level"
|
||||||
functionality to your models. (For "row-level" functionality -- i.e., functions
|
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.)
|
custom ``Manager`` methods.)
|
||||||
|
|
||||||
A custom ``Manager`` method can return anything you want. It doesn't have to
|
A custom ``Manager`` method can return anything you want. It doesn't have to
|
||||||
|
@ -753,6 +753,30 @@ For example::
|
|||||||
</ul>
|
</ul>
|
||||||
</form>
|
</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
|
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``
|
* 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
|
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
|
Finally, note that you can override the form field used for a given model
|
||||||
field. See "Overriding the default field types" below.
|
field. See "Overriding the default field types" below.
|
||||||
@ -2095,10 +2123,14 @@ instance instead of a model class::
|
|||||||
# Instantiate the form.
|
# Instantiate the form.
|
||||||
>>> f = AuthorForm()
|
>>> f = AuthorForm()
|
||||||
|
|
||||||
When a form created by ``form_for_instance()`` is created, the initial
|
When a form created by ``form_for_instance()`` is created, the initial data
|
||||||
data values for the form fields are drawn from the instance. However,
|
values for the form fields are drawn from the instance. However, this data is
|
||||||
this data is not bound to the form. You will need to bind data to the
|
not bound to the form. You will need to bind data to the form before the form
|
||||||
form before the form can be saved.
|
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()``,
|
When you call ``save()`` on a form created by ``form_for_instance()``,
|
||||||
the database instance will be updated. As in ``form_for_model()``, ``save()``
|
the database instance will be updated. As in ``form_for_model()``, ``save()``
|
||||||
|
@ -44,7 +44,7 @@ to this::
|
|||||||
DATABASE_ENGINE = "mysql_old"
|
DATABASE_ENGINE = "mysql_old"
|
||||||
|
|
||||||
However, we strongly encourage MySQL users to upgrade to a more recent
|
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;
|
provided only to ease this transition, and is considered deprecated;
|
||||||
aside from any necessary security fixes, it will not be actively
|
aside from any necessary security fixes, it will not be actively
|
||||||
maintained, and it will be removed in a future release of Django.
|
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::
|
An example makes this clear. Here's the code for these beat-specific feeds::
|
||||||
|
|
||||||
|
from django.contrib.syndication import FeedDoesNotExist
|
||||||
|
|
||||||
class BeatFeed(Feed):
|
class BeatFeed(Feed):
|
||||||
def get_object(self, bits):
|
def get_object(self, bits):
|
||||||
# In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter,
|
# 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
|
return "Chicagocrime.org: Crimes for beat %s" % obj.beat
|
||||||
|
|
||||||
def link(self, obj):
|
def link(self, obj):
|
||||||
|
if not obj:
|
||||||
|
raise FeedDoesNotExist
|
||||||
return obj.get_absolute_url()
|
return obj.get_absolute_url()
|
||||||
|
|
||||||
def description(self, obj):
|
def description(self, obj):
|
||||||
@ -246,11 +250,18 @@ request to the URL ``/rss/beats/0613/``:
|
|||||||
each of ``title``, ``link`` and ``description``, Django follows this
|
each of ``title``, ``link`` and ``description``, Django follows this
|
||||||
algorithm:
|
algorithm:
|
||||||
|
|
||||||
* First, it tries to call a method, passing the ``obj`` argument, where
|
* First, it tries to call a method, passing the ``obj`` argument,
|
||||||
``obj`` is the object returned by ``get_object()``.
|
where ``obj`` is the object returned by ``get_object()``.
|
||||||
* Failing that, it tries to call a method with no arguments.
|
* Failing that, it tries to call a method with no arguments.
|
||||||
* Failing that, it uses the class attribute.
|
* 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``
|
* Finally, note that ``items()`` in this example also takes the ``obj``
|
||||||
argument. The algorithm for ``items`` is the same as described in the
|
argument. The algorithm for ``items`` is the same as described in the
|
||||||
previous step -- first, it tries ``items(obj)``, then ``items()``, then
|
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
|
template that is filled with details from the current object. (In the admin's
|
||||||
case, this is the ``submit_row`` tag.)
|
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
|
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
|
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
|
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
|
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
|
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
|
where ``django-admin.py`` is installed, then run the command
|
||||||
``chmod +x django-admin.py``.
|
``chmod +x django-admin.py``.
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ include
|
|||||||
-------
|
-------
|
||||||
|
|
||||||
A function that takes a full Python import path to another URLconf that should
|
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
|
Notes on capturing text in URLs
|
||||||
===============================
|
===============================
|
||||||
|
@ -103,4 +103,14 @@ TypeError: Invalid lookup type: 'lt'
|
|||||||
>>> obj = list(serializers.deserialize("json", stream))[0]
|
>>> obj = list(serializers.deserialize("json", stream))[0]
|
||||||
>>> obj.object == m
|
>>> obj.object == m
|
||||||
True
|
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'),
|
(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):
|
class Category(models.Model):
|
||||||
name = models.CharField(max_length=20)
|
name = models.CharField(max_length=20)
|
||||||
slug = models.SlugField(max_length=20)
|
slug = models.SlugField(max_length=20)
|
||||||
@ -70,6 +87,12 @@ class PhoneNumber(models.Model):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.phone
|
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': """
|
__test__ = {'API_TESTS': """
|
||||||
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
|
>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
|
||||||
>>> import datetime
|
>>> import datetime
|
||||||
@ -592,4 +615,54 @@ ValidationError: [u'Select a valid choice. 4 is not one of the available choices
|
|||||||
True
|
True
|
||||||
>>> f.cleaned_data
|
>>> f.cleaned_data
|
||||||
{'phone': u'312-555-1212', 'description': u'Assistance'}
|
{'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')
|
>>> format(my_birthday, r'jS o\f F')
|
||||||
u'8th of July'
|
u'8th of July'
|
||||||
|
|
||||||
|
>>> format(the_future, r'Y')
|
||||||
|
u'2100'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.utils import dateformat, translation
|
from django.utils import dateformat, translation
|
||||||
@ -84,3 +87,4 @@ except AttributeError:
|
|||||||
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
my_birthday = datetime.datetime(1979, 7, 8, 22, 00)
|
||||||
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
summertime = datetime.datetime(2005, 10, 30, 1, 00)
|
||||||
wintertime = datetime.datetime(2005, 10, 30, 4, 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'
|
u'13.1031'
|
||||||
>>> floatformat(u'foo', u'bar')
|
>>> floatformat(u'foo', u'bar')
|
||||||
u''
|
u''
|
||||||
|
>>> floatformat(None)
|
||||||
|
u''
|
||||||
|
|
||||||
>>> addslashes(u'"double quotes" and \'single quotes\'')
|
>>> addslashes(u'"double quotes" and \'single quotes\'')
|
||||||
u'\\"double quotes\\" and \\\'single quotes\\\''
|
u'\\"double quotes\\" and \\\'single quotes\\\''
|
||||||
|
@ -323,6 +323,10 @@ Decimal("3.14")
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Enter a number.']
|
ValidationError: [u'Enter a number.']
|
||||||
|
>>> f.clean(u'łąść')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a number.']
|
||||||
>>> f.clean('1.0 ')
|
>>> f.clean('1.0 ')
|
||||||
Decimal("1.0")
|
Decimal("1.0")
|
||||||
>>> f.clean(' 1.0')
|
>>> f.clean(' 1.0')
|
||||||
@ -914,6 +918,11 @@ False
|
|||||||
>>> f.clean('Django rocks')
|
>>> f.clean('Django rocks')
|
||||||
True
|
True
|
||||||
|
|
||||||
|
>>> f.clean('True')
|
||||||
|
True
|
||||||
|
>>> f.clean('False')
|
||||||
|
False
|
||||||
|
|
||||||
>>> f = BooleanField(required=False)
|
>>> f = BooleanField(required=False)
|
||||||
>>> f.clean('')
|
>>> f.clean('')
|
||||||
False
|
False
|
||||||
@ -930,6 +939,11 @@ False
|
|||||||
>>> f.clean('Django rocks')
|
>>> f.clean('Django rocks')
|
||||||
True
|
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 #################################################################
|
# ChoiceField #################################################################
|
||||||
|
|
||||||
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
|
>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
|
||||||
|
@ -147,6 +147,10 @@ u'BC'
|
|||||||
u'NS'
|
u'NS'
|
||||||
>>> f.clean(' manitoba ')
|
>>> f.clean(' manitoba ')
|
||||||
u'MB'
|
u'MB'
|
||||||
|
>>> f.clean(' new brunswick ')
|
||||||
|
u'NB'
|
||||||
|
>>> f.clean('NB')
|
||||||
|
u'NB'
|
||||||
>>> f.clean('T2S 2H7')
|
>>> f.clean('T2S 2H7')
|
||||||
Traceback (most recent call last):
|
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'})
|
>>> w.render('email', '', attrs={'class': 'special'})
|
||||||
u'<input type="hidden" class="special" name="email" />'
|
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 ##################################################
|
# MultipleHiddenInput Widget ##################################################
|
||||||
|
|
||||||
>>> w = MultipleHiddenInput()
|
>>> w = MultipleHiddenInput()
|
||||||
|
@ -12,6 +12,15 @@ from datetime import datetime, timedelta
|
|||||||
from django.utils.tzinfo import LocalTimezone
|
from django.utils.tzinfo import LocalTimezone
|
||||||
from django.utils.safestring import mark_safe
|
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 --
|
# RESULT SYNTAX --
|
||||||
# 'template_name': ('template contents', 'context dict',
|
# 'template_name': ('template contents', 'context dict',
|
||||||
# 'expected string output' or Exception class)
|
# '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 < "),
|
'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
|
||||||
'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a < b"),
|
'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a < b"),
|
||||||
'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"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
|
# Literal string arguments to filters, if used in the result, are
|
||||||
# safe.
|
# 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
|
# The "safe" and "escape" filters cannot work due to internal
|
||||||
# implementation details (fortunately, the (no)autoescape block
|
# 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 django.utils import html, checksums
|
||||||
|
|
||||||
from timesince import timesince_tests
|
import timesince
|
||||||
|
import datastructures
|
||||||
|
|
||||||
|
# Extra tests
|
||||||
|
__test__ = {
|
||||||
|
'timesince': timesince,
|
||||||
|
'datastructures': datastructures,
|
||||||
|
}
|
||||||
|
|
||||||
class TestUtilsHtml(TestCase):
|
class TestUtilsHtml(TestCase):
|
||||||
|
|
||||||
@ -142,10 +149,6 @@ class TestUtilsChecksums(TestCase):
|
|||||||
for value, output in items:
|
for value, output in items:
|
||||||
self.check_output(f, value, output)
|
self.check_output(f, value, output)
|
||||||
|
|
||||||
__test__ = {
|
|
||||||
'timesince_tests': timesince_tests,
|
|
||||||
}
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
timesince_tests = """
|
"""
|
||||||
>>> from datetime import datetime, timedelta
|
>>> from datetime import datetime, timedelta
|
||||||
>>> from django.utils.timesince import timesince
|
>>> from django.utils.timesince import timesince
|
||||||
|
|
||||||
|
@ -12,4 +12,12 @@ class StaticTests(TestCase):
|
|||||||
for filename in media_files:
|
for filename in media_files:
|
||||||
response = self.client.get('/views/site_media/%s' % filename)
|
response = self.client.get('/views/site_media/%s' % filename)
|
||||||
file = open(path.join(media_dir, filename))
|
file = open(path.join(media_dir, filename))
|
||||||
self.assertEquals(file.read(), response.content)
|
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