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>
|
||||
Morten Bagai <m@bagai.com>
|
||||
Mikaël Barbero <mikael.barbero nospam at nospam free.fr>
|
||||
Randy Barlow <randy@electronsweatshop.com>
|
||||
Scott Barr <scott@divisionbyzero.com.au>
|
||||
Jiri Barton
|
||||
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>
|
||||
dusk@woofle.net
|
||||
Andy Dustman <farcepest@gmail.com>
|
||||
J. Clifford Dyer <jcd@unc.edu>
|
||||
J. Clifford Dyer <jcd@sdf.lonestar.org>
|
||||
Clint Ecker
|
||||
Nick Efford <nick@efford.org>
|
||||
eibaan@gmail.com
|
||||
@ -172,6 +173,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Alex Gaynor <alex.gaynor@gmail.com>
|
||||
Andy Gayton <andy-django@thecablelounge.com>
|
||||
Idan Gazit
|
||||
geber@datacollect.com
|
||||
Baishampayan Ghose
|
||||
Dimitris Glezos <dimitris@glezos.com>
|
||||
glin@seznam.cz
|
||||
@ -267,6 +269,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Finn Gruwier Larsen <finn@gruwier.dk>
|
||||
Lau Bech Lauritzen
|
||||
Rune Rønde Laursen <runerl@skjoldhoej.dk>
|
||||
Mark Lavin <markdlavin@gmail.com>
|
||||
Eugene Lazutkin <http://lazutkin.com/blog/>
|
||||
lcordier@point45.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/>
|
||||
Kevin McConnell <kevin.mcconnell@gmail.com>
|
||||
mccutchen@gmail.com
|
||||
Paul McLanahan <paul@mclanahan.net>
|
||||
Tobias McNulty <http://www.caktusgroup.com/blog>
|
||||
Christian Metts
|
||||
michael.mcewan@gmail.com
|
||||
@ -382,6 +386,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Massimo Scamarcia <massimo.scamarcia@gmail.com>
|
||||
David Schein
|
||||
Bernd Schlapsi
|
||||
schwank@gmail.com
|
||||
scott@staplefish.com
|
||||
Ilya Semenov <semenov@inetss.com>
|
||||
serbaut@gmail.com
|
||||
@ -393,6 +398,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||
Ben Slavin <benjamin.slavin@gmail.com>
|
||||
sloonz <simon.lipp@insa-lyon.fr>
|
||||
Paul Smith <blinkylights23@gmail.com>
|
||||
Warren Smith <warren@wandrsmith.net>
|
||||
smurf@smurf.noris.de
|
||||
Vsevolod Solovyov
|
||||
|
2
README
2
README
@ -27,7 +27,7 @@ http://code.djangoproject.com/newticket
|
||||
To get more help:
|
||||
|
||||
* 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
|
||||
http://groups.google.com/group/django-users.
|
||||
|
@ -692,6 +692,9 @@ class ModelAdmin(BaseModelAdmin):
|
||||
# perform an action on it, so bail.
|
||||
selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
|
||||
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
|
||||
|
||||
response = func(self, request, queryset.filter(pk__in=selected))
|
||||
@ -703,6 +706,9 @@ class ModelAdmin(BaseModelAdmin):
|
||||
return response
|
||||
else:
|
||||
return HttpResponseRedirect(".")
|
||||
else:
|
||||
msg = "No action selected."
|
||||
self.message_user(request, _(msg))
|
||||
|
||||
@csrf_protect
|
||||
@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 ''
|
||||
|
||||
# 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):
|
||||
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=''):
|
||||
"""
|
||||
|
@ -40,8 +40,8 @@ def get_srid_info(srid, connection):
|
||||
|
||||
return _srid_cache[name][srid]
|
||||
|
||||
class GeometryField(Field):
|
||||
"The base GIS field -- maps to the OpenGIS Specification Geometry type."
|
||||
class GeometryField(SpatialBackend.Field):
|
||||
"""The base GIS field -- maps to the OpenGIS Specification Geometry type."""
|
||||
|
||||
# The OpenGIS Geometry name.
|
||||
geom_type = 'GEOMETRY'
|
||||
@ -285,22 +285,29 @@ class GeometryField(Field):
|
||||
|
||||
# The OpenGIS Geometry Type Fields
|
||||
class PointField(GeometryField):
|
||||
"""Point"""
|
||||
geom_type = 'POINT'
|
||||
|
||||
class LineStringField(GeometryField):
|
||||
"""Line string"""
|
||||
geom_type = 'LINESTRING'
|
||||
|
||||
class PolygonField(GeometryField):
|
||||
"""Polygon"""
|
||||
geom_type = 'POLYGON'
|
||||
|
||||
class MultiPointField(GeometryField):
|
||||
"""Multi-point"""
|
||||
geom_type = 'MULTIPOINT'
|
||||
|
||||
class MultiLineStringField(GeometryField):
|
||||
"""Multi-line string"""
|
||||
geom_type = 'MULTILINESTRING'
|
||||
|
||||
class MultiPolygonField(GeometryField):
|
||||
"""Multi polygon"""
|
||||
geom_type = 'MULTIPOLYGON'
|
||||
|
||||
class GeometryCollectionField(GeometryField):
|
||||
"""Geometry collection"""
|
||||
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})$")
|
||||
|
||||
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 = {
|
||||
'invalid': _(u'Enter a postal code in the format XXX XXX.'),
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
from django.contrib.localflavor.us.us_states import STATE_CHOICES
|
||||
|
||||
class USStateField(Field):
|
||||
def get_internal_type(self):
|
||||
return "USStateField"
|
||||
|
||||
def db_type(self, connection):
|
||||
if connection.settings_dict['ENGINE'] == 'django.db.backends.oracle':
|
||||
return 'CHAR(2)'
|
||||
else:
|
||||
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 USStateField(CharField):
|
||||
"""U.S. state (two uppercase letters)"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['choices'] = STATE_CHOICES
|
||||
kwargs['max_length'] = 2
|
||||
super(USStateField, self).__init__(*args, **kwargs)
|
||||
|
||||
class PhoneNumberField(Field):
|
||||
"""Phone number"""
|
||||
def get_internal_type(self):
|
||||
return "PhoneNumberField"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import hmac
|
||||
|
||||
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.storage.base import BaseStorage, Message
|
||||
from django.utils import simplejson as json
|
||||
@ -41,7 +41,6 @@ class MessageDecoder(json.JSONDecoder):
|
||||
decoded = super(MessageDecoder, self).decode(s, **kwargs)
|
||||
return self.process_messages(decoded)
|
||||
|
||||
|
||||
class CookieStorage(BaseStorage):
|
||||
"""
|
||||
Stores messages in a cookie.
|
||||
@ -103,7 +102,7 @@ class CookieStorage(BaseStorage):
|
||||
SECRET_KEY, modified to make it unique for the present purpose.
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
|
@ -218,9 +218,9 @@ class BaseTest(TestCase):
|
||||
response = self.client.post(add_url, data, follow=True)
|
||||
self.assertRedirects(response, show_url)
|
||||
self.assertTrue('messages' in response.context)
|
||||
self.assertEqual(list(response.context['messages']),
|
||||
data['messages'])
|
||||
context_messages = list(response.context['messages'])
|
||||
for msg in data['messages']:
|
||||
self.assertTrue(msg in context_messages)
|
||||
self.assertContains(response, msg)
|
||||
|
||||
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()
|
||||
|
||||
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):
|
||||
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 + (
|
||||
make_option('--noinput', action='store_false', dest='interactive', default=True,
|
||||
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.'
|
||||
args = '[appname ...]'
|
||||
@ -18,8 +20,15 @@ class Command(BaseCommand):
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
interactive = options.get('interactive', True)
|
||||
failfast = options.get('failfast', False)
|
||||
test_runner = get_runner(settings)
|
||||
|
||||
# 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:
|
||||
sys.exit(failures)
|
||||
|
@ -257,9 +257,8 @@ class RegexURLResolver(object):
|
||||
|
||||
def _resolve_special(self, view_type):
|
||||
callback = getattr(self.urlconf_module, 'handler%s' % view_type)
|
||||
mod_name, func_name = get_mod_func(callback)
|
||||
try:
|
||||
return getattr(import_module(mod_name), func_name), {}
|
||||
return get_callable(callback), {}
|
||||
except (ImportError, AttributeError), e:
|
||||
raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
|
||||
|
||||
|
@ -3,10 +3,6 @@ import datetime
|
||||
import os
|
||||
import re
|
||||
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.models import signals
|
||||
@ -50,7 +46,9 @@ class FieldDoesNotExist(Exception):
|
||||
# getattr(obj, opts.pk.attname)
|
||||
|
||||
class Field(object):
|
||||
"""Base class for all field types"""
|
||||
__metaclass__ = LegacyConnection
|
||||
|
||||
# Designates whether empty strings fundamentally are allowed at the
|
||||
# database level.
|
||||
empty_strings_allowed = True
|
||||
@ -370,7 +368,10 @@ class Field(object):
|
||||
return getattr(obj, self.attname)
|
||||
|
||||
class AutoField(Field):
|
||||
"""Integer"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
|
||||
kwargs['blank'] = True
|
||||
@ -400,7 +401,10 @@ class AutoField(Field):
|
||||
return None
|
||||
|
||||
class BooleanField(Field):
|
||||
"""Boolean (Either True or False)"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['blank'] = True
|
||||
if 'default' not in kwargs and not kwargs.get('null'):
|
||||
@ -443,6 +447,8 @@ class BooleanField(Field):
|
||||
return super(BooleanField, self).formfield(**defaults)
|
||||
|
||||
class CharField(Field):
|
||||
"""String (up to %(max_length)s)"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
@ -464,6 +470,8 @@ class CharField(Field):
|
||||
|
||||
# TODO: Maybe move this into contrib, because it's specialized.
|
||||
class CommaSeparatedIntegerField(CharField):
|
||||
"""Comma-separated integers"""
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'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}$')
|
||||
|
||||
class DateField(Field):
|
||||
"""Date (without time)"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
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
|
||||
#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)
|
||||
|
||||
class DateTimeField(DateField):
|
||||
"""Date (with time)"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "DateTimeField"
|
||||
|
||||
@ -623,7 +636,10 @@ class DateTimeField(DateField):
|
||||
return super(DateTimeField, self).formfield(**defaults)
|
||||
|
||||
class DecimalField(Field):
|
||||
"""Decimal number"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
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
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
@ -677,6 +693,8 @@ class DecimalField(Field):
|
||||
return super(DecimalField, self).formfield(**defaults)
|
||||
|
||||
class EmailField(CharField):
|
||||
"""E-mail address"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||
CharField.__init__(self, *args, **kwargs)
|
||||
@ -687,6 +705,8 @@ class EmailField(CharField):
|
||||
return super(EmailField, self).formfield(**defaults)
|
||||
|
||||
class FilePathField(Field):
|
||||
"""File path"""
|
||||
|
||||
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
||||
self.path, self.match, self.recursive = path, match, recursive
|
||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||
@ -706,6 +726,8 @@ class FilePathField(Field):
|
||||
return "FilePathField"
|
||||
|
||||
class FloatField(Field):
|
||||
"""Floating point number"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
def get_prep_value(self, value):
|
||||
@ -731,8 +753,15 @@ class FloatField(Field):
|
||||
return super(FloatField, self).formfield(**defaults)
|
||||
|
||||
class IntegerField(Field):
|
||||
"""Integer"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
<<<<<<< HEAD:django/db/models/fields/__init__.py
|
||||
def get_prep_value(self, value):
|
||||
=======
|
||||
|
||||
def get_db_prep_value(self, value):
|
||||
>>>>>>> master:django/db/models/fields/__init__.py
|
||||
if value is None:
|
||||
return None
|
||||
return int(value)
|
||||
@ -755,7 +784,10 @@ class IntegerField(Field):
|
||||
return super(IntegerField, self).formfield(**defaults)
|
||||
|
||||
class IPAddressField(Field):
|
||||
"""IP address"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = 15
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
@ -769,7 +801,10 @@ class IPAddressField(Field):
|
||||
return super(IPAddressField, self).formfield(**defaults)
|
||||
|
||||
class NullBooleanField(Field):
|
||||
"""Boolean (Either True, False or None)"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['null'] = True
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
@ -809,6 +844,8 @@ class NullBooleanField(Field):
|
||||
return super(NullBooleanField, self).formfield(**defaults)
|
||||
|
||||
class PositiveIntegerField(IntegerField):
|
||||
"""Integer"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PositiveIntegerField"
|
||||
|
||||
@ -818,6 +855,8 @@ class PositiveIntegerField(IntegerField):
|
||||
return super(PositiveIntegerField, self).formfield(**defaults)
|
||||
|
||||
class PositiveSmallIntegerField(IntegerField):
|
||||
"""Integer"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "PositiveSmallIntegerField"
|
||||
|
||||
@ -827,6 +866,8 @@ class PositiveSmallIntegerField(IntegerField):
|
||||
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
||||
|
||||
class SlugField(CharField):
|
||||
"""String (up to %(max_length)s)"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 50)
|
||||
# Set db_index=True unless it's been set manually.
|
||||
@ -843,10 +884,14 @@ class SlugField(CharField):
|
||||
return super(SlugField, self).formfield(**defaults)
|
||||
|
||||
class SmallIntegerField(IntegerField):
|
||||
"""Integer"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "SmallIntegerField"
|
||||
|
||||
class TextField(Field):
|
||||
"""Text"""
|
||||
|
||||
def get_internal_type(self):
|
||||
return "TextField"
|
||||
|
||||
@ -856,7 +901,10 @@ class TextField(Field):
|
||||
return super(TextField, self).formfield(**defaults)
|
||||
|
||||
class TimeField(Field):
|
||||
"""Time"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
|
||||
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
|
||||
if auto_now or auto_now_add:
|
||||
@ -933,6 +981,8 @@ class TimeField(Field):
|
||||
return super(TimeField, self).formfield(**defaults)
|
||||
|
||||
class URLField(CharField):
|
||||
"""URL"""
|
||||
|
||||
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 200)
|
||||
self.verify_exists = verify_exists
|
||||
@ -944,6 +994,8 @@ class URLField(CharField):
|
||||
return super(URLField, self).formfield(**defaults)
|
||||
|
||||
class XMLField(TextField):
|
||||
"""XML text"""
|
||||
|
||||
def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
|
||||
self.schema_path = schema_path
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
@ -209,6 +209,8 @@ class FileDescriptor(object):
|
||||
instance.__dict__[self.field.name] = value
|
||||
|
||||
class FileField(Field):
|
||||
"""File path"""
|
||||
|
||||
# The class to wrap instance attributes in. Accessing the file object off
|
||||
# the instance will always return an instance of attr_class.
|
||||
attr_class = FieldFile
|
||||
@ -323,6 +325,8 @@ class ImageFieldFile(ImageFile, FieldFile):
|
||||
super(ImageFieldFile, self).delete(save)
|
||||
|
||||
class ImageField(FileField):
|
||||
"""File path"""
|
||||
|
||||
attr_class = ImageFieldFile
|
||||
descriptor_class = ImageFileDescriptor
|
||||
|
||||
|
@ -708,6 +708,8 @@ class ManyToManyRel(object):
|
||||
return self.to._meta.pk
|
||||
|
||||
class ForeignKey(RelatedField, Field):
|
||||
"""Foreign Key (type determined by related field)"""
|
||||
|
||||
empty_strings_allowed = False
|
||||
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
||||
try:
|
||||
@ -806,12 +808,13 @@ class ForeignKey(RelatedField, Field):
|
||||
return rel_field.db_type(connection=connection)
|
||||
|
||||
class OneToOneField(ForeignKey):
|
||||
"""
|
||||
"""One-to-one relationship
|
||||
|
||||
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
||||
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),
|
||||
rather than returning a list.
|
||||
"""
|
||||
rather than returning a list."""
|
||||
|
||||
def __init__(self, to, to_field=None, **kwargs):
|
||||
kwargs['unique'] = True
|
||||
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):
|
||||
"""Many-to-many relationship"""
|
||||
|
||||
def __init__(self, to, **kwargs):
|
||||
try:
|
||||
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()."
|
||||
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
|
||||
output, hidden_fields = [], []
|
||||
html_class_attr = ''
|
||||
|
||||
for name, field in self.fields.items():
|
||||
bf = BoundField(self, field, name)
|
||||
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])
|
||||
hidden_fields.append(unicode(bf))
|
||||
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:
|
||||
output.append(error_row % force_unicode(bf_errors))
|
||||
|
||||
if bf.label:
|
||||
label = conditional_escape(force_unicode(bf.label))
|
||||
# Only add the suffix if the label does not end in
|
||||
@ -158,13 +167,23 @@ class BaseForm(StrAndUnicode):
|
||||
label = bf.label_tag(label) or ''
|
||||
else:
|
||||
label = ''
|
||||
|
||||
if field.help_text:
|
||||
help_text = help_text_html % force_unicode(field.help_text)
|
||||
else:
|
||||
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:
|
||||
output.insert(0, error_row % force_unicode(top_errors))
|
||||
|
||||
if hidden_fields: # Insert any hidden fields in the last row.
|
||||
str_hidden = u''.join(hidden_fields)
|
||||
if output:
|
||||
@ -176,7 +195,9 @@ class BaseForm(StrAndUnicode):
|
||||
# that users write): if there are only top errors, we may
|
||||
# not be able to conscript the last row for our purposes,
|
||||
# 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[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
|
||||
else:
|
||||
@ -187,15 +208,30 @@ class BaseForm(StrAndUnicode):
|
||||
|
||||
def as_table(self):
|
||||
"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):
|
||||
"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):
|
||||
"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):
|
||||
"""
|
||||
@ -343,6 +379,7 @@ class BoundField(StrAndUnicode):
|
||||
self.name = name
|
||||
self.html_name = form.add_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:
|
||||
self.label = pretty_name(name)
|
||||
else:
|
||||
@ -374,7 +411,10 @@ class BoundField(StrAndUnicode):
|
||||
attrs = attrs or {}
|
||||
auto_id = self.auto_id
|
||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
||||
if not only_initial:
|
||||
attrs['id'] = auto_id
|
||||
else:
|
||||
attrs['id'] = self.html_initial_id
|
||||
if not self.form.is_bound:
|
||||
data = self.form.initial.get(self.name, self.field.initial)
|
||||
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))
|
||||
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):
|
||||
"Returns True if this BoundField's widget is hidden."
|
||||
return self.field.widget.is_hidden
|
||||
|
@ -912,6 +912,9 @@ class ModelChoiceIterator(object):
|
||||
for obj in self.queryset.all():
|
||||
yield self.choice(obj)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.queryset)
|
||||
|
||||
def choice(self, obj):
|
||||
if self.field.to_field_name:
|
||||
key = obj.serializable_value(self.field.to_field_name)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import os
|
||||
import re
|
||||
from Cookie import SimpleCookie, CookieError
|
||||
from Cookie import BaseCookie, SimpleCookie, CookieError
|
||||
from pprint import pformat
|
||||
from urllib import urlencode
|
||||
from urlparse import urljoin
|
||||
@ -251,13 +251,15 @@ class QueryDict(MultiValueDict):
|
||||
def parse_cookie(cookie):
|
||||
if cookie == '':
|
||||
return {}
|
||||
if not isinstance(cookie, BaseCookie):
|
||||
try:
|
||||
c = SimpleCookie()
|
||||
c.load(cookie)
|
||||
except CookieError:
|
||||
# Invalid cookie
|
||||
return {}
|
||||
|
||||
else:
|
||||
c = cookie
|
||||
cookiedict = {}
|
||||
for key in c.keys():
|
||||
cookiedict[key] = c.get(key).value
|
||||
|
@ -249,7 +249,8 @@ stringformat.is_safe = True
|
||||
|
||||
def title(value):
|
||||
"""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 = stringfilter(title)
|
||||
|
||||
|
@ -10,6 +10,26 @@ TEST_MODULE = 'tests'
|
||||
|
||||
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):
|
||||
try:
|
||||
app_path = app_module.__name__.split('.')[:-1]
|
||||
@ -146,7 +166,7 @@ def reorder_suite(suite, classes):
|
||||
bins[0].addTests(bins[i+1])
|
||||
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.
|
||||
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,))
|
||||
|
||||
old_names = []
|
||||
from django.db import connections
|
||||
old_names = []
|
||||
for alias in connections:
|
||||
connection = connections[alias]
|
||||
old_names.append((connection, connection.settings_dict['NAME']))
|
||||
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:
|
||||
connection.creation.destroy_test_db(old_name, verbosity)
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
class MergeDict(object):
|
||||
"""
|
||||
A simple class for creating new "virtual" dictionaries that actually look
|
||||
@ -72,22 +75,20 @@ class SortedDict(dict):
|
||||
self.keyOrder.append(key)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
from copy import deepcopy
|
||||
return self.__class__([(key, deepcopy(value, memo))
|
||||
for key, value in self.iteritems()])
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
super(SortedDict, self).__setitem__(key, value)
|
||||
if key not in self.keyOrder:
|
||||
if key not in self:
|
||||
self.keyOrder.append(key)
|
||||
super(SortedDict, self).__setitem__(key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
super(SortedDict, self).__delitem__(key)
|
||||
self.keyOrder.remove(key)
|
||||
|
||||
def __iter__(self):
|
||||
for k in self.keyOrder:
|
||||
yield k
|
||||
return iter(self.keyOrder)
|
||||
|
||||
def pop(self, k, *args):
|
||||
result = super(SortedDict, self).pop(k, *args)
|
||||
@ -108,7 +109,7 @@ class SortedDict(dict):
|
||||
|
||||
def iteritems(self):
|
||||
for key in self.keyOrder:
|
||||
yield key, super(SortedDict, self).__getitem__(key)
|
||||
yield key, self[key]
|
||||
|
||||
def keys(self):
|
||||
return self.keyOrder[:]
|
||||
@ -117,18 +118,18 @@ class SortedDict(dict):
|
||||
return iter(self.keyOrder)
|
||||
|
||||
def values(self):
|
||||
return map(super(SortedDict, self).__getitem__, self.keyOrder)
|
||||
return map(self.__getitem__, self.keyOrder)
|
||||
|
||||
def itervalues(self):
|
||||
for key in self.keyOrder:
|
||||
yield super(SortedDict, self).__getitem__(key)
|
||||
yield self[key]
|
||||
|
||||
def update(self, dict_):
|
||||
for k, v in dict_.items():
|
||||
self.__setitem__(k, v)
|
||||
for k, v in dict_.iteritems():
|
||||
self[k] = v
|
||||
|
||||
def setdefault(self, key, default):
|
||||
if key not in self.keyOrder:
|
||||
if key not in self:
|
||||
self.keyOrder.append(key)
|
||||
return super(SortedDict, self).setdefault(key, default)
|
||||
|
||||
|
@ -277,6 +277,13 @@ class LazyObject(object):
|
||||
self._setup()
|
||||
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):
|
||||
"""
|
||||
Must be implemented by subclasses to initialise the wrapped object.
|
||||
|
@ -8,9 +8,13 @@ available.
|
||||
try:
|
||||
import hashlib
|
||||
md5_constructor = hashlib.md5
|
||||
md5_hmac = md5_constructor
|
||||
sha_constructor = hashlib.sha1
|
||||
sha_hmac = sha_constructor
|
||||
except ImportError:
|
||||
import md5
|
||||
md5_constructor = md5.new
|
||||
md5_hmac = md5
|
||||
import sha
|
||||
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::
|
||||
|
||||
class Hand(object):
|
||||
"""A hand of cards (bridge style)"""
|
||||
|
||||
def __init__(self, north, east, south, west):
|
||||
# Input parameters are lists of cards ('Ah', '9s', etc)
|
||||
self.north = north
|
||||
@ -163,6 +165,8 @@ behave like any existing field, so we'll subclass directly from
|
||||
from django.db import models
|
||||
|
||||
class HandField(models.Field):
|
||||
"""A hand of cards (bridge style)"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = 104
|
||||
super(HandField, self).__init__(*args, **kwargs)
|
||||
@ -244,6 +248,8 @@ simple: make sure your field subclass uses a special metaclass:
|
||||
For example::
|
||||
|
||||
class HandField(models.Field):
|
||||
"""A hand of cards (bridge style)"""
|
||||
|
||||
__metaclass__ = models.SubfieldBase
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -252,6 +258,21 @@ For example::
|
||||
This ensures that the :meth:`to_python` method, documented below, will always be
|
||||
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
|
||||
--------------
|
||||
|
||||
|
@ -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/
|
||||
.. _post a question: http://groups.google.com/group/django-users/
|
||||
.. _#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/
|
||||
|
||||
First steps
|
||||
|
@ -802,6 +802,14 @@ test <app or test identifier>
|
||||
Runs tests for all installed models. See :ref:`topics-testing` for more
|
||||
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 ...>
|
||||
--------------------------------
|
||||
|
||||
|
@ -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_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:
|
||||
|
||||
Configuring HTML ``<label>`` tags
|
||||
|
@ -253,24 +253,30 @@ handler404
|
||||
|
||||
.. data:: handler404
|
||||
|
||||
A string representing the full Python import path to the view that should be
|
||||
called if none of the URL patterns match.
|
||||
A callable, or a string representing the full Python import path to the view
|
||||
that should be called if none of the URL patterns match.
|
||||
|
||||
By default, this is ``'django.views.defaults.page_not_found'``. That default
|
||||
value should suffice.
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
Previous versions of Django only accepted strings representing import paths.
|
||||
|
||||
handler500
|
||||
----------
|
||||
|
||||
.. data:: handler500
|
||||
|
||||
A string representing the full Python import path to the view that should be
|
||||
called in case of server errors. Server errors happen when you have runtime
|
||||
errors in view code.
|
||||
A callable, or a string representing the full Python import path to the view
|
||||
that should be called in case of server errors. Server errors happen when you
|
||||
have runtime errors in view code.
|
||||
|
||||
By default, this is ``'django.views.defaults.server_error'``. That default
|
||||
value should suffice.
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
Previous versions of Django only accepted strings representing import paths.
|
||||
|
||||
include
|
||||
-------
|
||||
|
||||
|
@ -885,7 +885,7 @@ False
|
||||
>>> form = formset.forms[0] # this formset only has one form
|
||||
>>> now = form.fields['date_joined'].initial
|
||||
>>> 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>
|
||||
|
||||
# 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,
|
||||
"Expected an action-checkbox-column in response")
|
||||
|
||||
|
||||
def test_multiple_actions_form(self):
|
||||
"""
|
||||
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(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):
|
||||
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()]
|
||||
['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''
|
||||
>>> f.clean('')
|
||||
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 ##########################################################
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from extra import tests as extra_tests
|
||||
from fields import tests as fields_tests
|
||||
from forms import tests as form_tests
|
||||
from error_messages import tests as custom_error_message_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 media import media_tests
|
||||
|
||||
from fields import FieldsTests
|
||||
|
||||
__test__ = {
|
||||
'extra_tests': extra_tests,
|
||||
'fields_tests': fields_tests,
|
||||
'form_tests': form_tests,
|
||||
'custom_error_message_tests': custom_error_message_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)
|
@ -101,3 +101,15 @@ class CustomFieldSaveTests(TestCase):
|
||||
# generate an AssertionError if it is called more than once during save.
|
||||
form = CFFForm(data = {'f': None})
|
||||
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
|
||||
# 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-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")}, u". a<b. . a<b."),
|
||||
'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-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-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}', {"a": "alpha & bravo", "b": mark_safe("alpha & bravo")}, u"alpha & ... alpha & ..."),
|
||||
'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
|
||||
{"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),
|
||||
# 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/42/37/', reverse('nodefault:urlobject-view', kwargs={'arg1':42, 'arg2':37}, current_app='other-ns1'))
|
||||
|
||||
|
||||
class RequestURLconfTests(TestCase):
|
||||
def setUp(self):
|
||||
self.root_urlconf = settings.ROOT_URLCONF
|
||||
@ -276,3 +275,25 @@ class RequestURLconfTests(TestCase):
|
||||
response = self.client.get('/second_test/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
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 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
|
||||
|
||||
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'
|
||||
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:
|
||||
sys.exit(failures)
|
||||
|
||||
@ -181,6 +182,8 @@ if __name__ == "__main__":
|
||||
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
|
||||
parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
|
||||
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',
|
||||
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()
|
||||
@ -189,4 +192,4 @@ if __name__ == "__main__":
|
||||
elif "DJANGO_SETTINGS_MODULE" not in os.environ:
|
||||
parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. "
|
||||
"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