mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
[soc2009/multidb] Merged up to trunk r11858.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11860 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
049dc42bde
commit
2794cceb5f
8
AUTHORS
8
AUTHORS
@ -55,6 +55,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Niran Babalola <niran@niran.org>
|
Niran Babalola <niran@niran.org>
|
||||||
Morten Bagai <m@bagai.com>
|
Morten Bagai <m@bagai.com>
|
||||||
Mikaël Barbero <mikael.barbero nospam at nospam free.fr>
|
Mikaël Barbero <mikael.barbero nospam at nospam free.fr>
|
||||||
|
Randy Barlow <randy@electronsweatshop.com>
|
||||||
Scott Barr <scott@divisionbyzero.com.au>
|
Scott Barr <scott@divisionbyzero.com.au>
|
||||||
Jiri Barton
|
Jiri Barton
|
||||||
Ned Batchelder <http://www.nedbatchelder.com/>
|
Ned Batchelder <http://www.nedbatchelder.com/>
|
||||||
@ -136,7 +137,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Andrew Durdin <adurdin@gmail.com>
|
Andrew Durdin <adurdin@gmail.com>
|
||||||
dusk@woofle.net
|
dusk@woofle.net
|
||||||
Andy Dustman <farcepest@gmail.com>
|
Andy Dustman <farcepest@gmail.com>
|
||||||
J. Clifford Dyer <jcd@unc.edu>
|
J. Clifford Dyer <jcd@sdf.lonestar.org>
|
||||||
Clint Ecker
|
Clint Ecker
|
||||||
Nick Efford <nick@efford.org>
|
Nick Efford <nick@efford.org>
|
||||||
eibaan@gmail.com
|
eibaan@gmail.com
|
||||||
@ -172,6 +173,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Alex Gaynor <alex.gaynor@gmail.com>
|
Alex Gaynor <alex.gaynor@gmail.com>
|
||||||
Andy Gayton <andy-django@thecablelounge.com>
|
Andy Gayton <andy-django@thecablelounge.com>
|
||||||
Idan Gazit
|
Idan Gazit
|
||||||
|
geber@datacollect.com
|
||||||
Baishampayan Ghose
|
Baishampayan Ghose
|
||||||
Dimitris Glezos <dimitris@glezos.com>
|
Dimitris Glezos <dimitris@glezos.com>
|
||||||
glin@seznam.cz
|
glin@seznam.cz
|
||||||
@ -267,6 +269,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Finn Gruwier Larsen <finn@gruwier.dk>
|
Finn Gruwier Larsen <finn@gruwier.dk>
|
||||||
Lau Bech Lauritzen
|
Lau Bech Lauritzen
|
||||||
Rune Rønde Laursen <runerl@skjoldhoej.dk>
|
Rune Rønde Laursen <runerl@skjoldhoej.dk>
|
||||||
|
Mark Lavin <markdlavin@gmail.com>
|
||||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||||
lcordier@point45.com
|
lcordier@point45.com
|
||||||
Jeong-Min Lee <falsetru@gmail.com>
|
Jeong-Min Lee <falsetru@gmail.com>
|
||||||
@ -300,6 +303,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jason McBrayer <http://www.carcosa.net/jason/>
|
Jason McBrayer <http://www.carcosa.net/jason/>
|
||||||
Kevin McConnell <kevin.mcconnell@gmail.com>
|
Kevin McConnell <kevin.mcconnell@gmail.com>
|
||||||
mccutchen@gmail.com
|
mccutchen@gmail.com
|
||||||
|
Paul McLanahan <paul@mclanahan.net>
|
||||||
Tobias McNulty <http://www.caktusgroup.com/blog>
|
Tobias McNulty <http://www.caktusgroup.com/blog>
|
||||||
Christian Metts
|
Christian Metts
|
||||||
michael.mcewan@gmail.com
|
michael.mcewan@gmail.com
|
||||||
@ -382,6 +386,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Massimo Scamarcia <massimo.scamarcia@gmail.com>
|
Massimo Scamarcia <massimo.scamarcia@gmail.com>
|
||||||
David Schein
|
David Schein
|
||||||
Bernd Schlapsi
|
Bernd Schlapsi
|
||||||
|
schwank@gmail.com
|
||||||
scott@staplefish.com
|
scott@staplefish.com
|
||||||
Ilya Semenov <semenov@inetss.com>
|
Ilya Semenov <semenov@inetss.com>
|
||||||
serbaut@gmail.com
|
serbaut@gmail.com
|
||||||
@ -393,6 +398,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||||
Ben Slavin <benjamin.slavin@gmail.com>
|
Ben Slavin <benjamin.slavin@gmail.com>
|
||||||
sloonz <simon.lipp@insa-lyon.fr>
|
sloonz <simon.lipp@insa-lyon.fr>
|
||||||
|
Paul Smith <blinkylights23@gmail.com>
|
||||||
Warren Smith <warren@wandrsmith.net>
|
Warren Smith <warren@wandrsmith.net>
|
||||||
smurf@smurf.noris.de
|
smurf@smurf.noris.de
|
||||||
Vsevolod Solovyov
|
Vsevolod Solovyov
|
||||||
|
2
README
2
README
@ -27,7 +27,7 @@ http://code.djangoproject.com/newticket
|
|||||||
To get more help:
|
To get more help:
|
||||||
|
|
||||||
* Join the #django channel on irc.freenode.net. Lots of helpful people
|
* Join the #django channel on irc.freenode.net. Lots of helpful people
|
||||||
hang out there. Read the archives at http://oebfare.com/logger/django/.
|
hang out there. Read the archives at http://botland.oebfare.com/logger/django/.
|
||||||
|
|
||||||
* Join the django-users mailing list, or read the archives, at
|
* Join the django-users mailing list, or read the archives, at
|
||||||
http://groups.google.com/group/django-users.
|
http://groups.google.com/group/django-users.
|
||||||
|
@ -692,6 +692,9 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
# perform an action on it, so bail.
|
# perform an action on it, so bail.
|
||||||
selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
|
selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
|
||||||
if not selected:
|
if not selected:
|
||||||
|
# Reminder that something needs to be selected or nothing will happen
|
||||||
|
msg = "Items must be selected in order to perform actions on them. No items have been changed."
|
||||||
|
self.message_user(request, _(msg))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
response = func(self, request, queryset.filter(pk__in=selected))
|
response = func(self, request, queryset.filter(pk__in=selected))
|
||||||
@ -703,6 +706,9 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(".")
|
return HttpResponseRedirect(".")
|
||||||
|
else:
|
||||||
|
msg = "No action selected."
|
||||||
|
self.message_user(request, _(msg))
|
||||||
|
|
||||||
@csrf_protect
|
@csrf_protect
|
||||||
@transaction.commit_on_success
|
@transaction.commit_on_success
|
||||||
|
1
django/contrib/admindocs/models.py
Normal file
1
django/contrib/admindocs/models.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Empty models.py to allow for specifying admindocs as a test label.
|
36
django/contrib/admindocs/tests/__init__.py
Normal file
36
django/contrib/admindocs/tests/__init__.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import unittest
|
||||||
|
from django.contrib.admindocs import views
|
||||||
|
import fields
|
||||||
|
|
||||||
|
from django.db.models import fields as builtin_fields
|
||||||
|
|
||||||
|
class TestFieldType(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_field_name(self):
|
||||||
|
self.assertRaises(AttributeError,
|
||||||
|
views.get_readable_field_data_type, "NotAField"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_builtin_fields(self):
|
||||||
|
self.assertEqual(
|
||||||
|
views.get_readable_field_data_type(builtin_fields.BooleanField()),
|
||||||
|
u'Boolean (Either True or False)'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_custom_fields(self):
|
||||||
|
self.assertEqual(
|
||||||
|
views.get_readable_field_data_type(fields.CustomField()),
|
||||||
|
u'A custom field type'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
views.get_readable_field_data_type(fields.DocstringLackingField()),
|
||||||
|
u'Field of type: DocstringLackingField'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_multiline_custom_field_truncation(self):
|
||||||
|
self.assertEqual(
|
||||||
|
views.get_readable_field_data_type(fields.ManyLineDocstringField()),
|
||||||
|
u'Many-line custom field'
|
||||||
|
)
|
13
django/contrib/admindocs/tests/fields.py
Normal file
13
django/contrib/admindocs/tests/fields.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class CustomField(models.Field):
|
||||||
|
"""A custom field type"""
|
||||||
|
|
||||||
|
class ManyLineDocstringField(models.Field):
|
||||||
|
"""Many-line custom field
|
||||||
|
|
||||||
|
This docstring has many lines. Lorum ipsem etc. etc. Four score
|
||||||
|
and seven years ago, and so on and so forth."""
|
||||||
|
|
||||||
|
class DocstringLackingField(models.Field):
|
||||||
|
pass
|
@ -326,43 +326,20 @@ def get_return_data_type(func_name):
|
|||||||
return 'Integer'
|
return 'Integer'
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
# Maps Field objects to their human-readable data types, as strings.
|
|
||||||
# Column-type strings can contain format strings; they'll be interpolated
|
|
||||||
# against the values of Field.__dict__ before being output.
|
|
||||||
# If a column type is set to None, it won't be included in the output.
|
|
||||||
DATA_TYPE_MAPPING = {
|
|
||||||
'AutoField' : _('Integer'),
|
|
||||||
'BooleanField' : _('Boolean (Either True or False)'),
|
|
||||||
'CharField' : _('String (up to %(max_length)s)'),
|
|
||||||
'CommaSeparatedIntegerField': _('Comma-separated integers'),
|
|
||||||
'DateField' : _('Date (without time)'),
|
|
||||||
'DateTimeField' : _('Date (with time)'),
|
|
||||||
'DecimalField' : _('Decimal number'),
|
|
||||||
'EmailField' : _('E-mail address'),
|
|
||||||
'FileField' : _('File path'),
|
|
||||||
'FilePathField' : _('File path'),
|
|
||||||
'FloatField' : _('Floating point number'),
|
|
||||||
'ForeignKey' : _('Integer'),
|
|
||||||
'ImageField' : _('File path'),
|
|
||||||
'IntegerField' : _('Integer'),
|
|
||||||
'IPAddressField' : _('IP address'),
|
|
||||||
'ManyToManyField' : '',
|
|
||||||
'NullBooleanField' : _('Boolean (Either True, False or None)'),
|
|
||||||
'OneToOneField' : _('Relation to parent model'),
|
|
||||||
'PhoneNumberField' : _('Phone number'),
|
|
||||||
'PositiveIntegerField' : _('Integer'),
|
|
||||||
'PositiveSmallIntegerField' : _('Integer'),
|
|
||||||
'SlugField' : _('String (up to %(max_length)s)'),
|
|
||||||
'SmallIntegerField' : _('Integer'),
|
|
||||||
'TextField' : _('Text'),
|
|
||||||
'TimeField' : _('Time'),
|
|
||||||
'URLField' : _('URL'),
|
|
||||||
'USStateField' : _('U.S. state (two uppercase letters)'),
|
|
||||||
'XMLField' : _('XML text'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_readable_field_data_type(field):
|
def get_readable_field_data_type(field):
|
||||||
return DATA_TYPE_MAPPING[field.get_internal_type()] % field.__dict__
|
"""Returns the first line of a doc string for a given field type, if it
|
||||||
|
exists. Fields' docstrings can contain format strings, which will be
|
||||||
|
interpolated against the values of Field.__dict__ before being output.
|
||||||
|
If no docstring is given, a sensible value will be auto-generated from
|
||||||
|
the field's class name."""
|
||||||
|
|
||||||
|
if field.__doc__:
|
||||||
|
doc = field.__doc__.split('\n')[0]
|
||||||
|
return _(doc) % field.__dict__
|
||||||
|
else:
|
||||||
|
return _(u'Field of type: %(field_type)s') % {
|
||||||
|
'field_type': field.__class__.__name__
|
||||||
|
}
|
||||||
|
|
||||||
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
def extract_views_from_urlpatterns(urlpatterns, base=''):
|
||||||
"""
|
"""
|
||||||
|
@ -40,8 +40,8 @@ def get_srid_info(srid, connection):
|
|||||||
|
|
||||||
return _srid_cache[name][srid]
|
return _srid_cache[name][srid]
|
||||||
|
|
||||||
class GeometryField(Field):
|
class GeometryField(SpatialBackend.Field):
|
||||||
"The base GIS field -- maps to the OpenGIS Specification Geometry type."
|
"""The base GIS field -- maps to the OpenGIS Specification Geometry type."""
|
||||||
|
|
||||||
# The OpenGIS Geometry name.
|
# The OpenGIS Geometry name.
|
||||||
geom_type = 'GEOMETRY'
|
geom_type = 'GEOMETRY'
|
||||||
@ -285,22 +285,29 @@ class GeometryField(Field):
|
|||||||
|
|
||||||
# The OpenGIS Geometry Type Fields
|
# The OpenGIS Geometry Type Fields
|
||||||
class PointField(GeometryField):
|
class PointField(GeometryField):
|
||||||
|
"""Point"""
|
||||||
geom_type = 'POINT'
|
geom_type = 'POINT'
|
||||||
|
|
||||||
class LineStringField(GeometryField):
|
class LineStringField(GeometryField):
|
||||||
|
"""Line string"""
|
||||||
geom_type = 'LINESTRING'
|
geom_type = 'LINESTRING'
|
||||||
|
|
||||||
class PolygonField(GeometryField):
|
class PolygonField(GeometryField):
|
||||||
|
"""Polygon"""
|
||||||
geom_type = 'POLYGON'
|
geom_type = 'POLYGON'
|
||||||
|
|
||||||
class MultiPointField(GeometryField):
|
class MultiPointField(GeometryField):
|
||||||
|
"""Multi-point"""
|
||||||
geom_type = 'MULTIPOINT'
|
geom_type = 'MULTIPOINT'
|
||||||
|
|
||||||
class MultiLineStringField(GeometryField):
|
class MultiLineStringField(GeometryField):
|
||||||
|
"""Multi-line string"""
|
||||||
geom_type = 'MULTILINESTRING'
|
geom_type = 'MULTILINESTRING'
|
||||||
|
|
||||||
class MultiPolygonField(GeometryField):
|
class MultiPolygonField(GeometryField):
|
||||||
|
"""Multi polygon"""
|
||||||
geom_type = 'MULTIPOLYGON'
|
geom_type = 'MULTIPOLYGON'
|
||||||
|
|
||||||
class GeometryCollectionField(GeometryField):
|
class GeometryCollectionField(GeometryField):
|
||||||
|
"""Geometry collection"""
|
||||||
geom_type = 'GEOMETRYCOLLECTION'
|
geom_type = 'GEOMETRYCOLLECTION'
|
||||||
|
@ -12,13 +12,20 @@ phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
|
|||||||
sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
|
sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
|
||||||
|
|
||||||
class CAPostalCodeField(RegexField):
|
class CAPostalCodeField(RegexField):
|
||||||
"""Canadian postal code field."""
|
"""
|
||||||
|
Canadian postal code field.
|
||||||
|
|
||||||
|
Validates against known invalid characters: D, F, I, O, Q, U
|
||||||
|
Additionally the first character cannot be Z or W.
|
||||||
|
For more info see:
|
||||||
|
http://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp#1402170
|
||||||
|
"""
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid': _(u'Enter a postal code in the format XXX XXX.'),
|
'invalid': _(u'Enter a postal code in the format XXX XXX.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
|
super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] \d[ABCEGHJKLMNPRSTVWXYZ]\d$',
|
||||||
max_length=None, min_length=None, *args, **kwargs)
|
max_length=None, min_length=None, *args, **kwargs)
|
||||||
|
|
||||||
class CAPhoneNumberField(Field):
|
class CAPhoneNumberField(Field):
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
from django.db.models.fields import Field
|
from django.conf import settings
|
||||||
|
from django.db.models.fields import Field, CharField
|
||||||
class USStateField(Field):
|
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
||||||
def get_internal_type(self):
|
|
||||||
return "USStateField"
|
class USStateField(CharField):
|
||||||
|
"""U.S. state (two uppercase letters)"""
|
||||||
def db_type(self, connection):
|
def __init__(self, *args, **kwargs):
|
||||||
if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle':
|
kwargs['choices'] = STATE_CHOICES
|
||||||
return 'CHAR(2)'
|
kwargs['max_length'] = 2
|
||||||
else:
|
super(USStateField, self).__init__(*args, **kwargs)
|
||||||
return 'varchar(2)'
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
from django.contrib.localflavor.us.forms import USStateSelect
|
|
||||||
defaults = {'widget': USStateSelect}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(USStateField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
class PhoneNumberField(Field):
|
class PhoneNumberField(Field):
|
||||||
|
"""Phone number"""
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PhoneNumberField"
|
return "PhoneNumberField"
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import hmac
|
import hmac
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.hashcompat import sha_constructor
|
from django.utils.hashcompat import sha_hmac
|
||||||
from django.contrib.messages import constants
|
from django.contrib.messages import constants
|
||||||
from django.contrib.messages.storage.base import BaseStorage, Message
|
from django.contrib.messages.storage.base import BaseStorage, Message
|
||||||
from django.utils import simplejson as json
|
from django.utils import simplejson as json
|
||||||
@ -41,7 +41,6 @@ class MessageDecoder(json.JSONDecoder):
|
|||||||
decoded = super(MessageDecoder, self).decode(s, **kwargs)
|
decoded = super(MessageDecoder, self).decode(s, **kwargs)
|
||||||
return self.process_messages(decoded)
|
return self.process_messages(decoded)
|
||||||
|
|
||||||
|
|
||||||
class CookieStorage(BaseStorage):
|
class CookieStorage(BaseStorage):
|
||||||
"""
|
"""
|
||||||
Stores messages in a cookie.
|
Stores messages in a cookie.
|
||||||
@ -103,7 +102,7 @@ class CookieStorage(BaseStorage):
|
|||||||
SECRET_KEY, modified to make it unique for the present purpose.
|
SECRET_KEY, modified to make it unique for the present purpose.
|
||||||
"""
|
"""
|
||||||
key = 'django.contrib.messages' + settings.SECRET_KEY
|
key = 'django.contrib.messages' + settings.SECRET_KEY
|
||||||
return hmac.new(key, value, sha_constructor).hexdigest()
|
return hmac.new(key, value, sha_hmac).hexdigest()
|
||||||
|
|
||||||
def _encode(self, messages, encode_empty=False):
|
def _encode(self, messages, encode_empty=False):
|
||||||
"""
|
"""
|
||||||
|
@ -218,9 +218,9 @@ class BaseTest(TestCase):
|
|||||||
response = self.client.post(add_url, data, follow=True)
|
response = self.client.post(add_url, data, follow=True)
|
||||||
self.assertRedirects(response, show_url)
|
self.assertRedirects(response, show_url)
|
||||||
self.assertTrue('messages' in response.context)
|
self.assertTrue('messages' in response.context)
|
||||||
self.assertEqual(list(response.context['messages']),
|
context_messages = list(response.context['messages'])
|
||||||
data['messages'])
|
|
||||||
for msg in data['messages']:
|
for msg in data['messages']:
|
||||||
|
self.assertTrue(msg in context_messages)
|
||||||
self.assertContains(response, msg)
|
self.assertContains(response, msg)
|
||||||
|
|
||||||
def test_middleware_disabled_anon_user(self):
|
def test_middleware_disabled_anon_user(self):
|
||||||
|
25
django/core/cache/backends/memcached.py
vendored
25
django/core/cache/backends/memcached.py
vendored
@ -46,7 +46,28 @@ class CacheClass(BaseCache):
|
|||||||
self._cache.disconnect_all()
|
self._cache.disconnect_all()
|
||||||
|
|
||||||
def incr(self, key, delta=1):
|
def incr(self, key, delta=1):
|
||||||
return self._cache.incr(key, delta)
|
try:
|
||||||
|
val = self._cache.incr(key, delta)
|
||||||
|
|
||||||
|
# python-memcache responds to incr on non-existent keys by
|
||||||
|
# raising a ValueError. Cmemcache returns None. In both
|
||||||
|
# cases, we should raise a ValueError though.
|
||||||
|
except ValueError:
|
||||||
|
val = None
|
||||||
|
if val is None:
|
||||||
|
raise ValueError("Key '%s' not found" % key)
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
def decr(self, key, delta=1):
|
def decr(self, key, delta=1):
|
||||||
return self._cache.decr(key, delta)
|
try:
|
||||||
|
val = self._cache.decr(key, delta)
|
||||||
|
|
||||||
|
# python-memcache responds to decr on non-existent keys by
|
||||||
|
# raising a ValueError. Cmemcache returns None. In both
|
||||||
|
# cases, we should raise a ValueError though.
|
||||||
|
except ValueError:
|
||||||
|
val = None
|
||||||
|
if val is None:
|
||||||
|
raise ValueError("Key '%s' not found" % key)
|
||||||
|
return val
|
||||||
|
@ -6,6 +6,8 @@ class Command(BaseCommand):
|
|||||||
option_list = BaseCommand.option_list + (
|
option_list = BaseCommand.option_list + (
|
||||||
make_option('--noinput', action='store_false', dest='interactive', default=True,
|
make_option('--noinput', action='store_false', dest='interactive', default=True,
|
||||||
help='Tells Django to NOT prompt the user for input of any kind.'),
|
help='Tells Django to NOT prompt the user for input of any kind.'),
|
||||||
|
make_option('--failfast', action='store_true', dest='failfast', default=False,
|
||||||
|
help='Tells Django to stop running the test suite after first failed test.')
|
||||||
)
|
)
|
||||||
help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
|
help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.'
|
||||||
args = '[appname ...]'
|
args = '[appname ...]'
|
||||||
@ -15,11 +17,18 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *test_labels, **options):
|
def handle(self, *test_labels, **options):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test.utils import get_runner
|
from django.test.utils import get_runner
|
||||||
|
|
||||||
verbosity = int(options.get('verbosity', 1))
|
verbosity = int(options.get('verbosity', 1))
|
||||||
interactive = options.get('interactive', True)
|
interactive = options.get('interactive', True)
|
||||||
|
failfast = options.get('failfast', False)
|
||||||
test_runner = get_runner(settings)
|
test_runner = get_runner(settings)
|
||||||
|
|
||||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
# Some custom test runners won't accept the failfast flag, so let's make sure they accept it before passing it to them
|
||||||
|
if 'failfast' in test_runner.func_code.co_varnames:
|
||||||
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive,
|
||||||
|
failfast=failfast)
|
||||||
|
else:
|
||||||
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
||||||
|
|
||||||
if failures:
|
if failures:
|
||||||
sys.exit(failures)
|
sys.exit(failures)
|
||||||
|
@ -257,9 +257,8 @@ class RegexURLResolver(object):
|
|||||||
|
|
||||||
def _resolve_special(self, view_type):
|
def _resolve_special(self, view_type):
|
||||||
callback = getattr(self.urlconf_module, 'handler%s' % view_type)
|
callback = getattr(self.urlconf_module, 'handler%s' % view_type)
|
||||||
mod_name, func_name = get_mod_func(callback)
|
|
||||||
try:
|
try:
|
||||||
return getattr(import_module(mod_name), func_name), {}
|
return get_callable(callback), {}
|
||||||
except (ImportError, AttributeError), e:
|
except (ImportError, AttributeError), e:
|
||||||
raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
|
raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
|
||||||
|
|
||||||
|
@ -3,10 +3,6 @@ import datetime
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
try:
|
|
||||||
import decimal
|
|
||||||
except ImportError:
|
|
||||||
from django.utils import _decimal as decimal # for Python 2.3
|
|
||||||
|
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
@ -50,7 +46,9 @@ class FieldDoesNotExist(Exception):
|
|||||||
# getattr(obj, opts.pk.attname)
|
# getattr(obj, opts.pk.attname)
|
||||||
|
|
||||||
class Field(object):
|
class Field(object):
|
||||||
|
"""Base class for all field types"""
|
||||||
__metaclass__ = LegacyConnection
|
__metaclass__ = LegacyConnection
|
||||||
|
|
||||||
# Designates whether empty strings fundamentally are allowed at the
|
# Designates whether empty strings fundamentally are allowed at the
|
||||||
# database level.
|
# database level.
|
||||||
empty_strings_allowed = True
|
empty_strings_allowed = True
|
||||||
@ -370,7 +368,10 @@ class Field(object):
|
|||||||
return getattr(obj, self.attname)
|
return getattr(obj, self.attname)
|
||||||
|
|
||||||
class AutoField(Field):
|
class AutoField(Field):
|
||||||
|
"""Integer"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
|
assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
@ -400,7 +401,10 @@ class AutoField(Field):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
class BooleanField(Field):
|
class BooleanField(Field):
|
||||||
|
"""Boolean (Either True or False)"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
if 'default' not in kwargs and not kwargs.get('null'):
|
if 'default' not in kwargs and not kwargs.get('null'):
|
||||||
@ -443,6 +447,8 @@ class BooleanField(Field):
|
|||||||
return super(BooleanField, self).formfield(**defaults)
|
return super(BooleanField, self).formfield(**defaults)
|
||||||
|
|
||||||
class CharField(Field):
|
class CharField(Field):
|
||||||
|
"""String (up to %(max_length)s)"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "CharField"
|
return "CharField"
|
||||||
|
|
||||||
@ -464,6 +470,8 @@ class CharField(Field):
|
|||||||
|
|
||||||
# TODO: Maybe move this into contrib, because it's specialized.
|
# TODO: Maybe move this into contrib, because it's specialized.
|
||||||
class CommaSeparatedIntegerField(CharField):
|
class CommaSeparatedIntegerField(CharField):
|
||||||
|
"""Comma-separated integers"""
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {
|
defaults = {
|
||||||
'form_class': forms.RegexField,
|
'form_class': forms.RegexField,
|
||||||
@ -479,7 +487,10 @@ class CommaSeparatedIntegerField(CharField):
|
|||||||
ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
|
ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$')
|
||||||
|
|
||||||
class DateField(Field):
|
class DateField(Field):
|
||||||
|
"""Date (without time)"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
#HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
|
#HACKs : auto_now_add/auto_now should be done as a default or a pre_save.
|
||||||
@ -559,6 +570,8 @@ class DateField(Field):
|
|||||||
return super(DateField, self).formfield(**defaults)
|
return super(DateField, self).formfield(**defaults)
|
||||||
|
|
||||||
class DateTimeField(DateField):
|
class DateTimeField(DateField):
|
||||||
|
"""Date (with time)"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "DateTimeField"
|
return "DateTimeField"
|
||||||
|
|
||||||
@ -623,7 +636,10 @@ class DateTimeField(DateField):
|
|||||||
return super(DateTimeField, self).formfield(**defaults)
|
return super(DateTimeField, self).formfield(**defaults)
|
||||||
|
|
||||||
class DecimalField(Field):
|
class DecimalField(Field):
|
||||||
|
"""Decimal number"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
|
||||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
@ -677,6 +693,8 @@ class DecimalField(Field):
|
|||||||
return super(DecimalField, self).formfield(**defaults)
|
return super(DecimalField, self).formfield(**defaults)
|
||||||
|
|
||||||
class EmailField(CharField):
|
class EmailField(CharField):
|
||||||
|
"""E-mail address"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||||
CharField.__init__(self, *args, **kwargs)
|
CharField.__init__(self, *args, **kwargs)
|
||||||
@ -687,6 +705,8 @@ class EmailField(CharField):
|
|||||||
return super(EmailField, self).formfield(**defaults)
|
return super(EmailField, self).formfield(**defaults)
|
||||||
|
|
||||||
class FilePathField(Field):
|
class FilePathField(Field):
|
||||||
|
"""File path"""
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
||||||
self.path, self.match, self.recursive = path, match, recursive
|
self.path, self.match, self.recursive = path, match, recursive
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||||
@ -706,6 +726,8 @@ class FilePathField(Field):
|
|||||||
return "FilePathField"
|
return "FilePathField"
|
||||||
|
|
||||||
class FloatField(Field):
|
class FloatField(Field):
|
||||||
|
"""Floating point number"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
@ -731,8 +753,15 @@ class FloatField(Field):
|
|||||||
return super(FloatField, self).formfield(**defaults)
|
return super(FloatField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
|
"""Integer"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
<<<<<<< HEAD:django/db/models/fields/__init__.py
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
|
=======
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value):
|
||||||
|
>>>>>>> master:django/db/models/fields/__init__.py
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return int(value)
|
return int(value)
|
||||||
@ -755,7 +784,10 @@ class IntegerField(Field):
|
|||||||
return super(IntegerField, self).formfield(**defaults)
|
return super(IntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IPAddressField(Field):
|
class IPAddressField(Field):
|
||||||
|
"""IP address"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = 15
|
kwargs['max_length'] = 15
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
@ -769,7 +801,10 @@ class IPAddressField(Field):
|
|||||||
return super(IPAddressField, self).formfield(**defaults)
|
return super(IPAddressField, self).formfield(**defaults)
|
||||||
|
|
||||||
class NullBooleanField(Field):
|
class NullBooleanField(Field):
|
||||||
|
"""Boolean (Either True, False or None)"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['null'] = True
|
kwargs['null'] = True
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
@ -809,6 +844,8 @@ class NullBooleanField(Field):
|
|||||||
return super(NullBooleanField, self).formfield(**defaults)
|
return super(NullBooleanField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PositiveIntegerField(IntegerField):
|
class PositiveIntegerField(IntegerField):
|
||||||
|
"""Integer"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PositiveIntegerField"
|
return "PositiveIntegerField"
|
||||||
|
|
||||||
@ -818,6 +855,8 @@ class PositiveIntegerField(IntegerField):
|
|||||||
return super(PositiveIntegerField, self).formfield(**defaults)
|
return super(PositiveIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class PositiveSmallIntegerField(IntegerField):
|
class PositiveSmallIntegerField(IntegerField):
|
||||||
|
"""Integer"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "PositiveSmallIntegerField"
|
return "PositiveSmallIntegerField"
|
||||||
|
|
||||||
@ -827,6 +866,8 @@ class PositiveSmallIntegerField(IntegerField):
|
|||||||
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
||||||
|
|
||||||
class SlugField(CharField):
|
class SlugField(CharField):
|
||||||
|
"""String (up to %(max_length)s)"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 50)
|
kwargs['max_length'] = kwargs.get('max_length', 50)
|
||||||
# Set db_index=True unless it's been set manually.
|
# Set db_index=True unless it's been set manually.
|
||||||
@ -843,10 +884,14 @@ class SlugField(CharField):
|
|||||||
return super(SlugField, self).formfield(**defaults)
|
return super(SlugField, self).formfield(**defaults)
|
||||||
|
|
||||||
class SmallIntegerField(IntegerField):
|
class SmallIntegerField(IntegerField):
|
||||||
|
"""Integer"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "SmallIntegerField"
|
return "SmallIntegerField"
|
||||||
|
|
||||||
class TextField(Field):
|
class TextField(Field):
|
||||||
|
"""Text"""
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "TextField"
|
return "TextField"
|
||||||
|
|
||||||
@ -856,7 +901,10 @@ class TextField(Field):
|
|||||||
return super(TextField, self).formfield(**defaults)
|
return super(TextField, self).formfield(**defaults)
|
||||||
|
|
||||||
class TimeField(Field):
|
class TimeField(Field):
|
||||||
|
"""Time"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
if auto_now or auto_now_add:
|
if auto_now or auto_now_add:
|
||||||
@ -933,6 +981,8 @@ class TimeField(Field):
|
|||||||
return super(TimeField, self).formfield(**defaults)
|
return super(TimeField, self).formfield(**defaults)
|
||||||
|
|
||||||
class URLField(CharField):
|
class URLField(CharField):
|
||||||
|
"""URL"""
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 200)
|
kwargs['max_length'] = kwargs.get('max_length', 200)
|
||||||
self.verify_exists = verify_exists
|
self.verify_exists = verify_exists
|
||||||
@ -944,6 +994,8 @@ class URLField(CharField):
|
|||||||
return super(URLField, self).formfield(**defaults)
|
return super(URLField, self).formfield(**defaults)
|
||||||
|
|
||||||
class XMLField(TextField):
|
class XMLField(TextField):
|
||||||
|
"""XML text"""
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
|
def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
|
||||||
self.schema_path = schema_path
|
self.schema_path = schema_path
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
|
@ -209,6 +209,8 @@ class FileDescriptor(object):
|
|||||||
instance.__dict__[self.field.name] = value
|
instance.__dict__[self.field.name] = value
|
||||||
|
|
||||||
class FileField(Field):
|
class FileField(Field):
|
||||||
|
"""File path"""
|
||||||
|
|
||||||
# The class to wrap instance attributes in. Accessing the file object off
|
# The class to wrap instance attributes in. Accessing the file object off
|
||||||
# the instance will always return an instance of attr_class.
|
# the instance will always return an instance of attr_class.
|
||||||
attr_class = FieldFile
|
attr_class = FieldFile
|
||||||
@ -323,6 +325,8 @@ class ImageFieldFile(ImageFile, FieldFile):
|
|||||||
super(ImageFieldFile, self).delete(save)
|
super(ImageFieldFile, self).delete(save)
|
||||||
|
|
||||||
class ImageField(FileField):
|
class ImageField(FileField):
|
||||||
|
"""File path"""
|
||||||
|
|
||||||
attr_class = ImageFieldFile
|
attr_class = ImageFieldFile
|
||||||
descriptor_class = ImageFileDescriptor
|
descriptor_class = ImageFileDescriptor
|
||||||
|
|
||||||
|
@ -708,6 +708,8 @@ class ManyToManyRel(object):
|
|||||||
return self.to._meta.pk
|
return self.to._meta.pk
|
||||||
|
|
||||||
class ForeignKey(RelatedField, Field):
|
class ForeignKey(RelatedField, Field):
|
||||||
|
"""Foreign Key (type determined by related field)"""
|
||||||
|
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
||||||
try:
|
try:
|
||||||
@ -806,12 +808,13 @@ class ForeignKey(RelatedField, Field):
|
|||||||
return rel_field.db_type(connection=connection)
|
return rel_field.db_type(connection=connection)
|
||||||
|
|
||||||
class OneToOneField(ForeignKey):
|
class OneToOneField(ForeignKey):
|
||||||
"""
|
"""One-to-one relationship
|
||||||
|
|
||||||
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
||||||
that always carries a "unique" constraint with it and the reverse relation
|
that always carries a "unique" constraint with it and the reverse relation
|
||||||
always returns the object pointed to (since there will only ever be one),
|
always returns the object pointed to (since there will only ever be one),
|
||||||
rather than returning a list.
|
rather than returning a list."""
|
||||||
"""
|
|
||||||
def __init__(self, to, to_field=None, **kwargs):
|
def __init__(self, to, to_field=None, **kwargs):
|
||||||
kwargs['unique'] = True
|
kwargs['unique'] = True
|
||||||
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
||||||
@ -865,6 +868,8 @@ def create_many_to_many_intermediary_model(field, klass):
|
|||||||
})
|
})
|
||||||
|
|
||||||
class ManyToManyField(RelatedField, Field):
|
class ManyToManyField(RelatedField, Field):
|
||||||
|
"""Many-to-many relationship"""
|
||||||
|
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
try:
|
try:
|
||||||
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
|
||||||
|
@ -138,6 +138,8 @@ class BaseForm(StrAndUnicode):
|
|||||||
"Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
|
"Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
|
||||||
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
|
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
|
||||||
output, hidden_fields = [], []
|
output, hidden_fields = [], []
|
||||||
|
html_class_attr = ''
|
||||||
|
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
bf = BoundField(self, field, name)
|
bf = BoundField(self, field, name)
|
||||||
bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
||||||
@ -146,8 +148,15 @@ class BaseForm(StrAndUnicode):
|
|||||||
top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
||||||
hidden_fields.append(unicode(bf))
|
hidden_fields.append(unicode(bf))
|
||||||
else:
|
else:
|
||||||
|
# Create a 'class="..."' atribute if the row should have any
|
||||||
|
# CSS classes applied.
|
||||||
|
css_classes = bf.css_classes()
|
||||||
|
if css_classes:
|
||||||
|
html_class_attr = ' class="%s"' % css_classes
|
||||||
|
|
||||||
if errors_on_separate_row and bf_errors:
|
if errors_on_separate_row and bf_errors:
|
||||||
output.append(error_row % force_unicode(bf_errors))
|
output.append(error_row % force_unicode(bf_errors))
|
||||||
|
|
||||||
if bf.label:
|
if bf.label:
|
||||||
label = conditional_escape(force_unicode(bf.label))
|
label = conditional_escape(force_unicode(bf.label))
|
||||||
# Only add the suffix if the label does not end in
|
# Only add the suffix if the label does not end in
|
||||||
@ -158,13 +167,23 @@ class BaseForm(StrAndUnicode):
|
|||||||
label = bf.label_tag(label) or ''
|
label = bf.label_tag(label) or ''
|
||||||
else:
|
else:
|
||||||
label = ''
|
label = ''
|
||||||
|
|
||||||
if field.help_text:
|
if field.help_text:
|
||||||
help_text = help_text_html % force_unicode(field.help_text)
|
help_text = help_text_html % force_unicode(field.help_text)
|
||||||
else:
|
else:
|
||||||
help_text = u''
|
help_text = u''
|
||||||
output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text})
|
|
||||||
|
output.append(normal_row % {
|
||||||
|
'errors': force_unicode(bf_errors),
|
||||||
|
'label': force_unicode(label),
|
||||||
|
'field': unicode(bf),
|
||||||
|
'help_text': help_text,
|
||||||
|
'html_class_attr': html_class_attr
|
||||||
|
})
|
||||||
|
|
||||||
if top_errors:
|
if top_errors:
|
||||||
output.insert(0, error_row % force_unicode(top_errors))
|
output.insert(0, error_row % force_unicode(top_errors))
|
||||||
|
|
||||||
if hidden_fields: # Insert any hidden fields in the last row.
|
if hidden_fields: # Insert any hidden fields in the last row.
|
||||||
str_hidden = u''.join(hidden_fields)
|
str_hidden = u''.join(hidden_fields)
|
||||||
if output:
|
if output:
|
||||||
@ -176,7 +195,9 @@ class BaseForm(StrAndUnicode):
|
|||||||
# that users write): if there are only top errors, we may
|
# that users write): if there are only top errors, we may
|
||||||
# not be able to conscript the last row for our purposes,
|
# not be able to conscript the last row for our purposes,
|
||||||
# so insert a new, empty row.
|
# so insert a new, empty row.
|
||||||
last_row = normal_row % {'errors': '', 'label': '', 'field': '', 'help_text': ''}
|
last_row = (normal_row % {'errors': '', 'label': '',
|
||||||
|
'field': '', 'help_text':'',
|
||||||
|
'html_class_attr': html_class_attr})
|
||||||
output.append(last_row)
|
output.append(last_row)
|
||||||
output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
|
output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
|
||||||
else:
|
else:
|
||||||
@ -187,15 +208,30 @@ class BaseForm(StrAndUnicode):
|
|||||||
|
|
||||||
def as_table(self):
|
def as_table(self):
|
||||||
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
|
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
|
||||||
return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False)
|
return self._html_output(
|
||||||
|
normal_row = u'<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
|
||||||
|
error_row = u'<tr><td colspan="2">%s</td></tr>',
|
||||||
|
row_ender = u'</td></tr>',
|
||||||
|
help_text_html = u'<br />%s',
|
||||||
|
errors_on_separate_row = False)
|
||||||
|
|
||||||
def as_ul(self):
|
def as_ul(self):
|
||||||
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
|
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
|
||||||
return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False)
|
return self._html_output(
|
||||||
|
normal_row = u'<li%(html_class_attr)s>%(errors)s%(label)s %(field)s%(help_text)s</li>',
|
||||||
|
error_row = u'<li>%s</li>',
|
||||||
|
row_ender = '</li>',
|
||||||
|
help_text_html = u' %s',
|
||||||
|
errors_on_separate_row = False)
|
||||||
|
|
||||||
def as_p(self):
|
def as_p(self):
|
||||||
"Returns this form rendered as HTML <p>s."
|
"Returns this form rendered as HTML <p>s."
|
||||||
return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'%s', '</p>', u' %s', True)
|
return self._html_output(
|
||||||
|
normal_row = u'<p%(html_class_attr)s>%(label)s %(field)s%(help_text)s</p>',
|
||||||
|
error_row = u'%s',
|
||||||
|
row_ender = '</p>',
|
||||||
|
help_text_html = u' %s',
|
||||||
|
errors_on_separate_row = True)
|
||||||
|
|
||||||
def non_field_errors(self):
|
def non_field_errors(self):
|
||||||
"""
|
"""
|
||||||
@ -343,6 +379,7 @@ class BoundField(StrAndUnicode):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.html_name = form.add_prefix(name)
|
self.html_name = form.add_prefix(name)
|
||||||
self.html_initial_name = form.add_initial_prefix(name)
|
self.html_initial_name = form.add_initial_prefix(name)
|
||||||
|
self.html_initial_id = form.add_initial_prefix(self.auto_id)
|
||||||
if self.field.label is None:
|
if self.field.label is None:
|
||||||
self.label = pretty_name(name)
|
self.label = pretty_name(name)
|
||||||
else:
|
else:
|
||||||
@ -374,7 +411,10 @@ class BoundField(StrAndUnicode):
|
|||||||
attrs = attrs or {}
|
attrs = attrs or {}
|
||||||
auto_id = self.auto_id
|
auto_id = self.auto_id
|
||||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
||||||
attrs['id'] = auto_id
|
if not only_initial:
|
||||||
|
attrs['id'] = auto_id
|
||||||
|
else:
|
||||||
|
attrs['id'] = self.html_initial_id
|
||||||
if not self.form.is_bound:
|
if not self.form.is_bound:
|
||||||
data = self.form.initial.get(self.name, self.field.initial)
|
data = self.form.initial.get(self.name, self.field.initial)
|
||||||
if callable(data):
|
if callable(data):
|
||||||
@ -429,6 +469,19 @@ class BoundField(StrAndUnicode):
|
|||||||
contents = u'<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, unicode(contents))
|
contents = u'<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, unicode(contents))
|
||||||
return mark_safe(contents)
|
return mark_safe(contents)
|
||||||
|
|
||||||
|
def css_classes(self, extra_classes=None):
|
||||||
|
"""
|
||||||
|
Returns a string of space-separated CSS classes for this field.
|
||||||
|
"""
|
||||||
|
if hasattr(extra_classes, 'split'):
|
||||||
|
extra_classes = extra_classes.split()
|
||||||
|
extra_classes = set(extra_classes or [])
|
||||||
|
if self.errors and hasattr(self.form, 'error_css_class'):
|
||||||
|
extra_classes.add(self.form.error_css_class)
|
||||||
|
if self.field.required and hasattr(self.form, 'required_css_class'):
|
||||||
|
extra_classes.add(self.form.required_css_class)
|
||||||
|
return ' '.join(extra_classes)
|
||||||
|
|
||||||
def _is_hidden(self):
|
def _is_hidden(self):
|
||||||
"Returns True if this BoundField's widget is hidden."
|
"Returns True if this BoundField's widget is hidden."
|
||||||
return self.field.widget.is_hidden
|
return self.field.widget.is_hidden
|
||||||
|
@ -912,6 +912,9 @@ class ModelChoiceIterator(object):
|
|||||||
for obj in self.queryset.all():
|
for obj in self.queryset.all():
|
||||||
yield self.choice(obj)
|
yield self.choice(obj)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.queryset)
|
||||||
|
|
||||||
def choice(self, obj):
|
def choice(self, obj):
|
||||||
if self.field.to_field_name:
|
if self.field.to_field_name:
|
||||||
key = obj.serializable_value(self.field.to_field_name)
|
key = obj.serializable_value(self.field.to_field_name)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from Cookie import SimpleCookie, CookieError
|
from Cookie import BaseCookie, SimpleCookie, CookieError
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
@ -251,13 +251,15 @@ class QueryDict(MultiValueDict):
|
|||||||
def parse_cookie(cookie):
|
def parse_cookie(cookie):
|
||||||
if cookie == '':
|
if cookie == '':
|
||||||
return {}
|
return {}
|
||||||
try:
|
if not isinstance(cookie, BaseCookie):
|
||||||
c = SimpleCookie()
|
try:
|
||||||
c.load(cookie)
|
c = SimpleCookie()
|
||||||
except CookieError:
|
c.load(cookie)
|
||||||
# Invalid cookie
|
except CookieError:
|
||||||
return {}
|
# Invalid cookie
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
c = cookie
|
||||||
cookiedict = {}
|
cookiedict = {}
|
||||||
for key in c.keys():
|
for key in c.keys():
|
||||||
cookiedict[key] = c.get(key).value
|
cookiedict[key] = c.get(key).value
|
||||||
|
@ -249,7 +249,8 @@ stringformat.is_safe = True
|
|||||||
|
|
||||||
def title(value):
|
def title(value):
|
||||||
"""Converts a string into titlecase."""
|
"""Converts a string into titlecase."""
|
||||||
return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
|
t = re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
|
||||||
|
return re.sub("\d([A-Z])", lambda m: m.group(0).lower(), t)
|
||||||
title.is_safe = True
|
title.is_safe = True
|
||||||
title = stringfilter(title)
|
title = stringfilter(title)
|
||||||
|
|
||||||
|
@ -10,6 +10,26 @@ TEST_MODULE = 'tests'
|
|||||||
|
|
||||||
doctestOutputChecker = OutputChecker()
|
doctestOutputChecker = OutputChecker()
|
||||||
|
|
||||||
|
class DjangoTestRunner(unittest.TextTestRunner):
|
||||||
|
|
||||||
|
def __init__(self, verbosity=0, failfast=False, **kwargs):
|
||||||
|
super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
|
||||||
|
self.failfast = failfast
|
||||||
|
|
||||||
|
def _makeResult(self):
|
||||||
|
result = super(DjangoTestRunner, self)._makeResult()
|
||||||
|
failfast = self.failfast
|
||||||
|
|
||||||
|
def stoptest_override(func):
|
||||||
|
def stoptest(test):
|
||||||
|
if failfast and not result.wasSuccessful():
|
||||||
|
result.stop()
|
||||||
|
func(test)
|
||||||
|
return stoptest
|
||||||
|
|
||||||
|
setattr(result, 'stopTest', stoptest_override(result.stopTest))
|
||||||
|
return result
|
||||||
|
|
||||||
def get_tests(app_module):
|
def get_tests(app_module):
|
||||||
try:
|
try:
|
||||||
app_path = app_module.__name__.split('.')[:-1]
|
app_path = app_module.__name__.split('.')[:-1]
|
||||||
@ -146,7 +166,7 @@ def reorder_suite(suite, classes):
|
|||||||
bins[0].addTests(bins[i+1])
|
bins[0].addTests(bins[i+1])
|
||||||
return bins[0]
|
return bins[0]
|
||||||
|
|
||||||
def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
|
def run_tests(test_labels, verbosity=1, interactive=True, failfast=False, extra_tests=[]):
|
||||||
"""
|
"""
|
||||||
Run the unit tests for all the test labels in the provided list.
|
Run the unit tests for all the test labels in the provided list.
|
||||||
Labels must be of the form:
|
Labels must be of the form:
|
||||||
@ -186,13 +206,13 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
|
|||||||
|
|
||||||
suite = reorder_suite(suite, (TestCase,))
|
suite = reorder_suite(suite, (TestCase,))
|
||||||
|
|
||||||
old_names = []
|
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
|
old_names = []
|
||||||
for alias in connections:
|
for alias in connections:
|
||||||
connection = connections[alias]
|
connection = connections[alias]
|
||||||
old_names.append((connection, connection.settings_dict['NAME']))
|
old_names.append((connection, connection.settings_dict['NAME']))
|
||||||
connection.creation.create_test_db(verbosity, autoclobber=not interactive)
|
connection.creation.create_test_db(verbosity, autoclobber=not interactive)
|
||||||
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
|
result = DjangoTestRunner(verbosity=verbosity, failfast=failfast).run(suite)
|
||||||
for connection, old_name in old_names:
|
for connection, old_name in old_names:
|
||||||
connection.creation.destroy_test_db(old_name, verbosity)
|
connection.creation.destroy_test_db(old_name, verbosity)
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
class MergeDict(object):
|
class MergeDict(object):
|
||||||
"""
|
"""
|
||||||
A simple class for creating new "virtual" dictionaries that actually look
|
A simple class for creating new "virtual" dictionaries that actually look
|
||||||
@ -72,22 +75,20 @@ class SortedDict(dict):
|
|||||||
self.keyOrder.append(key)
|
self.keyOrder.append(key)
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
from copy import deepcopy
|
|
||||||
return self.__class__([(key, deepcopy(value, memo))
|
return self.__class__([(key, deepcopy(value, memo))
|
||||||
for key, value in self.iteritems()])
|
for key, value in self.iteritems()])
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
super(SortedDict, self).__setitem__(key, value)
|
if key not in self:
|
||||||
if key not in self.keyOrder:
|
|
||||||
self.keyOrder.append(key)
|
self.keyOrder.append(key)
|
||||||
|
super(SortedDict, self).__setitem__(key, value)
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
super(SortedDict, self).__delitem__(key)
|
super(SortedDict, self).__delitem__(key)
|
||||||
self.keyOrder.remove(key)
|
self.keyOrder.remove(key)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for k in self.keyOrder:
|
return iter(self.keyOrder)
|
||||||
yield k
|
|
||||||
|
|
||||||
def pop(self, k, *args):
|
def pop(self, k, *args):
|
||||||
result = super(SortedDict, self).pop(k, *args)
|
result = super(SortedDict, self).pop(k, *args)
|
||||||
@ -108,7 +109,7 @@ class SortedDict(dict):
|
|||||||
|
|
||||||
def iteritems(self):
|
def iteritems(self):
|
||||||
for key in self.keyOrder:
|
for key in self.keyOrder:
|
||||||
yield key, super(SortedDict, self).__getitem__(key)
|
yield key, self[key]
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.keyOrder[:]
|
return self.keyOrder[:]
|
||||||
@ -117,18 +118,18 @@ class SortedDict(dict):
|
|||||||
return iter(self.keyOrder)
|
return iter(self.keyOrder)
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return map(super(SortedDict, self).__getitem__, self.keyOrder)
|
return map(self.__getitem__, self.keyOrder)
|
||||||
|
|
||||||
def itervalues(self):
|
def itervalues(self):
|
||||||
for key in self.keyOrder:
|
for key in self.keyOrder:
|
||||||
yield super(SortedDict, self).__getitem__(key)
|
yield self[key]
|
||||||
|
|
||||||
def update(self, dict_):
|
def update(self, dict_):
|
||||||
for k, v in dict_.items():
|
for k, v in dict_.iteritems():
|
||||||
self.__setitem__(k, v)
|
self[k] = v
|
||||||
|
|
||||||
def setdefault(self, key, default):
|
def setdefault(self, key, default):
|
||||||
if key not in self.keyOrder:
|
if key not in self:
|
||||||
self.keyOrder.append(key)
|
self.keyOrder.append(key)
|
||||||
return super(SortedDict, self).setdefault(key, default)
|
return super(SortedDict, self).setdefault(key, default)
|
||||||
|
|
||||||
@ -222,18 +223,18 @@ class MultiValueDict(dict):
|
|||||||
dict.__setitem__(result, copy.deepcopy(key, memo),
|
dict.__setitem__(result, copy.deepcopy(key, memo),
|
||||||
copy.deepcopy(value, memo))
|
copy.deepcopy(value, memo))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
obj_dict = self.__dict__.copy()
|
obj_dict = self.__dict__.copy()
|
||||||
obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self])
|
obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self])
|
||||||
return obj_dict
|
return obj_dict
|
||||||
|
|
||||||
def __setstate__(self, obj_dict):
|
def __setstate__(self, obj_dict):
|
||||||
data = obj_dict.pop('_data', {})
|
data = obj_dict.pop('_data', {})
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
self.setlist(k, v)
|
self.setlist(k, v)
|
||||||
self.__dict__.update(obj_dict)
|
self.__dict__.update(obj_dict)
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
"""
|
"""
|
||||||
Returns the last data value for the passed key. If key doesn't exist
|
Returns the last data value for the passed key. If key doesn't exist
|
||||||
@ -301,12 +302,12 @@ class MultiValueDict(dict):
|
|||||||
def values(self):
|
def values(self):
|
||||||
"""Returns a list of the last value on every key list."""
|
"""Returns a list of the last value on every key list."""
|
||||||
return [self[key] for key in self.keys()]
|
return [self[key] for key in self.keys()]
|
||||||
|
|
||||||
def itervalues(self):
|
def itervalues(self):
|
||||||
"""Yield the last value on every key list."""
|
"""Yield the last value on every key list."""
|
||||||
for key in self.iterkeys():
|
for key in self.iterkeys():
|
||||||
yield self[key]
|
yield self[key]
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""Returns a copy of this object."""
|
"""Returns a copy of this object."""
|
||||||
return self.__deepcopy__()
|
return self.__deepcopy__()
|
||||||
|
@ -277,6 +277,13 @@ class LazyObject(object):
|
|||||||
self._setup()
|
self._setup()
|
||||||
setattr(self._wrapped, name, value)
|
setattr(self._wrapped, name, value)
|
||||||
|
|
||||||
|
def __delattr__(self, name):
|
||||||
|
if name == "_wrapped":
|
||||||
|
raise TypeError("can't delete _wrapped.")
|
||||||
|
if self._wrapped is None:
|
||||||
|
self._setup()
|
||||||
|
delattr(self._wrapped, name)
|
||||||
|
|
||||||
def _setup(self):
|
def _setup(self):
|
||||||
"""
|
"""
|
||||||
Must be implemented by subclasses to initialise the wrapped object.
|
Must be implemented by subclasses to initialise the wrapped object.
|
||||||
|
@ -8,9 +8,13 @@ available.
|
|||||||
try:
|
try:
|
||||||
import hashlib
|
import hashlib
|
||||||
md5_constructor = hashlib.md5
|
md5_constructor = hashlib.md5
|
||||||
|
md5_hmac = md5_constructor
|
||||||
sha_constructor = hashlib.sha1
|
sha_constructor = hashlib.sha1
|
||||||
|
sha_hmac = sha_constructor
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import md5
|
import md5
|
||||||
md5_constructor = md5.new
|
md5_constructor = md5.new
|
||||||
|
md5_hmac = md5
|
||||||
import sha
|
import sha
|
||||||
sha_constructor = sha.new
|
sha_constructor = sha.new
|
||||||
|
sha_hmac = sha
|
||||||
|
@ -39,6 +39,8 @@ are traditionally called *north*, *east*, *south* and *west*. Our class looks
|
|||||||
something like this::
|
something like this::
|
||||||
|
|
||||||
class Hand(object):
|
class Hand(object):
|
||||||
|
"""A hand of cards (bridge style)"""
|
||||||
|
|
||||||
def __init__(self, north, east, south, west):
|
def __init__(self, north, east, south, west):
|
||||||
# Input parameters are lists of cards ('Ah', '9s', etc)
|
# Input parameters are lists of cards ('Ah', '9s', etc)
|
||||||
self.north = north
|
self.north = north
|
||||||
@ -163,6 +165,8 @@ behave like any existing field, so we'll subclass directly from
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
|
"""A hand of cards (bridge style)"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_length'] = 104
|
kwargs['max_length'] = 104
|
||||||
super(HandField, self).__init__(*args, **kwargs)
|
super(HandField, self).__init__(*args, **kwargs)
|
||||||
@ -244,6 +248,8 @@ simple: make sure your field subclass uses a special metaclass:
|
|||||||
For example::
|
For example::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
|
"""A hand of cards (bridge style)"""
|
||||||
|
|
||||||
__metaclass__ = models.SubfieldBase
|
__metaclass__ = models.SubfieldBase
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -252,6 +258,21 @@ For example::
|
|||||||
This ensures that the :meth:`to_python` method, documented below, will always be
|
This ensures that the :meth:`to_python` method, documented below, will always be
|
||||||
called when the attribute is initialized.
|
called when the attribute is initialized.
|
||||||
|
|
||||||
|
|
||||||
|
Documenting your Custom Field
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
As always, you should document your field type, so users will know what it is.
|
||||||
|
The best way to do this is to simply provide a docstring for it. This will
|
||||||
|
automatically be picked up by ``django.contrib.admindocs``, if you have it
|
||||||
|
installed, and the first line of it will show up as the field type in the
|
||||||
|
documentation for any model that uses your field. In the above examples, it
|
||||||
|
will show up as 'A hand of cards (bridge style)'. Note that if you provide a
|
||||||
|
more verbose docstring, only the first line will show up in
|
||||||
|
``django.contrib.admindocs``. The full docstring will, of course, still be
|
||||||
|
available through ``pydoc`` or the interactive interpreter's ``help()``
|
||||||
|
function.
|
||||||
|
|
||||||
Useful methods
|
Useful methods
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ Having trouble? We'd like to help!
|
|||||||
.. _archives of the django-users mailing list: http://groups.google.com/group/django-users/
|
.. _archives of the django-users mailing list: http://groups.google.com/group/django-users/
|
||||||
.. _post a question: http://groups.google.com/group/django-users/
|
.. _post a question: http://groups.google.com/group/django-users/
|
||||||
.. _#django IRC channel: irc://irc.freenode.net/django
|
.. _#django IRC channel: irc://irc.freenode.net/django
|
||||||
.. _IRC logs: http://oebfare.com/logger/django/
|
.. _IRC logs: http://botland.oebfare.com/logger/django/
|
||||||
.. _ticket tracker: http://code.djangoproject.com/
|
.. _ticket tracker: http://code.djangoproject.com/
|
||||||
|
|
||||||
First steps
|
First steps
|
||||||
|
@ -802,6 +802,14 @@ test <app or test identifier>
|
|||||||
Runs tests for all installed models. See :ref:`topics-testing` for more
|
Runs tests for all installed models. See :ref:`topics-testing` for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
--failfast
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
Use the ``--failfast`` option to stop running tests and report the failure
|
||||||
|
immediately after a test fails.
|
||||||
|
|
||||||
testserver <fixture fixture ...>
|
testserver <fixture fixture ...>
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
@ -366,6 +366,36 @@ calls its ``as_table()`` method behind the scenes::
|
|||||||
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
|
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
|
||||||
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
||||||
|
|
||||||
|
Styling required or erroneous form rows
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
It's pretty common to style form rows and fields that are required or have
|
||||||
|
errors. For example, you might want to present required form rows in bold and
|
||||||
|
highlight errors in red.
|
||||||
|
|
||||||
|
The :class:`Form` class has a couple of hooks you can use to add ``class``
|
||||||
|
attributes to required rows or to rows with errors: simple set the
|
||||||
|
:attr:`Form.error_css_class` and/or :attr:`Form.required_css_class`
|
||||||
|
attributes::
|
||||||
|
|
||||||
|
class ContactForm(Form):
|
||||||
|
error_css_class = 'error'
|
||||||
|
required_css_class = 'required'
|
||||||
|
|
||||||
|
# ... and the rest of your fields here
|
||||||
|
|
||||||
|
Once you've done that, rows will be given ``"error"`` and/or ``"required"``
|
||||||
|
classes, as needed. The HTML will look something like::
|
||||||
|
|
||||||
|
>>> f = ContactForm(data)
|
||||||
|
>>> print f.as_table()
|
||||||
|
<tr class="required"><th><label for="id_subject">Subject:</label> ...
|
||||||
|
<tr class="required"><th><label for="id_message">Message:</label> ...
|
||||||
|
<tr class="required error"><th><label for="id_sender">Sender:</label> ...
|
||||||
|
<tr><th><label for="id_cc_myself">Cc myself:<label> ...
|
||||||
|
|
||||||
.. _ref-forms-api-configuring-label:
|
.. _ref-forms-api-configuring-label:
|
||||||
|
|
||||||
Configuring HTML ``<label>`` tags
|
Configuring HTML ``<label>`` tags
|
||||||
|
@ -253,24 +253,30 @@ handler404
|
|||||||
|
|
||||||
.. data:: handler404
|
.. data:: handler404
|
||||||
|
|
||||||
A string representing the full Python import path to the view that should be
|
A callable, or a string representing the full Python import path to the view
|
||||||
called if none of the URL patterns match.
|
that should be called if none of the URL patterns match.
|
||||||
|
|
||||||
By default, this is ``'django.views.defaults.page_not_found'``. That default
|
By default, this is ``'django.views.defaults.page_not_found'``. That default
|
||||||
value should suffice.
|
value should suffice.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.2
|
||||||
|
Previous versions of Django only accepted strings representing import paths.
|
||||||
|
|
||||||
handler500
|
handler500
|
||||||
----------
|
----------
|
||||||
|
|
||||||
.. data:: handler500
|
.. data:: handler500
|
||||||
|
|
||||||
A string representing the full Python import path to the view that should be
|
A callable, or a string representing the full Python import path to the view
|
||||||
called in case of server errors. Server errors happen when you have runtime
|
that should be called in case of server errors. Server errors happen when you
|
||||||
errors in view code.
|
have runtime errors in view code.
|
||||||
|
|
||||||
By default, this is ``'django.views.defaults.server_error'``. That default
|
By default, this is ``'django.views.defaults.server_error'``. That default
|
||||||
value should suffice.
|
value should suffice.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.2
|
||||||
|
Previous versions of Django only accepted strings representing import paths.
|
||||||
|
|
||||||
include
|
include
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -885,7 +885,7 @@ False
|
|||||||
>>> form = formset.forms[0] # this formset only has one form
|
>>> form = formset.forms[0] # this formset only has one form
|
||||||
>>> now = form.fields['date_joined'].initial
|
>>> now = form.fields['date_joined'].initial
|
||||||
>>> print form.as_p()
|
>>> print form.as_p()
|
||||||
<p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /></p>
|
<p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="..." id="initial-membership_set-0-id_membership_set-0-date_joined" /></p>
|
||||||
<p><label for="id_membership_set-0-karma">Karma:</label> <input type="text" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-person" value="1" id="id_membership_set-0-person" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>
|
<p><label for="id_membership_set-0-karma">Karma:</label> <input type="text" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-person" value="1" id="id_membership_set-0-person" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>
|
||||||
|
|
||||||
# test for validation with callable defaults. Validations rely on hidden fields
|
# test for validation with callable defaults. Validations rely on hidden fields
|
||||||
|
@ -1157,7 +1157,6 @@ class AdminActionsTest(TestCase):
|
|||||||
self.assert_('action-checkbox-column' in response.content,
|
self.assert_('action-checkbox-column' in response.content,
|
||||||
"Expected an action-checkbox-column in response")
|
"Expected an action-checkbox-column in response")
|
||||||
|
|
||||||
|
|
||||||
def test_multiple_actions_form(self):
|
def test_multiple_actions_form(self):
|
||||||
"""
|
"""
|
||||||
Test that actions come from the form whose submit button was pressed (#10618).
|
Test that actions come from the form whose submit button was pressed (#10618).
|
||||||
@ -1175,6 +1174,35 @@ class AdminActionsTest(TestCase):
|
|||||||
self.assertEquals(len(mail.outbox), 1)
|
self.assertEquals(len(mail.outbox), 1)
|
||||||
self.assertEquals(mail.outbox[0].subject, 'Greetings from a function action')
|
self.assertEquals(mail.outbox[0].subject, 'Greetings from a function action')
|
||||||
|
|
||||||
|
def test_user_message_on_none_selected(self):
|
||||||
|
"""
|
||||||
|
User should see a warning when 'Go' is pressed and no items are selected.
|
||||||
|
"""
|
||||||
|
action_data = {
|
||||||
|
ACTION_CHECKBOX_NAME: [],
|
||||||
|
'action' : 'delete_selected',
|
||||||
|
'index': 0,
|
||||||
|
}
|
||||||
|
response = self.client.post('/test_admin/admin/admin_views/subscriber/', action_data)
|
||||||
|
msg = """Items must be selected in order to perform actions on them. No items have been changed."""
|
||||||
|
self.assertContains(response, msg)
|
||||||
|
self.failUnlessEqual(Subscriber.objects.count(), 2)
|
||||||
|
|
||||||
|
def test_user_message_on_no_action(self):
|
||||||
|
"""
|
||||||
|
User should see a warning when 'Go' is pressed and no action is selected.
|
||||||
|
"""
|
||||||
|
action_data = {
|
||||||
|
ACTION_CHECKBOX_NAME: [1, 2],
|
||||||
|
'action' : '',
|
||||||
|
'index': 0,
|
||||||
|
}
|
||||||
|
response = self.client.post('/test_admin/admin/admin_views/subscriber/', action_data)
|
||||||
|
msg = """No action selected."""
|
||||||
|
self.assertContains(response, msg)
|
||||||
|
self.failUnlessEqual(Subscriber.objects.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class TestInlineNotEditable(TestCase):
|
class TestInlineNotEditable(TestCase):
|
||||||
fixtures = ['admin-views-users.xml']
|
fixtures = ['admin-views-users.xml']
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1807,4 +1807,43 @@ True
|
|||||||
>>> [f.name for f in form.visible_fields()]
|
>>> [f.name for f in form.visible_fields()]
|
||||||
['artist', 'name']
|
['artist', 'name']
|
||||||
|
|
||||||
|
# Hidden initial input gets its own unique id ################################
|
||||||
|
|
||||||
|
>>> class MyForm(Form):
|
||||||
|
... field1 = CharField(max_length=50, show_hidden_initial=True)
|
||||||
|
>>> print MyForm()
|
||||||
|
<tr><th><label for="id_field1">Field1:</label></th><td><input id="id_field1" type="text" name="field1" maxlength="50" /><input type="hidden" name="initial-field1" id="initial-id_field1" /></td></tr>
|
||||||
|
|
||||||
|
# The error_html_class and required_html_class attributes ####################
|
||||||
|
|
||||||
|
>>> p = Person({})
|
||||||
|
>>> p.error_css_class = 'error'
|
||||||
|
>>> p.required_css_class = 'required'
|
||||||
|
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li class="required error"><ul class="errorlist"><li>This field is required.</li></ul><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li>
|
||||||
|
<li class="required"><label for="id_is_cool">Is cool:</label> <select name="is_cool" id="id_is_cool">
|
||||||
|
<option value="1" selected="selected">Unknown</option>
|
||||||
|
<option value="2">Yes</option>
|
||||||
|
<option value="3">No</option>
|
||||||
|
</select></li>
|
||||||
|
|
||||||
|
>>> print p.as_p()
|
||||||
|
<ul class="errorlist"><li>This field is required.</li></ul>
|
||||||
|
<p class="required error"><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p>
|
||||||
|
<p class="required"><label for="id_is_cool">Is cool:</label> <select name="is_cool" id="id_is_cool">
|
||||||
|
<option value="1" selected="selected">Unknown</option>
|
||||||
|
<option value="2">Yes</option>
|
||||||
|
<option value="3">No</option>
|
||||||
|
</select></p>
|
||||||
|
|
||||||
|
>>> print p.as_table()
|
||||||
|
<tr class="required error"><th><label for="id_name">Name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="name" id="id_name" /></td></tr>
|
||||||
|
<tr class="required"><th><label for="id_is_cool">Is cool:</label></th><td><select name="is_cool" id="id_is_cool">
|
||||||
|
<option value="1" selected="selected">Unknown</option>
|
||||||
|
<option value="2">Yes</option>
|
||||||
|
<option value="3">No</option>
|
||||||
|
</select></td></tr>
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -60,6 +60,50 @@ ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
|||||||
u''
|
u''
|
||||||
>>> f.clean('')
|
>>> f.clean('')
|
||||||
u''
|
u''
|
||||||
|
>>> f.clean('W2S 2H3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('T2W 2H7')
|
||||||
|
u'T2W 2H7'
|
||||||
|
>>> f.clean('T2S 2W7')
|
||||||
|
u'T2S 2W7'
|
||||||
|
>>> f.clean('Z2S 2H3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('T2Z 2H7')
|
||||||
|
u'T2Z 2H7'
|
||||||
|
>>> f.clean('T2S 2Z7')
|
||||||
|
u'T2S 2Z7'
|
||||||
|
>>> f.clean('F2S 2H3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('A2S 2D3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('A2I 2R3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('A2I 2R3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('A2Q 2R3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('U2B 2R3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
>>> f.clean('O2B 2R3')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||||
|
|
||||||
# CAPhoneNumberField ##########################################################
|
# CAPhoneNumberField ##########################################################
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from extra import tests as extra_tests
|
from extra import tests as extra_tests
|
||||||
from fields import tests as fields_tests
|
|
||||||
from forms import tests as form_tests
|
from forms import tests as form_tests
|
||||||
from error_messages import tests as custom_error_message_tests
|
from error_messages import tests as custom_error_message_tests
|
||||||
from localflavor.ar import tests as localflavor_ar_tests
|
from localflavor.ar import tests as localflavor_ar_tests
|
||||||
@ -32,9 +31,10 @@ from widgets import tests as widgets_tests
|
|||||||
from formsets import tests as formset_tests
|
from formsets import tests as formset_tests
|
||||||
from media import media_tests
|
from media import media_tests
|
||||||
|
|
||||||
|
from fields import FieldsTests
|
||||||
|
|
||||||
__test__ = {
|
__test__ = {
|
||||||
'extra_tests': extra_tests,
|
'extra_tests': extra_tests,
|
||||||
'fields_tests': fields_tests,
|
|
||||||
'form_tests': form_tests,
|
'form_tests': form_tests,
|
||||||
'custom_error_message_tests': custom_error_message_tests,
|
'custom_error_message_tests': custom_error_message_tests,
|
||||||
'localflavor_ar_tests': localflavor_ar_tests,
|
'localflavor_ar_tests': localflavor_ar_tests,
|
||||||
|
0
tests/regressiontests/localflavor/__init__.py
Normal file
0
tests/regressiontests/localflavor/__init__.py
Normal file
14
tests/regressiontests/localflavor/forms.py
Normal file
14
tests/regressiontests/localflavor/forms.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from django.forms import ModelForm
|
||||||
|
from models import Place
|
||||||
|
|
||||||
|
class PlaceForm(ModelForm):
|
||||||
|
"""docstring for PlaceForm"""
|
||||||
|
class Meta:
|
||||||
|
model = Place
|
||||||
|
from django.forms import ModelForm
|
||||||
|
from models import Place
|
||||||
|
|
||||||
|
class PlaceForm(ModelForm):
|
||||||
|
"""docstring for PlaceForm"""
|
||||||
|
class Meta:
|
||||||
|
model = Place
|
16
tests/regressiontests/localflavor/models.py
Normal file
16
tests/regressiontests/localflavor/models.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.contrib.localflavor.us.models import USStateField
|
||||||
|
|
||||||
|
class Place(models.Model):
|
||||||
|
state = USStateField(blank=True)
|
||||||
|
state_req = USStateField()
|
||||||
|
state_default = USStateField(default="CA", blank=True)
|
||||||
|
name = models.CharField(max_length=20)
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.localflavor.us.models import USStateField
|
||||||
|
|
||||||
|
class Place(models.Model):
|
||||||
|
state = USStateField(blank=True)
|
||||||
|
state_req = USStateField()
|
||||||
|
state_default = USStateField(default="CA", blank=True)
|
||||||
|
name = models.CharField(max_length=20)
|
166
tests/regressiontests/localflavor/tests.py
Normal file
166
tests/regressiontests/localflavor/tests.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
from models import Place
|
||||||
|
from forms import PlaceForm
|
||||||
|
|
||||||
|
class USLocalflavorTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.form = PlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
|
||||||
|
|
||||||
|
def test_get_display_methods(self):
|
||||||
|
"""Test that the get_*_display() methods are added to the model instances."""
|
||||||
|
place = self.form.save()
|
||||||
|
self.assertEqual(place.get_state_display(), 'Georgia')
|
||||||
|
self.assertEqual(place.get_state_req_display(), 'North Carolina')
|
||||||
|
|
||||||
|
def test_required(self):
|
||||||
|
"""Test that required USStateFields throw appropriate errors."""
|
||||||
|
form = PlaceForm({'state':'GA', 'name':'Place in GA'})
|
||||||
|
self.assertFalse(form.is_valid())
|
||||||
|
self.assertEqual(form.errors['state_req'], [u'This field is required.'])
|
||||||
|
|
||||||
|
def test_field_blank_option(self):
|
||||||
|
"""Test that the empty option is there."""
|
||||||
|
state_select_html = """\
|
||||||
|
<select name="state" id="id_state">
|
||||||
|
<option value="">---------</option>
|
||||||
|
<option value="AL">Alabama</option>
|
||||||
|
<option value="AK">Alaska</option>
|
||||||
|
<option value="AS">American Samoa</option>
|
||||||
|
<option value="AZ">Arizona</option>
|
||||||
|
<option value="AR">Arkansas</option>
|
||||||
|
<option value="CA">California</option>
|
||||||
|
<option value="CO">Colorado</option>
|
||||||
|
<option value="CT">Connecticut</option>
|
||||||
|
<option value="DE">Delaware</option>
|
||||||
|
<option value="DC">District of Columbia</option>
|
||||||
|
<option value="FL">Florida</option>
|
||||||
|
<option value="GA" selected="selected">Georgia</option>
|
||||||
|
<option value="GU">Guam</option>
|
||||||
|
<option value="HI">Hawaii</option>
|
||||||
|
<option value="ID">Idaho</option>
|
||||||
|
<option value="IL">Illinois</option>
|
||||||
|
<option value="IN">Indiana</option>
|
||||||
|
<option value="IA">Iowa</option>
|
||||||
|
<option value="KS">Kansas</option>
|
||||||
|
<option value="KY">Kentucky</option>
|
||||||
|
<option value="LA">Louisiana</option>
|
||||||
|
<option value="ME">Maine</option>
|
||||||
|
<option value="MD">Maryland</option>
|
||||||
|
<option value="MA">Massachusetts</option>
|
||||||
|
<option value="MI">Michigan</option>
|
||||||
|
<option value="MN">Minnesota</option>
|
||||||
|
<option value="MS">Mississippi</option>
|
||||||
|
<option value="MO">Missouri</option>
|
||||||
|
<option value="MT">Montana</option>
|
||||||
|
<option value="NE">Nebraska</option>
|
||||||
|
<option value="NV">Nevada</option>
|
||||||
|
<option value="NH">New Hampshire</option>
|
||||||
|
<option value="NJ">New Jersey</option>
|
||||||
|
<option value="NM">New Mexico</option>
|
||||||
|
<option value="NY">New York</option>
|
||||||
|
<option value="NC">North Carolina</option>
|
||||||
|
<option value="ND">North Dakota</option>
|
||||||
|
<option value="MP">Northern Mariana Islands</option>
|
||||||
|
<option value="OH">Ohio</option>
|
||||||
|
<option value="OK">Oklahoma</option>
|
||||||
|
<option value="OR">Oregon</option>
|
||||||
|
<option value="PA">Pennsylvania</option>
|
||||||
|
<option value="PR">Puerto Rico</option>
|
||||||
|
<option value="RI">Rhode Island</option>
|
||||||
|
<option value="SC">South Carolina</option>
|
||||||
|
<option value="SD">South Dakota</option>
|
||||||
|
<option value="TN">Tennessee</option>
|
||||||
|
<option value="TX">Texas</option>
|
||||||
|
<option value="UT">Utah</option>
|
||||||
|
<option value="VT">Vermont</option>
|
||||||
|
<option value="VI">Virgin Islands</option>
|
||||||
|
<option value="VA">Virginia</option>
|
||||||
|
<option value="WA">Washington</option>
|
||||||
|
<option value="WV">West Virginia</option>
|
||||||
|
<option value="WI">Wisconsin</option>
|
||||||
|
<option value="WY">Wyoming</option>
|
||||||
|
</select>"""
|
||||||
|
self.assertEqual(str(self.form['state']), state_select_html)
|
||||||
|
from django.test import TestCase
|
||||||
|
from models import Place
|
||||||
|
from forms import PlaceForm
|
||||||
|
|
||||||
|
class USLocalflavorTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.form = PlaceForm({'state':'GA', 'state_req':'NC', 'name':'impossible'})
|
||||||
|
|
||||||
|
def test_get_display_methods(self):
|
||||||
|
"""Test that the get_*_display() methods are added to the model instances."""
|
||||||
|
place = self.form.save()
|
||||||
|
self.assertEqual(place.get_state_display(), 'Georgia')
|
||||||
|
self.assertEqual(place.get_state_req_display(), 'North Carolina')
|
||||||
|
|
||||||
|
def test_required(self):
|
||||||
|
"""Test that required USStateFields throw appropriate errors."""
|
||||||
|
form = PlaceForm({'state':'GA', 'name':'Place in GA'})
|
||||||
|
self.assertFalse(form.is_valid())
|
||||||
|
self.assertEqual(form.errors['state_req'], [u'This field is required.'])
|
||||||
|
|
||||||
|
def test_field_blank_option(self):
|
||||||
|
"""Test that the empty option is there."""
|
||||||
|
state_select_html = """\
|
||||||
|
<select name="state" id="id_state">
|
||||||
|
<option value="">---------</option>
|
||||||
|
<option value="AL">Alabama</option>
|
||||||
|
<option value="AK">Alaska</option>
|
||||||
|
<option value="AS">American Samoa</option>
|
||||||
|
<option value="AZ">Arizona</option>
|
||||||
|
<option value="AR">Arkansas</option>
|
||||||
|
<option value="CA">California</option>
|
||||||
|
<option value="CO">Colorado</option>
|
||||||
|
<option value="CT">Connecticut</option>
|
||||||
|
<option value="DE">Delaware</option>
|
||||||
|
<option value="DC">District of Columbia</option>
|
||||||
|
<option value="FL">Florida</option>
|
||||||
|
<option value="GA" selected="selected">Georgia</option>
|
||||||
|
<option value="GU">Guam</option>
|
||||||
|
<option value="HI">Hawaii</option>
|
||||||
|
<option value="ID">Idaho</option>
|
||||||
|
<option value="IL">Illinois</option>
|
||||||
|
<option value="IN">Indiana</option>
|
||||||
|
<option value="IA">Iowa</option>
|
||||||
|
<option value="KS">Kansas</option>
|
||||||
|
<option value="KY">Kentucky</option>
|
||||||
|
<option value="LA">Louisiana</option>
|
||||||
|
<option value="ME">Maine</option>
|
||||||
|
<option value="MD">Maryland</option>
|
||||||
|
<option value="MA">Massachusetts</option>
|
||||||
|
<option value="MI">Michigan</option>
|
||||||
|
<option value="MN">Minnesota</option>
|
||||||
|
<option value="MS">Mississippi</option>
|
||||||
|
<option value="MO">Missouri</option>
|
||||||
|
<option value="MT">Montana</option>
|
||||||
|
<option value="NE">Nebraska</option>
|
||||||
|
<option value="NV">Nevada</option>
|
||||||
|
<option value="NH">New Hampshire</option>
|
||||||
|
<option value="NJ">New Jersey</option>
|
||||||
|
<option value="NM">New Mexico</option>
|
||||||
|
<option value="NY">New York</option>
|
||||||
|
<option value="NC">North Carolina</option>
|
||||||
|
<option value="ND">North Dakota</option>
|
||||||
|
<option value="MP">Northern Mariana Islands</option>
|
||||||
|
<option value="OH">Ohio</option>
|
||||||
|
<option value="OK">Oklahoma</option>
|
||||||
|
<option value="OR">Oregon</option>
|
||||||
|
<option value="PA">Pennsylvania</option>
|
||||||
|
<option value="PR">Puerto Rico</option>
|
||||||
|
<option value="RI">Rhode Island</option>
|
||||||
|
<option value="SC">South Carolina</option>
|
||||||
|
<option value="SD">South Dakota</option>
|
||||||
|
<option value="TN">Tennessee</option>
|
||||||
|
<option value="TX">Texas</option>
|
||||||
|
<option value="UT">Utah</option>
|
||||||
|
<option value="VT">Vermont</option>
|
||||||
|
<option value="VI">Virgin Islands</option>
|
||||||
|
<option value="VA">Virginia</option>
|
||||||
|
<option value="WA">Washington</option>
|
||||||
|
<option value="WV">West Virginia</option>
|
||||||
|
<option value="WI">Wisconsin</option>
|
||||||
|
<option value="WY">Wyoming</option>
|
||||||
|
</select>"""
|
||||||
|
self.assertEqual(str(self.form['state']), state_select_html)
|
@ -100,4 +100,16 @@ class CustomFieldSaveTests(TestCase):
|
|||||||
# It's enough that the form saves without error -- the custom save routine will
|
# It's enough that the form saves without error -- the custom save routine will
|
||||||
# generate an AssertionError if it is called more than once during save.
|
# generate an AssertionError if it is called more than once during save.
|
||||||
form = CFFForm(data = {'f': None})
|
form = CFFForm(data = {'f': None})
|
||||||
form.save()
|
form.save()
|
||||||
|
|
||||||
|
class ModelChoiceIteratorTests(TestCase):
|
||||||
|
def test_len(self):
|
||||||
|
class Form(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Article
|
||||||
|
fields = ["publications"]
|
||||||
|
|
||||||
|
Publication.objects.create(title="Pravda",
|
||||||
|
date_published=date(1991, 8, 22))
|
||||||
|
f = Form()
|
||||||
|
self.assertEqual(len(f.fields["publications"].choices), 1)
|
||||||
|
0
tests/regressiontests/settings_tests/__init__.py
Normal file
0
tests/regressiontests/settings_tests/__init__.py
Normal file
0
tests/regressiontests/settings_tests/models.py
Normal file
0
tests/regressiontests/settings_tests/models.py
Normal file
17
tests/regressiontests/settings_tests/tests.py
Normal file
17
tests/regressiontests/settings_tests/tests.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import unittest
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
class SettingsTests(unittest.TestCase):
|
||||||
|
|
||||||
|
#
|
||||||
|
# Regression tests for #10130: deleting settings.
|
||||||
|
#
|
||||||
|
|
||||||
|
def test_settings_delete(self):
|
||||||
|
settings.TEST = 'test'
|
||||||
|
self.assertEqual('test', settings.TEST)
|
||||||
|
del settings.TEST
|
||||||
|
self.assertRaises(AttributeError, getattr, settings, 'TEST')
|
||||||
|
|
||||||
|
def test_settings_delete_wrapped(self):
|
||||||
|
self.assertRaises(TypeError, delattr, settings, '_wrapped')
|
@ -120,13 +120,19 @@ def get_filter_tests():
|
|||||||
|
|
||||||
# Notice that escaping is applied *after* any filters, so the string
|
# Notice that escaping is applied *after* any filters, so the string
|
||||||
# formatting here only needs to deal with pre-escaped characters.
|
# formatting here only needs to deal with pre-escaped characters.
|
||||||
'filter-stringformat01': ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}', {"a": "a<b", "b": mark_safe("a<b")}, u". a<b. . a<b."),
|
'filter-stringformat01': ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
|
||||||
'filter-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")}, u". a<b. . a<b."),
|
{"a": "a<b", "b": mark_safe("a<b")}, u". a<b. . a<b."),
|
||||||
|
'filter-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")},
|
||||||
|
u". a<b. . a<b."),
|
||||||
|
|
||||||
# XXX No test for "title" filter; needs an actual object.
|
# Test the title filter
|
||||||
|
'filter-title1' : ('{{ a|title }}', {'a' : 'JOE\'S CRAB SHACK'}, u'Joe's Crab Shack'),
|
||||||
|
'filter-title2' : ('{{ a|title }}', {'a' : '555 WEST 53RD STREET'}, u'555 West 53rd Street'),
|
||||||
|
|
||||||
'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}', {"a": "alpha & bravo", "b": mark_safe("alpha & bravo")}, u"alpha & ... alpha & ..."),
|
'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
|
||||||
'filter-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}', {"a": "alpha & bravo", "b": mark_safe("alpha & bravo")}, u"alpha & ... alpha & ..."),
|
{"a": "alpha & bravo", "b": mark_safe("alpha & bravo")}, u"alpha & ... alpha & ..."),
|
||||||
|
'filter-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}',
|
||||||
|
{"a": "alpha & bravo", "b": mark_safe("alpha & bravo")}, u"alpha & ... alpha & ..."),
|
||||||
|
|
||||||
# The "upper" filter messes up entities (which are case-sensitive),
|
# The "upper" filter messes up entities (which are case-sensitive),
|
||||||
# so it's not safe for non-escaping purposes.
|
# so it's not safe for non-escaping purposes.
|
||||||
|
0
tests/regressiontests/test_runner/__init__.py
Normal file
0
tests/regressiontests/test_runner/__init__.py
Normal file
0
tests/regressiontests/test_runner/models.py
Normal file
0
tests/regressiontests/test_runner/models.py
Normal file
29
tests/regressiontests/test_runner/tests.py
Normal file
29
tests/regressiontests/test_runner/tests.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
Tests for django test runner
|
||||||
|
"""
|
||||||
|
import StringIO
|
||||||
|
import unittest
|
||||||
|
import django
|
||||||
|
from django.test import TestCase, TransactionTestCase, simple
|
||||||
|
|
||||||
|
class DjangoTestRunnerTests(TestCase):
|
||||||
|
|
||||||
|
def test_failfast(self):
|
||||||
|
class MockTestOne(TransactionTestCase):
|
||||||
|
def runTest(self):
|
||||||
|
assert False
|
||||||
|
class MockTestTwo(TransactionTestCase):
|
||||||
|
def runTest(self):
|
||||||
|
assert False
|
||||||
|
|
||||||
|
suite = unittest.TestSuite([MockTestOne(), MockTestTwo()])
|
||||||
|
mock_stream = StringIO.StringIO()
|
||||||
|
dtr = simple.DjangoTestRunner(verbosity=0, failfast=False, stream=mock_stream)
|
||||||
|
result = dtr.run(suite)
|
||||||
|
self.assertEqual(2, result.testsRun)
|
||||||
|
self.assertEqual(2, len(result.failures))
|
||||||
|
|
||||||
|
dtr = simple.DjangoTestRunner(verbosity=0, failfast=True, stream=mock_stream)
|
||||||
|
result = dtr.run(suite)
|
||||||
|
self.assertEqual(1, result.testsRun)
|
||||||
|
self.assertEqual(1, len(result.failures))
|
@ -244,7 +244,6 @@ class NamespaceTests(TestCase):
|
|||||||
self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1'))
|
self.assertEquals('/other1/inner/37/42/', reverse('nodefault:urlobject-view', args=[37,42], current_app='other-ns1'))
|
||||||
self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
|
self.assertEquals('/other1/inner/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
|
||||||
|
|
||||||
|
|
||||||
class RequestURLconfTests(TestCase):
|
class RequestURLconfTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.root_urlconf = settings.ROOT_URLCONF
|
self.root_urlconf = settings.ROOT_URLCONF
|
||||||
@ -276,3 +275,25 @@ class RequestURLconfTests(TestCase):
|
|||||||
response = self.client.get('/second_test/')
|
response = self.client.get('/second_test/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.content, 'outer:,inner:/second_test/')
|
self.assertEqual(response.content, 'outer:,inner:/second_test/')
|
||||||
|
|
||||||
|
class ErrorHandlerResolutionTests(TestCase):
|
||||||
|
"""Tests for handler404 and handler500"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
from django.core.urlresolvers import RegexURLResolver
|
||||||
|
urlconf = 'regressiontests.urlpatterns_reverse.urls_error_handlers'
|
||||||
|
urlconf_callables = 'regressiontests.urlpatterns_reverse.urls_error_handlers_callables'
|
||||||
|
self.resolver = RegexURLResolver(r'^$', urlconf)
|
||||||
|
self.callable_resolver = RegexURLResolver(r'^$', urlconf_callables)
|
||||||
|
|
||||||
|
def test_named_handlers(self):
|
||||||
|
from views import empty_view
|
||||||
|
handler = (empty_view, {})
|
||||||
|
self.assertEqual(self.resolver.resolve404(), handler)
|
||||||
|
self.assertEqual(self.resolver.resolve500(), handler)
|
||||||
|
|
||||||
|
def test_callable_handers(self):
|
||||||
|
from views import empty_view
|
||||||
|
handler = (empty_view, {})
|
||||||
|
self.assertEqual(self.callable_resolver.resolve404(), handler)
|
||||||
|
self.assertEqual(self.callable_resolver.resolve500(), handler)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
# Used by the ErrorHandlerResolutionTests test case.
|
||||||
|
|
||||||
|
from django.conf.urls.defaults import patterns
|
||||||
|
|
||||||
|
urlpatterns = patterns('')
|
||||||
|
|
||||||
|
handler404 = 'regressiontests.urlpatterns_reverse.views.empty_view'
|
||||||
|
handler500 = 'regressiontests.urlpatterns_reverse.views.empty_view'
|
@ -0,0 +1,9 @@
|
|||||||
|
# Used by the ErrorHandlerResolutionTests test case.
|
||||||
|
|
||||||
|
from django.conf.urls.defaults import patterns
|
||||||
|
from views import empty_view
|
||||||
|
|
||||||
|
urlpatterns = patterns('')
|
||||||
|
|
||||||
|
handler404 = empty_view
|
||||||
|
handler500 = empty_view
|
@ -86,7 +86,7 @@ class InvalidModelTestCase(unittest.TestCase):
|
|||||||
self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
|
self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected))
|
||||||
self.assert_(not missing, "Missing Errors: " + '\n'.join(missing))
|
self.assert_(not missing, "Missing Errors: " + '\n'.join(missing))
|
||||||
|
|
||||||
def django_tests(verbosity, interactive, test_labels):
|
def django_tests(verbosity, interactive, failfast, test_labels):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
old_installed_apps = settings.INSTALLED_APPS
|
old_installed_apps = settings.INSTALLED_APPS
|
||||||
@ -159,7 +159,8 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
settings.TEST_RUNNER = 'django.test.simple.run_tests'
|
settings.TEST_RUNNER = 'django.test.simple.run_tests'
|
||||||
test_runner = get_runner(settings)
|
test_runner = get_runner(settings)
|
||||||
|
|
||||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests)
|
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, failfast=failfast,
|
||||||
|
extra_tests=extra_tests)
|
||||||
if failures:
|
if failures:
|
||||||
sys.exit(failures)
|
sys.exit(failures)
|
||||||
|
|
||||||
@ -181,6 +182,8 @@ if __name__ == "__main__":
|
|||||||
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
|
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
|
||||||
parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
|
parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
|
||||||
help='Tells Django to NOT prompt the user for input of any kind.')
|
help='Tells Django to NOT prompt the user for input of any kind.')
|
||||||
|
parser.add_option('--failfast', action='store_true', dest='failfast', default=False,
|
||||||
|
help='Tells Django to stop running the test suite after first failed test.')
|
||||||
parser.add_option('--settings',
|
parser.add_option('--settings',
|
||||||
help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
|
help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
@ -189,4 +192,4 @@ if __name__ == "__main__":
|
|||||||
elif "DJANGO_SETTINGS_MODULE" not in os.environ:
|
elif "DJANGO_SETTINGS_MODULE" not in os.environ:
|
||||||
parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. "
|
parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. "
|
||||||
"Set it or use --settings.")
|
"Set it or use --settings.")
|
||||||
django_tests(int(options.verbosity), options.interactive, args)
|
django_tests(int(options.verbosity), options.interactive, options.failfast, args)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user