mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged to [6381]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6382 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
28a4aa6f49
commit
94c320d8a9
6
AUTHORS
6
AUTHORS
@ -49,6 +49,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
andy@jadedplanet.net
|
||||
Fabrice Aneche <akh@nobugware.com>
|
||||
ant9000@netwise.it
|
||||
Florian Apolloner
|
||||
David Ascher <http://ascher.ca/>
|
||||
david@kazserve.org
|
||||
Arthur <avandorp@gmail.com>
|
||||
@ -83,6 +84,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Russell Cloran <russell@rucus.net>
|
||||
colin@owlfish.com
|
||||
crankycoder@gmail.com
|
||||
Paul Collier <paul@paul-collier.com>
|
||||
Pete Crosier <pete.crosier@gmail.com>
|
||||
Matt Croydon <http://www.postneo.com/>
|
||||
flavio.curella@gmail.com
|
||||
@ -121,6 +123,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Afonso Fernández Nogueira <fonzzo.django@gmail.com>
|
||||
Matthew Flanagan <http://wadofstuff.blogspot.com>
|
||||
Eric Floehr <eric@intellovations.com>
|
||||
Vincent Foley <vfoleybourgon@yahoo.ca>
|
||||
Jorge Gajon <gajon@gajon.org>
|
||||
gandalf@owca.info
|
||||
Marc Garcia <marc.garcia@accopensys.com>
|
||||
@ -194,6 +197,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Waylan Limberg <waylan@gmail.com>
|
||||
limodou
|
||||
Philip Lindborg <philip.lindborg@gmail.com>
|
||||
msaelices <msaelices@gmail.com>
|
||||
Matt McClanahan <http://mmcc.cx/>
|
||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||
masonsimon+django@gmail.com
|
||||
@ -257,6 +261,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Brian Rosner <brosner@gmail.com>
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
ryankanno
|
||||
Manuel Saelices <msaelices@yaco.es>
|
||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||
David Schein
|
||||
@ -271,6 +276,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
sopel
|
||||
Leo Soto <leo.soto@gmail.com>
|
||||
Wiliam Alves de Souza <wiliamsouza83@gmail.com>
|
||||
Don Spaulding <donspauldingii@gmail.com>
|
||||
Bjørn Stabell <bjorn@exoweb.net>
|
||||
Georgi Stanojevski <glisha@gmail.com>
|
||||
Vasiliy Stavenko <stavenko@gmail.com>
|
||||
|
@ -4,20 +4,31 @@ import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
def compile_messages(locale=None):
|
||||
basedir = None
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
from sets import Set as set # For Python 2.3
|
||||
|
||||
if os.path.isdir(os.path.join('conf', 'locale')):
|
||||
basedir = os.path.abspath(os.path.join('conf', 'locale'))
|
||||
elif os.path.isdir('locale'):
|
||||
basedir = os.path.abspath('locale')
|
||||
else:
|
||||
print "This script should be run from the Django SVN tree or your project or app tree."
|
||||
|
||||
def compile_messages(locale=None):
|
||||
basedirs = [os.path.join('conf', 'locale'), 'locale']
|
||||
if os.environ.get('DJANGO_SETTINGS_MODULE'):
|
||||
from django.conf import settings
|
||||
basedirs += settings.LOCALE_PATHS
|
||||
|
||||
# Gather existing directories.
|
||||
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
|
||||
|
||||
if not basedirs:
|
||||
print "This script should be run from the Django SVN tree or your project or app tree, or with the settings module specified."
|
||||
sys.exit(1)
|
||||
|
||||
if locale is not None:
|
||||
basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
|
||||
for basedir in basedirs:
|
||||
if locale:
|
||||
basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
|
||||
compile_messages_in_dir(basedir)
|
||||
|
||||
def compile_messages_in_dir(basedir):
|
||||
for dirpath, dirnames, filenames in os.walk(basedir):
|
||||
for f in filenames:
|
||||
if f.endswith('.po'):
|
||||
@ -40,9 +51,13 @@ def main():
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('-l', '--locale', dest='locale',
|
||||
help="The locale to process. Default is to process all.")
|
||||
parser.add_option('--settings',
|
||||
help='Python path to settings module, e.g. "myproject.settings". If provided, all LOCALE_PATHS will be processed. If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be checked as well.')
|
||||
options, args = parser.parse_args()
|
||||
if len(args):
|
||||
parser.error("This program takes no arguments")
|
||||
if options.settings:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
|
||||
compile_messages(options.locale)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -140,7 +140,7 @@ class AdminBoundField(object):
|
||||
|
||||
def original_value(self):
|
||||
if self.original:
|
||||
return self.original.__dict__[self.field.column]
|
||||
return self.original.__dict__[self.field.attname]
|
||||
|
||||
def existing_display(self):
|
||||
try:
|
||||
|
@ -1,3 +1,4 @@
|
||||
from django.db import connection
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class ModelBackend:
|
||||
@ -14,6 +15,49 @@ class ModelBackend:
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
def get_group_permissions(self, user_obj):
|
||||
"Returns a list of permission strings that this user has through his/her groups."
|
||||
if not hasattr(user_obj, '_group_perm_cache'):
|
||||
cursor = connection.cursor()
|
||||
# The SQL below works out to the following, after DB quoting:
|
||||
# cursor.execute("""
|
||||
# SELECT ct."app_label", p."codename"
|
||||
# FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct
|
||||
# WHERE p."id" = gp."permission_id"
|
||||
# AND gp."group_id" = ug."group_id"
|
||||
# AND ct."id" = p."content_type_id"
|
||||
# AND ug."user_id" = %s, [self.id])
|
||||
qn = connection.ops.quote_name
|
||||
sql = """
|
||||
SELECT ct.%s, p.%s
|
||||
FROM %s p, %s gp, %s ug, %s ct
|
||||
WHERE p.%s = gp.%s
|
||||
AND gp.%s = ug.%s
|
||||
AND ct.%s = p.%s
|
||||
AND ug.%s = %%s""" % (
|
||||
qn('app_label'), qn('codename'),
|
||||
qn('auth_permission'), qn('auth_group_permissions'),
|
||||
qn('auth_user_groups'), qn('django_content_type'),
|
||||
qn('id'), qn('permission_id'),
|
||||
qn('group_id'), qn('group_id'),
|
||||
qn('id'), qn('content_type_id'),
|
||||
qn('user_id'),)
|
||||
cursor.execute(sql, [user_obj.id])
|
||||
user_obj._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
|
||||
return user_obj._group_perm_cache
|
||||
|
||||
def get_all_permissions(self, user_obj):
|
||||
if not hasattr(user_obj, '_perm_cache'):
|
||||
user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()])
|
||||
user_obj._perm_cache.update(self.get_group_permissions(user_obj))
|
||||
return user_obj._perm_cache
|
||||
|
||||
def has_perm(self, user_obj, perm):
|
||||
return perm in self.get_all_permissions(user_obj)
|
||||
|
||||
def has_module_perms(self, user_obj, app_label):
|
||||
return bool(len([p for p in self.get_all_permissions(user_obj) if p[:p.index('.')] == app_label]))
|
||||
|
||||
def get_user(self, user_id):
|
||||
try:
|
||||
return User.objects.get(pk=user_id)
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.contrib import auth
|
||||
from django.core import validators
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db import connection, models
|
||||
from django.db import models
|
||||
from django.db.models.manager import EmptyManager
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.encoding import smart_str
|
||||
@ -210,64 +211,68 @@ class User(models.Model):
|
||||
return self.password != UNUSABLE_PASSWORD
|
||||
|
||||
def get_group_permissions(self):
|
||||
"Returns a list of permission strings that this user has through his/her groups."
|
||||
if not hasattr(self, '_group_perm_cache'):
|
||||
cursor = connection.cursor()
|
||||
# The SQL below works out to the following, after DB quoting:
|
||||
# cursor.execute("""
|
||||
# SELECT ct."app_label", p."codename"
|
||||
# FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct
|
||||
# WHERE p."id" = gp."permission_id"
|
||||
# AND gp."group_id" = ug."group_id"
|
||||
# AND ct."id" = p."content_type_id"
|
||||
# AND ug."user_id" = %s, [self.id])
|
||||
qn = connection.ops.quote_name
|
||||
sql = """
|
||||
SELECT ct.%s, p.%s
|
||||
FROM %s p, %s gp, %s ug, %s ct
|
||||
WHERE p.%s = gp.%s
|
||||
AND gp.%s = ug.%s
|
||||
AND ct.%s = p.%s
|
||||
AND ug.%s = %%s""" % (
|
||||
qn('app_label'), qn('codename'),
|
||||
qn('auth_permission'), qn('auth_group_permissions'),
|
||||
qn('auth_user_groups'), qn('django_content_type'),
|
||||
qn('id'), qn('permission_id'),
|
||||
qn('group_id'), qn('group_id'),
|
||||
qn('id'), qn('content_type_id'),
|
||||
qn('user_id'),)
|
||||
cursor.execute(sql, [self.id])
|
||||
self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
|
||||
return self._group_perm_cache
|
||||
"""
|
||||
Returns a list of permission strings that this user has through
|
||||
his/her groups. This method queries all available auth backends.
|
||||
"""
|
||||
permissions = set()
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "get_group_permissions"):
|
||||
permissions.update(backend.get_group_permissions(self))
|
||||
return permissions
|
||||
|
||||
def get_all_permissions(self):
|
||||
if not hasattr(self, '_perm_cache'):
|
||||
self._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
|
||||
self._perm_cache.update(self.get_group_permissions())
|
||||
return self._perm_cache
|
||||
permissions = set()
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "get_all_permissions"):
|
||||
permissions.update(backend.get_all_permissions(self))
|
||||
return permissions
|
||||
|
||||
def has_perm(self, perm):
|
||||
"Returns True if the user has the specified permission."
|
||||
"""
|
||||
Returns True if the user has the specified permission. This method
|
||||
queries all available auth backends, but returns immediately if any
|
||||
backend returns True. Thus, a user who has permission from a single
|
||||
auth backend is assumed to have permission in general.
|
||||
"""
|
||||
# Inactive users have no permissions.
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
# Superusers have all permissions.
|
||||
if self.is_superuser:
|
||||
return True
|
||||
return perm in self.get_all_permissions()
|
||||
|
||||
# Otherwise we need to check the backends.
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "has_perm"):
|
||||
if backend.has_perm(self, perm):
|
||||
return True
|
||||
return False
|
||||
|
||||
def has_perms(self, perm_list):
|
||||
"Returns True if the user has each of the specified permissions."
|
||||
"""Returns True if the user has each of the specified permissions."""
|
||||
for perm in perm_list:
|
||||
if not self.has_perm(perm):
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"Returns True if the user has any permissions in the given app label."
|
||||
"""
|
||||
Returns True if the user has any permissions in the given app
|
||||
label. Uses pretty much the same logic as has_perm, above.
|
||||
"""
|
||||
if not self.is_active:
|
||||
return False
|
||||
|
||||
if self.is_superuser:
|
||||
return True
|
||||
return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))
|
||||
|
||||
for backend in auth.get_backends():
|
||||
if hasattr(backend, "has_module_perms"):
|
||||
if backend.has_module_perms(self, app_label):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_and_delete_messages(self):
|
||||
messages = []
|
||||
@ -300,7 +305,12 @@ class User(models.Model):
|
||||
|
||||
class Message(models.Model):
|
||||
"""
|
||||
The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
|
||||
The message system is a lightweight way to queue messages for given
|
||||
users. A message is associated with a User instance (so it is only
|
||||
applicable for registered users). There's no concept of expiration or
|
||||
timestamps. Messages are created by the Django admin after successful
|
||||
actions. For example, "The poll Foo was created successfully." is a
|
||||
message.
|
||||
"""
|
||||
user = models.ForeignKey(User)
|
||||
message = models.TextField(_('message'))
|
||||
|
@ -107,7 +107,7 @@ class SessionBase(object):
|
||||
try:
|
||||
return self._session_cache
|
||||
except AttributeError:
|
||||
if self.session_key is None:
|
||||
if self._session_key is None:
|
||||
self._session_cache = {}
|
||||
else:
|
||||
self._session_cache = self.load()
|
||||
|
@ -31,11 +31,12 @@ class SessionStore(SessionBase):
|
||||
try:
|
||||
session_file = open(self._key_to_file(), "rb")
|
||||
try:
|
||||
session_data = self.decode(session_file.read())
|
||||
except(EOFError, SuspiciousOperation):
|
||||
self._session_key = self._get_new_session_key()
|
||||
self._session_cache = {}
|
||||
self.save()
|
||||
try:
|
||||
session_data = self.decode(session_file.read())
|
||||
except(EOFError, SuspiciousOperation):
|
||||
self._session_key = self._get_new_session_key()
|
||||
self._session_cache = {}
|
||||
self.save()
|
||||
finally:
|
||||
session_file.close()
|
||||
except(IOError):
|
||||
@ -64,4 +65,4 @@ class SessionStore(SessionBase):
|
||||
pass
|
||||
|
||||
def clean(self):
|
||||
pass
|
||||
pass
|
||||
|
@ -13,11 +13,19 @@ def auth(request):
|
||||
"""
|
||||
Returns context variables required by apps that use Django's authentication
|
||||
system.
|
||||
|
||||
If there is no 'user' attribute in the request, uses AnonymousUser (from
|
||||
django.contrib.auth).
|
||||
"""
|
||||
if hasattr(request, 'user'):
|
||||
user = request.user
|
||||
else:
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
user = AnonymousUser()
|
||||
return {
|
||||
'user': request.user,
|
||||
'messages': request.user.get_and_delete_messages(),
|
||||
'perms': PermWrapper(request.user),
|
||||
'user': user,
|
||||
'messages': user.get_and_delete_messages(),
|
||||
'perms': PermWrapper(user),
|
||||
}
|
||||
|
||||
def debug(request):
|
||||
|
@ -42,8 +42,11 @@ class ModPythonRequest(http.HttpRequest):
|
||||
return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '')
|
||||
|
||||
def is_secure(self):
|
||||
# Note: modpython 3.2.10+ has req.is_https(), but we need to support previous versions
|
||||
return 'HTTPS' in self._req.subprocess_env and self._req.subprocess_env['HTTPS'] == 'on'
|
||||
try:
|
||||
return self._req.is_https()
|
||||
except AttributeError:
|
||||
# mod_python < 3.2.10 doesn't have req.is_https().
|
||||
return self._req.subprocess_env.get('HTTPS', '').lower() in ('on', '1')
|
||||
|
||||
def _load_post_and_files(self):
|
||||
"Populates self._post and self._files"
|
||||
|
@ -6,10 +6,10 @@ DATA_TYPES = {
|
||||
'DateField': 'smalldatetime',
|
||||
'DateTimeField': 'smalldatetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
'FileField': 'varchar(100)',
|
||||
'FilePathField': 'varchar(100)',
|
||||
'FileField': 'varchar(%(max_length)s)',
|
||||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'ImageField': 'varchar(100)',
|
||||
'ImageField': 'varchar(%(max_length)s)',
|
||||
'IntegerField': 'int',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bit',
|
||||
|
@ -10,10 +10,10 @@ DATA_TYPES = {
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
'FileField': 'varchar(100)',
|
||||
'FilePathField': 'varchar(100)',
|
||||
'FileField': 'varchar(%(max_length)s)',
|
||||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'ImageField': 'varchar(100)',
|
||||
'ImageField': 'varchar(%(max_length)s)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bool',
|
||||
|
@ -10,10 +10,10 @@ DATA_TYPES = {
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
'FileField': 'varchar(100)',
|
||||
'FilePathField': 'varchar(100)',
|
||||
'FileField': 'varchar(%(max_length)s)',
|
||||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'ImageField': 'varchar(100)',
|
||||
'ImageField': 'varchar(%(max_length)s)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bool',
|
||||
|
@ -13,10 +13,10 @@ DATA_TYPES = {
|
||||
'DateField': 'DATE',
|
||||
'DateTimeField': 'TIMESTAMP',
|
||||
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
||||
'FileField': 'NVARCHAR2(100)',
|
||||
'FilePathField': 'NVARCHAR2(100)',
|
||||
'FileField': 'NVARCHAR2(%(max_length)s)',
|
||||
'FilePathField': 'NVARCHAR2(%(max_length)s)',
|
||||
'FloatField': 'DOUBLE PRECISION',
|
||||
'ImageField': 'NVARCHAR2(100)',
|
||||
'ImageField': 'NVARCHAR2(%(max_length)s)',
|
||||
'IntegerField': 'NUMBER(11)',
|
||||
'IPAddressField': 'VARCHAR2(15)',
|
||||
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
||||
@ -28,7 +28,7 @@ DATA_TYPES = {
|
||||
'SmallIntegerField': 'NUMBER(11)',
|
||||
'TextField': 'NCLOB',
|
||||
'TimeField': 'TIMESTAMP',
|
||||
'URLField': 'VARCHAR2(200)',
|
||||
'URLField': 'VARCHAR2(%(max_length)s)',
|
||||
'USStateField': 'CHAR(2)',
|
||||
}
|
||||
|
||||
|
@ -10,10 +10,10 @@ DATA_TYPES = {
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'timestamp with time zone',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
'FileField': 'varchar(100)',
|
||||
'FilePathField': 'varchar(100)',
|
||||
'FileField': 'varchar(%(max_length)s)',
|
||||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'double precision',
|
||||
'ImageField': 'varchar(100)',
|
||||
'ImageField': 'varchar(%(max_length)s)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'inet',
|
||||
'NullBooleanField': 'boolean',
|
||||
|
@ -9,10 +9,10 @@ DATA_TYPES = {
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'decimal',
|
||||
'FileField': 'varchar(100)',
|
||||
'FilePathField': 'varchar(100)',
|
||||
'FileField': 'varchar(%(max_length)s)',
|
||||
'FilePathField': 'varchar(%(max_length)s)',
|
||||
'FloatField': 'real',
|
||||
'ImageField': 'varchar(100)',
|
||||
'ImageField': 'varchar(%(max_length)s)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'NullBooleanField': 'bool',
|
||||
|
@ -83,6 +83,11 @@ class Model(object):
|
||||
def _get_pk_val(self):
|
||||
return getattr(self, self._meta.pk.attname)
|
||||
|
||||
def _set_pk_val(self, value):
|
||||
return setattr(self, self._meta.pk.attname, value)
|
||||
|
||||
pk = property(_get_pk_val, _set_pk_val)
|
||||
|
||||
def __repr__(self):
|
||||
return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
|
||||
|
||||
|
@ -693,8 +693,7 @@ class DecimalField(Field):
|
||||
|
||||
class EmailField(CharField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'max_length' not in kwargs:
|
||||
kwargs['max_length'] = 75
|
||||
kwargs['max_length'] = kwargs.get('max_length', 75)
|
||||
CharField.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
@ -714,6 +713,7 @@ class EmailField(CharField):
|
||||
class FileField(Field):
|
||||
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
|
||||
self.upload_to = upload_to
|
||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_db_prep_save(self, value):
|
||||
@ -815,6 +815,7 @@ class FileField(Field):
|
||||
class FilePathField(Field):
|
||||
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)
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
@ -887,6 +888,11 @@ class IPAddressField(Field):
|
||||
def validate(self, field_data, all_data):
|
||||
validators.isValidIPAddress4(field_data, None)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.IPAddressField}
|
||||
defaults.update(kwargs)
|
||||
return super(IPAddressField, self).formfield(**defaults)
|
||||
|
||||
class NullBooleanField(Field):
|
||||
empty_strings_allowed = False
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -55,6 +55,7 @@ class SetRemoteAddrFromForwardedFor(object):
|
||||
return None
|
||||
else:
|
||||
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.
|
||||
# Take just the first one.
|
||||
real_ip = real_ip.split(",")[0]
|
||||
# Take just the last one.
|
||||
# See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/
|
||||
real_ip = real_ip.split(",")[-1].strip()
|
||||
request.META['REMOTE_ADDR'] = real_ip
|
||||
|
@ -26,7 +26,7 @@ __all__ = (
|
||||
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField',
|
||||
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
|
||||
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
||||
'SplitDateTimeField',
|
||||
'SplitDateTimeField', 'IPAddressField',
|
||||
)
|
||||
|
||||
# These values, if given to to_python(), will trigger the self.required check.
|
||||
@ -635,3 +635,11 @@ class SplitDateTimeField(MultiValueField):
|
||||
raise ValidationError(ugettext(u'Enter a valid time.'))
|
||||
return datetime.datetime.combine(*data_list)
|
||||
return None
|
||||
|
||||
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
|
||||
|
||||
class IPAddressField(RegexField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
RegexField.__init__(self, ipv4_re,
|
||||
error_message=ugettext(u'Enter a valid IPv4 address.'),
|
||||
*args, **kwargs)
|
||||
|
@ -58,7 +58,7 @@ class BaseForm(StrAndUnicode):
|
||||
# information. Any improvements to the form API should be made to *this*
|
||||
# class, not to the Form class.
|
||||
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
|
||||
initial=None, error_class=ErrorList):
|
||||
initial=None, error_class=ErrorList, label_suffix=':'):
|
||||
self.is_bound = data is not None or files is not None
|
||||
self.data = data or {}
|
||||
self.files = files or {}
|
||||
@ -66,6 +66,7 @@ class BaseForm(StrAndUnicode):
|
||||
self.prefix = prefix
|
||||
self.initial = initial or {}
|
||||
self.error_class = error_class
|
||||
self.label_suffix = label_suffix
|
||||
self._errors = None # Stores the errors after clean() has been called.
|
||||
|
||||
# The base_fields class attribute is the *class-wide* definition of
|
||||
@ -129,9 +130,10 @@ class BaseForm(StrAndUnicode):
|
||||
output.append(error_row % force_unicode(bf_errors))
|
||||
if bf.label:
|
||||
label = escape(force_unicode(bf.label))
|
||||
# Only add a colon if the label does not end in punctuation.
|
||||
if label[-1] not in ':?.!':
|
||||
label += ':'
|
||||
# Only add the suffix if the label does not end in punctuation.
|
||||
if self.label_suffix:
|
||||
if label[-1] not in ':?.!':
|
||||
label += self.label_suffix
|
||||
label = bf.label_tag(label) or ''
|
||||
else:
|
||||
label = ''
|
||||
|
@ -447,7 +447,7 @@ class LargeTextField(TextField):
|
||||
self.field_name, self.rows, self.cols, escape(data))
|
||||
|
||||
class HiddenField(FormField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None, max_length=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name, self.is_required = field_name, is_required
|
||||
self.validator_list = validator_list[:]
|
||||
@ -674,7 +674,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
|
||||
####################
|
||||
|
||||
class FileUploadField(FormField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None, max_length=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name, self.is_required = field_name, is_required
|
||||
self.validator_list = [self.isNonEmptyFile] + validator_list
|
||||
@ -946,7 +946,7 @@ class IPAddressField(TextField):
|
||||
|
||||
class FilePathField(SelectField):
|
||||
"A SelectField whose choices are the files in a given directory."
|
||||
def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None, max_length=None):
|
||||
import os
|
||||
from django.db.models import BLANK_CHOICE_DASH
|
||||
if match is not None:
|
||||
|
@ -72,12 +72,23 @@ class SortedDict(dict):
|
||||
def items(self):
|
||||
return zip(self.keyOrder, self.values())
|
||||
|
||||
def iteritems(self):
|
||||
for key in self.keyOrder:
|
||||
yield key, dict.__getitem__(self, key)
|
||||
|
||||
def keys(self):
|
||||
return self.keyOrder[:]
|
||||
|
||||
def iterkeys(self):
|
||||
return iter(self.keyOrder)
|
||||
|
||||
def values(self):
|
||||
return [dict.__getitem__(self, k) for k in self.keyOrder]
|
||||
|
||||
def itervalues(self):
|
||||
for key in self.keyOrder:
|
||||
yield dict.__getitem__(self, key)
|
||||
|
||||
def update(self, dict):
|
||||
for k, v in dict.items():
|
||||
self.__setitem__(k, v)
|
||||
@ -91,6 +102,15 @@ class SortedDict(dict):
|
||||
"Returns the value of the item at the given zero-based index."
|
||||
return self[self.keyOrder[index]]
|
||||
|
||||
def insert(self, index, key, value):
|
||||
"Inserts the key, value pair before the item with the given index."
|
||||
if key in self.keyOrder:
|
||||
n = self.keyOrder.index(key)
|
||||
del self.keyOrder[n]
|
||||
if n < index: index -= 1
|
||||
self.keyOrder.insert(index, key)
|
||||
dict.__setitem__(self, key, value)
|
||||
|
||||
def copy(self):
|
||||
"Returns a copy of this object."
|
||||
# This way of initializing the copy means it works for subclasses, too.
|
||||
|
@ -166,8 +166,8 @@ class DateFormat(TimeFormat):
|
||||
|
||||
def O(self):
|
||||
"Difference to Greenwich time in hours; e.g. '+0200'"
|
||||
tz = self.timezone.utcoffset(self.data)
|
||||
return u"%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
|
||||
seconds = self.Z()
|
||||
return u"%+03d%02d" % (seconds // 3600, (seconds // 60) % 60)
|
||||
|
||||
def r(self):
|
||||
"RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
|
||||
|
@ -1,11 +1,20 @@
|
||||
import datetime, math, time
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from django.utils.tzinfo import LocalTimezone
|
||||
from django.utils.translation import ungettext, ugettext
|
||||
|
||||
def timesince(d, now=None):
|
||||
"""
|
||||
Takes two datetime objects and returns the time between then and now
|
||||
as a nicely formatted string, e.g "10 minutes"
|
||||
Takes two datetime objects and returns the time between d and now
|
||||
as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
|
||||
then "0 minutes" is returned.
|
||||
|
||||
Units used are years, months, weeks, days, hours, and minutes.
|
||||
Seconds and microseconds are ignored. Up to two adjacent units will be
|
||||
displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
|
||||
possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
|
||||
|
||||
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
|
||||
"""
|
||||
chunks = (
|
||||
@ -32,6 +41,9 @@ def timesince(d, now=None):
|
||||
# ignore microsecond part of 'd' since we removed it from 'now'
|
||||
delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
|
||||
since = delta.days * 24 * 60 * 60 + delta.seconds
|
||||
if since <= 0:
|
||||
# d is in the future compared to now, stop processing.
|
||||
return u'0 ' + ugettext('minutes')
|
||||
for i, (seconds, name) in enumerate(chunks):
|
||||
count = since // seconds
|
||||
if count != 0:
|
||||
|
@ -34,12 +34,12 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||
If you're using Apache 2.2, you'll need to take a couple extra steps.
|
||||
|
||||
You'll need to ensure that ``mod_auth_basic`` and ``mod_authz_user``
|
||||
are loaded. These might be compiled staticly into Apache, or you might
|
||||
are loaded. These might be compiled statically into Apache, or you might
|
||||
need to use ``LoadModule`` to load them dynamically (as shown in the
|
||||
example at the bottom of this note).
|
||||
|
||||
You'll also need to insert configuration directives that prevent Apache
|
||||
from trying to use other authentication modules. Depnding on which other
|
||||
from trying to use other authentication modules. Depending on which other
|
||||
authentication modules you have loaded, you might need one or more of
|
||||
the following directives::
|
||||
|
||||
|
@ -1062,3 +1062,40 @@ object the first time a user authenticates::
|
||||
return User.objects.get(pk=user_id)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
Handling authorization in custom backends
|
||||
-----------------------------------------
|
||||
|
||||
Custom auth backends can provide their own permissions.
|
||||
|
||||
The user model will delegate permission lookup functions
|
||||
(``get_group_permissions()``, ``get_all_permissions()``, ``has_perm()``, and
|
||||
``has_module_perms()``) to any authentication backend that implements these
|
||||
functions.
|
||||
|
||||
The permissions given to the user will be the superset of all permissions
|
||||
returned by all backends. That is, Django grants a permission to a user that any
|
||||
one backend grants.
|
||||
|
||||
The simple backend above could implement permissions for the magic admin fairly
|
||||
simply::
|
||||
|
||||
class SettingsBackend:
|
||||
|
||||
# ...
|
||||
|
||||
def has_perm(self, user_obj, perm):
|
||||
if user_obj.username == settings.ADMIN_LOGIN:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
This gives full permissions to the user granted access in the above example. Notice
|
||||
that the backend auth functions all take the user object as an argument, and
|
||||
they also accept the same arguments given to the associated ``User`` functions.
|
||||
|
||||
A full authorization implementation can be found in
|
||||
``django/contrib/auth/backends.py`` _, which is the default backend and queries
|
||||
the ``auth_permission`` table most of the time.
|
||||
|
||||
.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
|
||||
|
@ -645,11 +645,11 @@ Examples:
|
||||
To run the test server on port 7000 with ``fixture1`` and ``fixture2``::
|
||||
|
||||
django-admin.py testserver --addrport 7000 fixture1 fixture2
|
||||
django-admin.py testserver fixture1 fixture2 --addrport 8080
|
||||
django-admin.py testserver fixture1 fixture2 --addrport 7000
|
||||
|
||||
(The above statements are equivalent. We include both of them to demonstrate
|
||||
that it doesn't matter whether the options come before or after the
|
||||
``testserver`` command.)
|
||||
that it doesn't matter whether the options come before or after the fixture
|
||||
arguments.)
|
||||
|
||||
To run on 1.2.3.4:7000 with a `test` fixture::
|
||||
|
||||
|
@ -328,7 +328,7 @@ attribute on the ``EmailMessage`` class to change the main content type. The
|
||||
major type will always be ``"text"``, but you can change it to the subtype. For
|
||||
example::
|
||||
|
||||
msg = EmailMessage(subject, html_content, from_email, to)
|
||||
msg = EmailMessage(subject, html_content, from_email, [to])
|
||||
msg.content_subtype = "html" # Main content is now text/html
|
||||
msg.send()
|
||||
|
||||
|
@ -669,8 +669,11 @@ To create message files, you use the same ``make-messages.py`` tool as with the
|
||||
Django message files. You only need to be in the right place -- in the directory
|
||||
where either the ``conf/locale`` (in case of the source tree) or the ``locale/``
|
||||
(in case of app messages or project messages) directory are located. And you
|
||||
use the same ``compile-messages.py`` to produce the binary ``django.mo`` files that
|
||||
are used by ``gettext``.
|
||||
use the same ``compile-messages.py`` to produce the binary ``django.mo`` files
|
||||
that are used by ``gettext``.
|
||||
|
||||
You can also run ``compile-message.py --settings=path.to.settings`` to make
|
||||
the compiler process all the directories in your ``LOCALE_PATHS`` setting.
|
||||
|
||||
Application message files are a bit complicated to discover -- they need the
|
||||
``LocaleMiddleware``. If you don't use the middleware, only the Django message
|
||||
@ -710,7 +713,7 @@ language choice in a ``django_language`` cookie.
|
||||
After setting the language choice, Django redirects the user, following this
|
||||
algorithm:
|
||||
|
||||
* Django looks for a ``next`` parameter in ``POST`` request.
|
||||
* Django looks for a ``next`` parameter in the ``POST`` data.
|
||||
* If that doesn't exist, or is empty, Django tries the URL in the
|
||||
``Referrer`` header.
|
||||
* If that's empty -- say, if a user's browser suppresses that header --
|
||||
|
@ -86,7 +86,7 @@ to create a temporary test database.
|
||||
.. _SQLite: http://www.sqlite.org/
|
||||
.. _pysqlite: http://initd.org/tracker/pysqlite
|
||||
.. _MySQL backend: ../databases/
|
||||
.. _cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/
|
||||
.. _cx_Oracle: http://cx-oracle.sourceforge.net/
|
||||
.. _Oracle: http://www.oracle.com/
|
||||
.. _testing framework: ../testing/
|
||||
|
||||
|
@ -293,6 +293,10 @@ visiting its URL on your site. Don't allow that.
|
||||
|
||||
.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
|
||||
|
||||
**New in development version:** By default, ``FileField`` instances are
|
||||
created as ``varchar(100)`` columns in your database. As with other fields, you
|
||||
can change the maximum length using the ``max_length`` argument.
|
||||
|
||||
``FilePathField``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -330,6 +334,10 @@ not the full path. So, this example::
|
||||
because the ``match`` applies to the base filename (``foo.gif`` and
|
||||
``bar.gif``).
|
||||
|
||||
**New in development version:** By default, ``FilePathField`` instances are
|
||||
created as ``varchar(100)`` columns in your database. As with other fields, you
|
||||
can change the maximum length using the ``max_length`` argument.
|
||||
|
||||
``FloatField``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@ -361,6 +369,11 @@ Requires the `Python Imaging Library`_.
|
||||
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
||||
.. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width
|
||||
|
||||
**New in development version:** By default, ``ImageField`` instances are
|
||||
created as ``varchar(100)`` columns in your database. As with other fields, you
|
||||
can change the maximum length using the ``max_length`` argument.
|
||||
|
||||
|
||||
``IntegerField``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1284,6 +1297,17 @@ won't add the automatic ``id`` column.
|
||||
|
||||
Each model requires exactly one field to have ``primary_key=True``.
|
||||
|
||||
The ``pk`` property
|
||||
-------------------
|
||||
**New in Django development version**
|
||||
|
||||
Regardless of whether you define a primary key field yourself, or let Django
|
||||
supply one for you, each model will have a property called ``pk``. It behaves
|
||||
like a normal attribute on the model, but is actually an alias for whichever
|
||||
attribute is the primary key field for the model. You can read and set this
|
||||
value, just as you would for any other attribute, and it will update the
|
||||
correct field in the model.
|
||||
|
||||
Admin options
|
||||
=============
|
||||
|
||||
|
@ -513,6 +513,26 @@ include ``%s`` -- then the library will act as if ``auto_id`` is ``True``.
|
||||
|
||||
By default, ``auto_id`` is set to the string ``'id_%s'``.
|
||||
|
||||
Normally, a colon (``:``) will be appended after any label name when a form is
|
||||
rendered. It's possible to change the colon to another character, or omit it
|
||||
entirely, using the ``label_suffix`` parameter::
|
||||
|
||||
>>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
|
||||
>>> print f.as_ul()
|
||||
<li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
|
||||
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li>
|
||||
<li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li>
|
||||
<li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
|
||||
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
|
||||
>>> print f.as_ul()
|
||||
<li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
|
||||
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li>
|
||||
<li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li>
|
||||
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
|
||||
|
||||
Note that the label suffix is added only if the last character of the
|
||||
label isn't a punctuation character (``.``, ``!``, ``?`` or ``:``)
|
||||
|
||||
Notes on field ordering
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1264,6 +1284,15 @@ When you use a ``FileField`` on a form, you must also remember to
|
||||
Takes two optional arguments for validation, ``max_value`` and ``min_value``.
|
||||
These control the range of values permitted in the field.
|
||||
|
||||
``IPAddressField``
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Default widget: ``TextInput``
|
||||
* Empty value: ``''`` (an empty string)
|
||||
* Normalizes to: A Unicode object.
|
||||
* Validates that the given value is a valid IPv4 address, using a regular
|
||||
expression.
|
||||
|
||||
``MultipleChoiceField``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1690,7 +1719,7 @@ the full list of conversions:
|
||||
``ForeignKey`` ``ModelChoiceField`` (see below)
|
||||
``ImageField`` ``ImageField``
|
||||
``IntegerField`` ``IntegerField``
|
||||
``IPAddressField`` ``CharField``
|
||||
``IPAddressField`` ``IPAddressField``
|
||||
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
|
||||
below)
|
||||
``NullBooleanField`` ``CharField``
|
||||
|
@ -18,13 +18,13 @@ To enable session functionality, do the following:
|
||||
``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
|
||||
The default ``settings.py`` created by ``django-admin.py startproject`` has
|
||||
``SessionMiddleware`` activated.
|
||||
|
||||
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting,
|
||||
and run ``manage.py syncdb`` to install the single database table
|
||||
that stores session data.
|
||||
|
||||
|
||||
**New in development version**: this step is optional if you're not using
|
||||
the database session backend; see `configuring the session engine`_.
|
||||
the database session backend; see `configuring the session engine`_.
|
||||
|
||||
If you don't want to use sessions, you might as well remove the
|
||||
``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'``
|
||||
@ -50,7 +50,7 @@ To use file-based sessions, set the ``SESSION_ENGINE`` setting to
|
||||
|
||||
You might also want to set the ``SESSION_FILE_PATH`` setting (which
|
||||
defaults to ``/tmp``) to control where Django stores session files. Be
|
||||
sure to check that your web server has permissions to read and write to
|
||||
sure to check that your Web server has permissions to read and write to
|
||||
this location.
|
||||
|
||||
Using cache-based sessions
|
||||
@ -64,8 +64,8 @@ you've configured your cache; see the `cache documentation`_ for details.
|
||||
|
||||
.. note::
|
||||
|
||||
You probably don't want to use cache-based sessions if you're not using
|
||||
the memcached cache backend. The local memory and simple cache backends
|
||||
You should probably only use cache-based sessions if you're using the
|
||||
memcached cache backend. The local memory and simple cache backends
|
||||
don't retain data long enough to be good choices, and it'll be faster
|
||||
to use file or database sessions directly instead of sending everything
|
||||
through the file or database cache backends.
|
||||
@ -194,25 +194,26 @@ Here's a typical usage example::
|
||||
Using sessions out of views
|
||||
===========================
|
||||
|
||||
The ``SessionStore`` which implements the session storage method can be imported
|
||||
and a API is available to manipulate the session data outside of a view::
|
||||
**New in Django development version**
|
||||
|
||||
>>> from django.contrib.sessions.engines.db import SessionStore
|
||||
An API is available to manipulate session data outside of a view::
|
||||
|
||||
>>> from django.contrib.sessions.backends.db import SessionStore
|
||||
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
|
||||
>>> s['last_login']
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 0)
|
||||
>>> s.save()
|
||||
|
||||
Or if you are using the ``django.contrib.sessions.engine.db`` each
|
||||
session is just a normal Django model. The ``Session`` model
|
||||
is defined in ``django/contrib/sessions/models.py``. Because it's a normal
|
||||
model, you can access sessions using the normal Django database API::
|
||||
If you're using the ``django.contrib.sessions.engine.db`` backend, each
|
||||
session is just a normal Django model. The ``Session`` model is defined in
|
||||
``django/contrib/sessions/models.py``. Because it's a normal model, you can
|
||||
access sessions using the normal Django database API::
|
||||
|
||||
>>> from django.contrib.sessions.models import Session
|
||||
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s.expire_date
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 12)
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 12)
|
||||
|
||||
Note that you'll need to call ``get_decoded()`` to get the session dictionary.
|
||||
This is necessary because the dictionary is stored in an encoded format::
|
||||
@ -306,10 +307,10 @@ Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
|
||||
See `configuring the session engine`_ for more details.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
|
@ -257,10 +257,11 @@ The database backend to use. The build-in database backends are
|
||||
``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'mysql_old'``,
|
||||
``'sqlite3'``, ``'oracle'``, or ``'ado_mssql'``.
|
||||
|
||||
You can also use a database backend that doesn't ship with Django by
|
||||
setting ``DATABASE_ENGINE`` to a fully-qualified path (i.e.
|
||||
In the Django development version, you can use a database backend that doesn't
|
||||
ship with Django by setting ``DATABASE_ENGINE`` to a fully-qualified path (i.e.
|
||||
``mypackage.backends.whatever``). Writing a whole new database backend from
|
||||
scratch is left as an exercise to the reader.
|
||||
scratch is left as an exercise to the reader; see the other backends for
|
||||
examples.
|
||||
|
||||
DATABASE_HOST
|
||||
-------------
|
||||
|
@ -1275,17 +1275,23 @@ For example, if ``blog_date`` is a date instance representing midnight on 1
|
||||
June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006,
|
||||
then ``{{ comment_date|timesince:blog_date }}`` would return "8 hours".
|
||||
|
||||
Minutes is the smallest unit used, and "0 minutes" will be returned for any
|
||||
date that is in the future relative to the comparison point.
|
||||
|
||||
timeuntil
|
||||
~~~~~~~~~
|
||||
|
||||
Similar to ``timesince``, except that it measures the time from now until the
|
||||
given date or datetime. For example, if today is 1 June 2006 and
|
||||
``conference_date`` is a date instance holding 29 June 2006, then
|
||||
``{{ conference_date|timeuntil }}`` will return "28 days".
|
||||
``{{ conference_date|timeuntil }}`` will return "4 weeks".
|
||||
|
||||
Takes an optional argument that is a variable containing the date to use as
|
||||
the comparison point (instead of *now*). If ``from_date`` contains 22 June
|
||||
2006, then ``{{ conference_date|timeuntil:from_date }}`` will return "7 days".
|
||||
2006, then ``{{ conference_date|timeuntil:from_date }}`` will return "1 week".
|
||||
|
||||
Minutes is the smallest unit used, and "0 minutes" will be returned for any
|
||||
date that is in the past relative to the comparison point.
|
||||
|
||||
title
|
||||
~~~~~
|
||||
|
@ -33,6 +33,11 @@ __test__ = {'API_TESTS': """
|
||||
>>> a.id
|
||||
1L
|
||||
|
||||
# Models have a pk property that is an alias for the primary key attribute (by
|
||||
# default, the 'id' attribute).
|
||||
>>> a.pk
|
||||
1L
|
||||
|
||||
# Access database columns via Python attributes.
|
||||
>>> a.headline
|
||||
'Area man programs in Python'
|
||||
|
@ -56,6 +56,15 @@ DoesNotExist: Employee matching query does not exist.
|
||||
>>> Employee.objects.filter(pk__in=['ABC123','XYZ456'])
|
||||
[<Employee: Fran Bones>, <Employee: Dan Jones>]
|
||||
|
||||
# The primary key can be accessed via the pk property on the model.
|
||||
>>> e = Employee.objects.get(pk='ABC123')
|
||||
>>> e.pk
|
||||
u'ABC123'
|
||||
|
||||
# Or we can use the real attribute name for the primary key:
|
||||
>>> e.employee_code
|
||||
u'ABC123'
|
||||
|
||||
# Fran got married and changed her last name.
|
||||
>>> fran = Employee.objects.get(pk='XYZ456')
|
||||
>>> fran.last_name = 'Jones'
|
||||
|
@ -9,6 +9,7 @@ FIXTURE_DIRS setting.
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
class Article(models.Model):
|
||||
headline = models.CharField(max_length=100, default='Default headline')
|
||||
@ -53,7 +54,13 @@ __test__ = {'API_TESTS': """
|
||||
# object list is unaffected
|
||||
>>> Article.objects.all()
|
||||
[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
|
||||
"""}
|
||||
|
||||
# Database flushing does not work on MySQL with the default storage engine
|
||||
# because it requires transaction support.
|
||||
if settings.DATABASE_ENGINE not in ('mysql', 'mysql_old'):
|
||||
__test__['API_TESTS'] += \
|
||||
"""
|
||||
# Reset the database representation of this app. This will delete all data.
|
||||
>>> management.call_command('flush', verbosity=0, interactive=False)
|
||||
>>> Article.objects.all()
|
||||
@ -75,7 +82,7 @@ Multiple fixtures named 'fixture2' in '...fixtures'. Aborting.
|
||||
# Dump the current contents of the database as a JSON fixture
|
||||
>>> management.call_command('dumpdata', 'fixtures', format='json')
|
||||
[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}]
|
||||
"""}
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
0
tests/regressiontests/auth_backends/__init__.py
Normal file
0
tests/regressiontests/auth_backends/__init__.py
Normal file
0
tests/regressiontests/auth_backends/models.py
Normal file
0
tests/regressiontests/auth_backends/models.py
Normal file
66
tests/regressiontests/auth_backends/tests.py
Normal file
66
tests/regressiontests/auth_backends/tests.py
Normal file
@ -0,0 +1,66 @@
|
||||
"""
|
||||
>>> from django.contrib.auth.models import User, Group, Permission
|
||||
>>> from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
# No Permissions assigned yet, should return False except for superuser
|
||||
|
||||
>>> user = User.objects.create_user('test', 'test@example.com', 'test')
|
||||
>>> user.has_perm("auth.test")
|
||||
False
|
||||
>>> user.is_staff=True
|
||||
>>> user.save()
|
||||
>>> user.has_perm("auth.test")
|
||||
False
|
||||
>>> user.is_superuser=True
|
||||
>>> user.save()
|
||||
>>> user.has_perm("auth.test")
|
||||
True
|
||||
>>> user.is_staff = False
|
||||
>>> user.is_superuser = False
|
||||
>>> user.save()
|
||||
>>> user.has_perm("auth.test")
|
||||
False
|
||||
>>> content_type=ContentType.objects.get_for_model(Group)
|
||||
>>> perm = Permission.objects.create(name="test", content_type=content_type, codename="test")
|
||||
>>> user.user_permissions.add(perm)
|
||||
>>> user.save()
|
||||
|
||||
# reloading user to purge the _perm_cache
|
||||
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test'])
|
||||
>>> user.get_group_permissions()
|
||||
set([])
|
||||
>>> user.has_module_perms("Group")
|
||||
False
|
||||
>>> user.has_module_perms("auth")
|
||||
True
|
||||
>>> perm = Permission.objects.create(name="test2", content_type=content_type, codename="test2")
|
||||
>>> user.user_permissions.add(perm)
|
||||
>>> user.save()
|
||||
>>> perm = Permission.objects.create(name="test3", content_type=content_type, codename="test3")
|
||||
>>> user.user_permissions.add(perm)
|
||||
>>> user.save()
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test2', u'auth.test', u'auth.test3'])
|
||||
>>> user.has_perm('test')
|
||||
False
|
||||
>>> user.has_perm('auth.test')
|
||||
True
|
||||
>>> user.has_perms(['auth.test2', 'auth.test3'])
|
||||
True
|
||||
>>> perm = Permission.objects.create(name="test_group", content_type=content_type, codename="test_group")
|
||||
>>> group = Group.objects.create(name='test_group')
|
||||
>>> group.permissions.add(perm)
|
||||
>>> group.save()
|
||||
>>> user.groups.add(group)
|
||||
>>> user = User.objects.get(username="test")
|
||||
>>> user.get_all_permissions()
|
||||
set([u'auth.test2', u'auth.test', u'auth.test3', u'auth.test_group'])
|
||||
>>> user.get_group_permissions()
|
||||
set([u'auth.test_group'])
|
||||
>>> user.has_perms(['auth.test3', 'auth.test_group'])
|
||||
True
|
||||
"""
|
@ -1,4 +1,5 @@
|
||||
from django.db import models
|
||||
from django.db import connection
|
||||
|
||||
class Square(models.Model):
|
||||
root = models.IntegerField()
|
||||
@ -7,18 +8,27 @@ class Square(models.Model):
|
||||
def __unicode__(self):
|
||||
return "%s ** 2 == %s" % (self.root, self.square)
|
||||
|
||||
if connection.features.uses_case_insensitive_names:
|
||||
t_convert = lambda x: x.upper()
|
||||
else:
|
||||
t_convert = lambda x: x
|
||||
qn = connection.ops.quote_name
|
||||
|
||||
__test__ = {'API_TESTS': """
|
||||
|
||||
#4896: Test cursor.executemany
|
||||
>>> from django.db import connection
|
||||
>>> cursor = connection.cursor()
|
||||
>>> cursor.executemany('INSERT INTO BACKENDS_SQUARE (ROOT, SQUARE) VALUES (%s, %s)',
|
||||
... [(i, i**2) for i in range(-5, 6)]) and None or None
|
||||
>>> opts = Square._meta
|
||||
>>> f1, f2 = opts.get_field('root'), opts.get_field('square')
|
||||
>>> query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)'
|
||||
... % (t_convert(opts.db_table), qn(f1.column), qn(f2.column)))
|
||||
>>> cursor.executemany(query, [(i, i**2) for i in range(-5, 6)]) and None or None
|
||||
>>> Square.objects.order_by('root')
|
||||
[<Square: -5 ** 2 == 25>, <Square: -4 ** 2 == 16>, <Square: -3 ** 2 == 9>, <Square: -2 ** 2 == 4>, <Square: -1 ** 2 == 1>, <Square: 0 ** 2 == 0>, <Square: 1 ** 2 == 1>, <Square: 2 ** 2 == 4>, <Square: 3 ** 2 == 9>, <Square: 4 ** 2 == 16>, <Square: 5 ** 2 == 25>]
|
||||
|
||||
#4765: executemany with params=[] does nothing
|
||||
>>> cursor.executemany('INSERT INTO BACKENDS_SQUARE (ROOT, SQUARE) VALUES (%s, %s)', []) and None or None
|
||||
>>> cursor.executemany(query, []) and None or None
|
||||
>>> Square.objects.count()
|
||||
11
|
||||
|
||||
|
398
tests/regressiontests/forms/extra.py
Normal file
398
tests/regressiontests/forms/extra.py
Normal file
@ -0,0 +1,398 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
tests = r"""
|
||||
>>> from django.newforms import *
|
||||
>>> import datetime
|
||||
>>> import time
|
||||
>>> import re
|
||||
>>> try:
|
||||
... from decimal import Decimal
|
||||
... except ImportError:
|
||||
... from django.utils._decimal import Decimal
|
||||
|
||||
###############
|
||||
# Extra stuff #
|
||||
###############
|
||||
|
||||
The newforms library comes with some extra, higher-level Field and Widget
|
||||
classes that demonstrate some of the library's abilities.
|
||||
|
||||
# SelectDateWidget ############################################################
|
||||
|
||||
>>> from django.newforms.extras import SelectDateWidget
|
||||
>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
|
||||
>>> print w.render('mydate', '')
|
||||
<select name="mydate_month">
|
||||
<option value="1">January</option>
|
||||
<option value="2">February</option>
|
||||
<option value="3">March</option>
|
||||
<option value="4">April</option>
|
||||
<option value="5">May</option>
|
||||
<option value="6">June</option>
|
||||
<option value="7">July</option>
|
||||
<option value="8">August</option>
|
||||
<option value="9">September</option>
|
||||
<option value="10">October</option>
|
||||
<option value="11">November</option>
|
||||
<option value="12">December</option>
|
||||
</select>
|
||||
<select name="mydate_day">
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="14">14</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="17">17</option>
|
||||
<option value="18">18</option>
|
||||
<option value="19">19</option>
|
||||
<option value="20">20</option>
|
||||
<option value="21">21</option>
|
||||
<option value="22">22</option>
|
||||
<option value="23">23</option>
|
||||
<option value="24">24</option>
|
||||
<option value="25">25</option>
|
||||
<option value="26">26</option>
|
||||
<option value="27">27</option>
|
||||
<option value="28">28</option>
|
||||
<option value="29">29</option>
|
||||
<option value="30">30</option>
|
||||
<option value="31">31</option>
|
||||
</select>
|
||||
<select name="mydate_year">
|
||||
<option value="2007">2007</option>
|
||||
<option value="2008">2008</option>
|
||||
<option value="2009">2009</option>
|
||||
<option value="2010">2010</option>
|
||||
<option value="2011">2011</option>
|
||||
<option value="2012">2012</option>
|
||||
<option value="2013">2013</option>
|
||||
<option value="2014">2014</option>
|
||||
<option value="2015">2015</option>
|
||||
<option value="2016">2016</option>
|
||||
</select>
|
||||
>>> w.render('mydate', None) == w.render('mydate', '')
|
||||
True
|
||||
>>> print w.render('mydate', '2010-04-15')
|
||||
<select name="mydate_month">
|
||||
<option value="1">January</option>
|
||||
<option value="2">February</option>
|
||||
<option value="3">March</option>
|
||||
<option value="4" selected="selected">April</option>
|
||||
<option value="5">May</option>
|
||||
<option value="6">June</option>
|
||||
<option value="7">July</option>
|
||||
<option value="8">August</option>
|
||||
<option value="9">September</option>
|
||||
<option value="10">October</option>
|
||||
<option value="11">November</option>
|
||||
<option value="12">December</option>
|
||||
</select>
|
||||
<select name="mydate_day">
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="14">14</option>
|
||||
<option value="15" selected="selected">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="17">17</option>
|
||||
<option value="18">18</option>
|
||||
<option value="19">19</option>
|
||||
<option value="20">20</option>
|
||||
<option value="21">21</option>
|
||||
<option value="22">22</option>
|
||||
<option value="23">23</option>
|
||||
<option value="24">24</option>
|
||||
<option value="25">25</option>
|
||||
<option value="26">26</option>
|
||||
<option value="27">27</option>
|
||||
<option value="28">28</option>
|
||||
<option value="29">29</option>
|
||||
<option value="30">30</option>
|
||||
<option value="31">31</option>
|
||||
</select>
|
||||
<select name="mydate_year">
|
||||
<option value="2007">2007</option>
|
||||
<option value="2008">2008</option>
|
||||
<option value="2009">2009</option>
|
||||
<option value="2010" selected="selected">2010</option>
|
||||
<option value="2011">2011</option>
|
||||
<option value="2012">2012</option>
|
||||
<option value="2013">2013</option>
|
||||
<option value="2014">2014</option>
|
||||
<option value="2015">2015</option>
|
||||
<option value="2016">2016</option>
|
||||
</select>
|
||||
|
||||
Using a SelectDateWidget in a form:
|
||||
|
||||
>>> class GetDate(Form):
|
||||
... mydate = DateField(widget=SelectDateWidget)
|
||||
>>> a = GetDate({'mydate_month':'4', 'mydate_day':'1', 'mydate_year':'2008'})
|
||||
>>> print a.is_valid()
|
||||
True
|
||||
>>> print a.cleaned_data['mydate']
|
||||
2008-04-01
|
||||
|
||||
As with any widget that implements get_value_from_datadict,
|
||||
we must be prepared to accept the input from the "as_hidden"
|
||||
rendering as well.
|
||||
|
||||
>>> print a['mydate'].as_hidden()
|
||||
<input type="hidden" name="mydate" value="2008-4-1" id="id_mydate" />
|
||||
>>> b=GetDate({'mydate':'2008-4-1'})
|
||||
>>> print b.is_valid()
|
||||
True
|
||||
>>> print b.cleaned_data['mydate']
|
||||
2008-04-01
|
||||
|
||||
|
||||
# MultiWidget and MultiValueField #############################################
|
||||
# MultiWidgets are widgets composed of other widgets. They are usually
|
||||
# combined with MultiValueFields - a field that is composed of other fields.
|
||||
# MulitWidgets can themselved be composed of other MultiWidgets.
|
||||
# SplitDateTimeWidget is one example of a MultiWidget.
|
||||
|
||||
>>> class ComplexMultiWidget(MultiWidget):
|
||||
... def __init__(self, attrs=None):
|
||||
... widgets = (
|
||||
... TextInput(),
|
||||
... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
|
||||
... SplitDateTimeWidget(),
|
||||
... )
|
||||
... super(ComplexMultiWidget, self).__init__(widgets, attrs)
|
||||
...
|
||||
... def decompress(self, value):
|
||||
... if value:
|
||||
... data = value.split(',')
|
||||
... return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])]
|
||||
... return [None, None, None]
|
||||
... def format_output(self, rendered_widgets):
|
||||
... return u'\n'.join(rendered_widgets)
|
||||
>>> w = ComplexMultiWidget()
|
||||
>>> print w.render('name', 'some text,JP,2007-04-25 06:24:00')
|
||||
<input type="text" name="name_0" value="some text" />
|
||||
<select multiple="multiple" name="name_1">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
<input type="text" name="name_2_0" value="2007-04-25" /><input type="text" name="name_2_1" value="06:24:00" />
|
||||
|
||||
>>> class ComplexField(MultiValueField):
|
||||
... def __init__(self, required=True, widget=None, label=None, initial=None):
|
||||
... fields = (
|
||||
... CharField(),
|
||||
... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
|
||||
... SplitDateTimeField()
|
||||
... )
|
||||
... super(ComplexField, self).__init__(fields, required, widget, label, initial)
|
||||
...
|
||||
... def compress(self, data_list):
|
||||
... if data_list:
|
||||
... return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2])
|
||||
... return None
|
||||
|
||||
>>> f = ComplexField(widget=w)
|
||||
>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']])
|
||||
u'some text,JP,2007-04-25 06:24:00'
|
||||
>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']])
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Select a valid choice. X is not one of the available choices.']
|
||||
|
||||
# If insufficient data is provided, None is substituted
|
||||
>>> f.clean(['some text',['JP']])
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> class ComplexFieldForm(Form):
|
||||
... field1 = ComplexField(widget=w)
|
||||
>>> f = ComplexFieldForm()
|
||||
>>> print f
|
||||
<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" id="id_field1_0" />
|
||||
<select multiple="multiple" name="field1_1" id="id_field1_1">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
<input type="text" name="field1_2_0" id="id_field1_2_0" /><input type="text" name="field1_2_1" id="id_field1_2_1" /></td></tr>
|
||||
|
||||
>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
|
||||
>>> print f
|
||||
<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" value="some text" id="id_field1_0" />
|
||||
<select multiple="multiple" name="field1_1" id="id_field1_1">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
|
||||
|
||||
>>> f.cleaned_data
|
||||
{'field1': u'some text,JP,2007-04-25 06:24:00'}
|
||||
|
||||
|
||||
# IPAddressField ##################################################################
|
||||
|
||||
>>> f = IPAddressField()
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('127.0.0.1')
|
||||
u'127.0.0.1'
|
||||
>>> f.clean('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('127.0.0.')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('1.2.3.4.5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('256.125.1.5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
|
||||
>>> f = IPAddressField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('127.0.0.1')
|
||||
u'127.0.0.1'
|
||||
>>> f.clean('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('127.0.0.')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('1.2.3.4.5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
>>> f.clean('256.125.1.5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid IPv4 address.']
|
||||
|
||||
#################################
|
||||
# Tests of underlying functions #
|
||||
#################################
|
||||
|
||||
# smart_unicode tests
|
||||
>>> from django.utils.encoding import smart_unicode
|
||||
>>> class Test:
|
||||
... def __str__(self):
|
||||
... return 'ŠĐĆŽćžšđ'
|
||||
>>> class TestU:
|
||||
... def __str__(self):
|
||||
... return 'Foo'
|
||||
... def __unicode__(self):
|
||||
... return u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
|
||||
>>> smart_unicode(Test())
|
||||
u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
|
||||
>>> smart_unicode(TestU())
|
||||
u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
|
||||
>>> smart_unicode(1)
|
||||
u'1'
|
||||
>>> smart_unicode('foo')
|
||||
u'foo'
|
||||
|
||||
|
||||
####################################
|
||||
# Test accessing errors in clean() #
|
||||
####################################
|
||||
|
||||
>>> class UserForm(Form):
|
||||
... username = CharField(max_length=10)
|
||||
... password = CharField(widget=PasswordInput)
|
||||
... def clean(self):
|
||||
... data = self.cleaned_data
|
||||
... if not self.errors:
|
||||
... data['username'] = data['username'].lower()
|
||||
... return data
|
||||
|
||||
>>> f = UserForm({'username': 'SirRobin', 'password': 'blue'})
|
||||
>>> f.is_valid()
|
||||
True
|
||||
>>> f.cleaned_data['username']
|
||||
u'sirrobin'
|
||||
|
||||
#######################################
|
||||
# Test overriding ErrorList in a form #
|
||||
#######################################
|
||||
|
||||
>>> from django.newforms.util import ErrorList
|
||||
>>> class DivErrorList(ErrorList):
|
||||
... def __unicode__(self):
|
||||
... return self.as_divs()
|
||||
... def as_divs(self):
|
||||
... if not self: return u''
|
||||
... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
|
||||
>>> class CommentForm(Form):
|
||||
... name = CharField(max_length=50, required=False)
|
||||
... email = EmailField()
|
||||
... comment = CharField()
|
||||
>>> data = dict(email='invalid')
|
||||
>>> f = CommentForm(data, auto_id=False, error_class=DivErrorList)
|
||||
>>> print f.as_p()
|
||||
<p>Name: <input type="text" name="name" maxlength="50" /></p>
|
||||
<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
|
||||
<p>Email: <input type="text" name="email" value="invalid" /></p>
|
||||
<div class="errorlist"><div class="error">This field is required.</div></div>
|
||||
<p>Comment: <input type="text" name="comment" /></p>
|
||||
|
||||
#################################
|
||||
# Test multipart-encoded form #
|
||||
#################################
|
||||
|
||||
>>> class FormWithoutFile(Form):
|
||||
... username = CharField()
|
||||
>>> class FormWithFile(Form):
|
||||
... username = CharField()
|
||||
... file = FileField()
|
||||
>>> class FormWithImage(Form):
|
||||
... image = ImageField()
|
||||
|
||||
>>> FormWithoutFile().is_multipart()
|
||||
False
|
||||
>>> FormWithFile().is_multipart()
|
||||
True
|
||||
>>> FormWithImage().is_multipart()
|
||||
True
|
||||
|
||||
"""
|
1162
tests/regressiontests/forms/fields.py
Normal file
1162
tests/regressiontests/forms/fields.py
Normal file
File diff suppressed because it is too large
Load Diff
1606
tests/regressiontests/forms/forms.py
Normal file
1606
tests/regressiontests/forms/forms.py
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1
tests/regressiontests/forms/localflavor/__init__.py
Normal file
1
tests/regressiontests/forms/localflavor/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
294
tests/regressiontests/forms/localflavor/ar.py
Normal file
294
tests/regressiontests/forms/localflavor/ar.py
Normal file
@ -0,0 +1,294 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ AR form fields.
|
||||
|
||||
tests = r"""
|
||||
# ARProvinceField #############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ar.forms import ARProvinceSelect
|
||||
>>> f = ARProvinceSelect()
|
||||
>>> f.render('provincias', 'A')
|
||||
u'<select name="provincias">\n<option value="B">Buenos Aires</option>\n<option value="K">Catamarca</option>\n<option value="H">Chaco</option>\n<option value="U">Chubut</option>\n<option value="C">Ciudad Aut\xf3noma de Buenos Aires</option>\n<option value="X">C\xf3rdoba</option>\n<option value="W">Corrientes</option>\n<option value="E">Entre R\xedos</option>\n<option value="P">Formosa</option>\n<option value="Y">Jujuy</option>\n<option value="L">La Pampa</option>\n<option value="F">La Rioja</option>\n<option value="M">Mendoza</option>\n<option value="N">Misiones</option>\n<option value="Q">Neuqu\xe9n</option>\n<option value="R">R\xedo Negro</option>\n<option value="A" selected="selected">Salta</option>\n<option value="J">San Juan</option>\n<option value="D">San Luis</option>\n<option value="Z">Santa Cruz</option>\n<option value="S">Santa Fe</option>\n<option value="G">Santiago del Estero</option>\n<option value="V">Tierra del Fuego, Ant\xe1rtida e Islas del Atl\xe1ntico Sur</option>\n<option value="T">Tucum\xe1n</option>\n</select>'
|
||||
|
||||
# ARPostalCodeField ###########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ar.forms import ARPostalCodeField
|
||||
>>> f = ARPostalCodeField()
|
||||
>>> f.clean('5000')
|
||||
u'5000'
|
||||
>>> f.clean('C1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('c1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('C1064aab')
|
||||
u'C1064AAB'
|
||||
>>> f.clean(u'4400')
|
||||
u'4400'
|
||||
>>> f.clean(u'C1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('C1064AABB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
|
||||
>>> f.clean('C1064AA')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('C106AAB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('106AAB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('500')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
|
||||
>>> f.clean('5PPP')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(u'')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = ARPostalCodeField(required=False)
|
||||
>>> f.clean('5000')
|
||||
u'5000'
|
||||
>>> f.clean('C1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('c1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('C1064aab')
|
||||
u'C1064AAB'
|
||||
>>> f.clean(u'4400')
|
||||
u'4400'
|
||||
>>> f.clean(u'C1064AAB')
|
||||
u'C1064AAB'
|
||||
>>> f.clean('C1064AABB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
|
||||
>>> f.clean('C1064AA')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('C106AAB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('106AAB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean('500')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
|
||||
>>> f.clean('5PPP')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(u'')
|
||||
u''
|
||||
|
||||
# ARDNIField ##################################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ar.forms import ARDNIField
|
||||
>>> f = ARDNIField()
|
||||
>>> f.clean('20123456')
|
||||
u'20123456'
|
||||
>>> f.clean('20.123.456')
|
||||
u'20123456'
|
||||
>>> f.clean('9123456')
|
||||
u'9123456'
|
||||
>>> f.clean('9.123.456')
|
||||
u'9123456'
|
||||
>>> f.clean(u'20123456')
|
||||
u'20123456'
|
||||
>>> f.clean(u'20.123.456')
|
||||
u'20123456'
|
||||
>>> f.clean('20.123456')
|
||||
u'20123456'
|
||||
>>> f.clean('101234566')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires 7 or 8 digits.']
|
||||
>>> f.clean('W0123456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f.clean('10,123,456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(u'')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = ARDNIField(required=False)
|
||||
>>> f.clean('20123456')
|
||||
u'20123456'
|
||||
>>> f.clean('20.123.456')
|
||||
u'20123456'
|
||||
>>> f.clean('9123456')
|
||||
u'9123456'
|
||||
>>> f.clean('9.123.456')
|
||||
u'9123456'
|
||||
>>> f.clean(u'20123456')
|
||||
u'20123456'
|
||||
>>> f.clean(u'20.123.456')
|
||||
u'20123456'
|
||||
>>> f.clean('20.123456')
|
||||
u'20123456'
|
||||
>>> f.clean('101234566')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires 7 or 8 digits.']
|
||||
>>> f.clean('W0123456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f.clean('10,123,456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(u'')
|
||||
u''
|
||||
|
||||
# ARCUITField #################################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ar.forms import ARCUITField
|
||||
>>> f = ARCUITField()
|
||||
>>> f.clean('20-10123456-9')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean(u'20-10123456-9')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean('27-10345678-4')
|
||||
u'27-10345678-4'
|
||||
>>> f.clean('20101234569')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean('27103456784')
|
||||
u'27-10345678-4'
|
||||
>>> f.clean('2-10123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('210123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456-5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(u'2-10123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('27-10345678-1')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(u'27-10345678-1')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(u'')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = ARCUITField(required=False)
|
||||
>>> f.clean('20-10123456-9')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean(u'20-10123456-9')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean('27-10345678-4')
|
||||
u'27-10345678-4'
|
||||
>>> f.clean('20101234569')
|
||||
u'20-10123456-9'
|
||||
>>> f.clean('27103456784')
|
||||
u'27-10345678-4'
|
||||
>>> f.clean('2-10123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('210123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('20-10123456-5')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(u'2-10123456-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||
>>> f.clean('27-10345678-1')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(u'27-10345678-1')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CUIT.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(u'')
|
||||
u''
|
||||
"""
|
134
tests/regressiontests/forms/localflavor/au.py
Normal file
134
tests/regressiontests/forms/localflavor/au.py
Normal file
@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ AU form fields.
|
||||
|
||||
tests = r"""
|
||||
## AUPostCodeField ##########################################################
|
||||
|
||||
A field that accepts a four digit Australian post code.
|
||||
|
||||
>>> from django.contrib.localflavor.au.forms import AUPostCodeField
|
||||
>>> f = AUPostCodeField()
|
||||
>>> f.clean('1234')
|
||||
u'1234'
|
||||
>>> f.clean('2000')
|
||||
u'2000'
|
||||
>>> f.clean('abcd')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a 4 digit post code.']
|
||||
>>> f.clean('20001')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a 4 digit post code.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = AUPostCodeField(required=False)
|
||||
>>> f.clean('1234')
|
||||
u'1234'
|
||||
>>> f.clean('2000')
|
||||
u'2000'
|
||||
>>> f.clean('abcd')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a 4 digit post code.']
|
||||
>>> f.clean('20001')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a 4 digit post code.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
## AUPhoneNumberField ########################################################
|
||||
|
||||
A field that accepts a 10 digit Australian phone number.
|
||||
llows spaces and parentheses around area code.
|
||||
|
||||
>>> from django.contrib.localflavor.au.forms import AUPhoneNumberField
|
||||
>>> f = AUPhoneNumberField()
|
||||
>>> f.clean('1234567890')
|
||||
u'1234567890'
|
||||
>>> f.clean('0213456789')
|
||||
u'0213456789'
|
||||
>>> f.clean('02 13 45 67 89')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02) 1345 6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02) 1345-6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02)1345-6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('0408 123 456')
|
||||
u'0408123456'
|
||||
>>> f.clean('123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must contain 10 digits.']
|
||||
>>> f.clean('1800DJANGO')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must contain 10 digits.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = AUPhoneNumberField(required=False)
|
||||
>>> f.clean('1234567890')
|
||||
u'1234567890'
|
||||
>>> f.clean('0213456789')
|
||||
u'0213456789'
|
||||
>>> f.clean('02 13 45 67 89')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02) 1345 6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02) 1345-6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('(02)1345-6789')
|
||||
u'0213456789'
|
||||
>>> f.clean('0408 123 456')
|
||||
u'0408123456'
|
||||
>>> f.clean('123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must contain 10 digits.']
|
||||
>>> f.clean('1800DJANGO')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must contain 10 digits.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
## AUStateSelect #############################################################
|
||||
|
||||
AUStateSelect is a Select widget that uses a list of Australian
|
||||
states/territories as its choices.
|
||||
|
||||
>>> from django.contrib.localflavor.au.forms import AUStateSelect
|
||||
>>> f = AUStateSelect()
|
||||
>>> print f.render('state', 'NSW')
|
||||
<select name="state">
|
||||
<option value="ACT">Australian Capital Territory</option>
|
||||
<option value="NSW" selected="selected">New South Wales</option>
|
||||
<option value="NT">Northern Territory</option>
|
||||
<option value="QLD">Queensland</option>
|
||||
<option value="SA">South Australia</option>
|
||||
<option value="TAS">Tasmania</option>
|
||||
<option value="VIC">Victoria</option>
|
||||
<option value="WA">Western Australia</option>
|
||||
</select>
|
||||
"""
|
220
tests/regressiontests/forms/localflavor/br.py
Normal file
220
tests/regressiontests/forms/localflavor/br.py
Normal file
@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ BR form fields.
|
||||
|
||||
tests = r"""
|
||||
# BRZipCodeField ############################################################
|
||||
>>> from django.contrib.localflavor.br.forms import BRZipCodeField
|
||||
>>> f = BRZipCodeField()
|
||||
>>> f.clean('12345-123')
|
||||
u'12345-123'
|
||||
>>> f.clean('12345_123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('1234-123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('abcde-abc')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('12345-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('-123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = BRZipCodeField(required=False)
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean('-123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('12345-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('abcde-abc')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('1234-123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('12345_123')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
|
||||
>>> f.clean('12345-123')
|
||||
u'12345-123'
|
||||
|
||||
# BRCNPJField ############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.br.forms import BRCNPJField
|
||||
>>> f = BRCNPJField(required=True)
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('12-345-678/9012-10')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CNPJ number.']
|
||||
>>> f.clean('12.345.678/9012-10')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CNPJ number.']
|
||||
>>> f.clean('12345678/9012-10')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CNPJ number.']
|
||||
>>> f.clean('64.132.916/0001-88')
|
||||
'64.132.916/0001-88'
|
||||
>>> f.clean('64-132-916/0001-88')
|
||||
'64-132-916/0001-88'
|
||||
>>> f.clean('64132916/0001-88')
|
||||
'64132916/0001-88'
|
||||
>>> f.clean('64.132.916/0001-XX')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f = BRCNPJField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# BRCPFField #################################################################
|
||||
|
||||
>>> from django.contrib.localflavor.br.forms import BRCPFField
|
||||
>>> f = BRCPFField()
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('489.294.654-54')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CPF number.']
|
||||
>>> f.clean('295.669.575-98')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CPF number.']
|
||||
>>> f.clean('539.315.127-22')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Invalid CPF number.']
|
||||
>>> f.clean('663.256.017-26')
|
||||
u'663.256.017-26'
|
||||
>>> f.clean('66325601726')
|
||||
u'66325601726'
|
||||
>>> f.clean('375.788.573-20')
|
||||
u'375.788.573-20'
|
||||
>>> f.clean('84828509895')
|
||||
u'84828509895'
|
||||
>>> f.clean('375.788.573-XX')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires only numbers.']
|
||||
>>> f.clean('375.788.573-000')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at most 14 characters (it has 15).']
|
||||
>>> f.clean('123.456.78')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Ensure this value has at least 11 characters (it has 10).']
|
||||
>>> f.clean('123456789555')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field requires at most 11 digits or 14 characters.']
|
||||
>>> f = BRCPFField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
|
||||
# BRPhoneNumberField #########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.br.forms import BRPhoneNumberField
|
||||
>>> f = BRPhoneNumberField()
|
||||
>>> f.clean('41-3562-3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('4135623464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41 3562-3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41 3562 3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('(41) 3562 3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41.3562.3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41.3562-3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean(' (41) 3562.3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = BRPhoneNumberField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean(' (41) 3562.3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41.3562-3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('(41) 3562 3464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('4135623464')
|
||||
u'41-3562-3464'
|
||||
>>> f.clean('41 3562-3464')
|
||||
u'41-3562-3464'
|
||||
|
||||
# BRStateSelect ##############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.br.forms import BRStateSelect
|
||||
>>> w = BRStateSelect()
|
||||
>>> w.render('states', 'PR')
|
||||
u'<select name="states">\n<option value="AC">Acre</option>\n<option value="AL">Alagoas</option>\n<option value="AP">Amap\xe1</option>\n<option value="AM">Amazonas</option>\n<option value="BA">Bahia</option>\n<option value="CE">Cear\xe1</option>\n<option value="DF">Distrito Federal</option>\n<option value="ES">Esp\xedrito Santo</option>\n<option value="GO">Goi\xe1s</option>\n<option value="MA">Maranh\xe3o</option>\n<option value="MT">Mato Grosso</option>\n<option value="MS">Mato Grosso do Sul</option>\n<option value="MG">Minas Gerais</option>\n<option value="PA">Par\xe1</option>\n<option value="PB">Para\xedba</option>\n<option value="PR" selected="selected">Paran\xe1</option>\n<option value="PE">Pernambuco</option>\n<option value="PI">Piau\xed</option>\n<option value="RJ">Rio de Janeiro</option>\n<option value="RN">Rio Grande do Norte</option>\n<option value="RS">Rio Grande do Sul</option>\n<option value="RO">Rond\xf4nia</option>\n<option value="RR">Roraima</option>\n<option value="SC">Santa Catarina</option>\n<option value="SP">S\xe3o Paulo</option>\n<option value="SE">Sergipe</option>\n<option value="TO">Tocantins</option>\n</select>'
|
||||
|
||||
# BRStateChoiceField #########################################################
|
||||
>>> from django.contrib.localflavor.br.forms import BRStateChoiceField
|
||||
>>> f = BRStateChoiceField()
|
||||
>>> ', '.join([f.clean(s) for s, _ in f.widget.choices])
|
||||
u'AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO'
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('pr')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Select a valid brazilian state. That state is not one of the available states.']
|
||||
"""
|
221
tests/regressiontests/forms/localflavor/ca.py
Normal file
221
tests/regressiontests/forms/localflavor/ca.py
Normal file
@ -0,0 +1,221 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ CA form fields.
|
||||
|
||||
tests = r"""
|
||||
# CAPostalCodeField ##############################################################
|
||||
|
||||
CAPostalCodeField validates that the data is a six-character Canadian postal code.
|
||||
>>> from django.contrib.localflavor.ca.forms import CAPostalCodeField
|
||||
>>> f = CAPostalCodeField()
|
||||
>>> f.clean('T2S 2H7')
|
||||
u'T2S 2H7'
|
||||
>>> f.clean('T2S 2H')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean('2T6 H8I')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean('T2S2H')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean(90210)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f = CAPostalCodeField(required=False)
|
||||
>>> f.clean('T2S 2H7')
|
||||
u'T2S 2H7'
|
||||
>>> f.clean('T2S2H7')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean('T2S 2H')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean('2T6 H8I')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean('T2S2H')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean(90210)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXX XXX.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# CAPhoneNumberField ##########################################################
|
||||
|
||||
CAPhoneNumberField validates that the data is a valid Canadian phone number,
|
||||
including the area code. It's normalized to XXX-XXX-XXXX format.
|
||||
Note: This test is exactly the same as the USPhoneNumberField except using a real
|
||||
Candian area code
|
||||
|
||||
>>> from django.contrib.localflavor.ca.forms import CAPhoneNumberField
|
||||
>>> f = CAPhoneNumberField()
|
||||
>>> f.clean('403-555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('4035551212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403 555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('(403) 555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403 555 1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403.555.1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403.555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean(' (403) 555.1212 ')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('555-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('403-55-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = CAPhoneNumberField(required=False)
|
||||
>>> f.clean('403-555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('4035551212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403 555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('(403) 555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403 555 1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403.555.1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('403.555-1212')
|
||||
u'403-555-1212'
|
||||
>>> f.clean(' (403) 555.1212 ')
|
||||
u'403-555-1212'
|
||||
>>> f.clean('555-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('403-55-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# CAProvinceField ################################################################
|
||||
|
||||
CAProvinceField validates that the data is either an abbreviation or name of a
|
||||
Canadian province.
|
||||
>>> from django.contrib.localflavor.ca.forms import CAProvinceField
|
||||
>>> f = CAProvinceField()
|
||||
>>> f.clean('ab')
|
||||
u'AB'
|
||||
>>> f.clean('BC')
|
||||
u'BC'
|
||||
>>> f.clean('nova scotia')
|
||||
u'NS'
|
||||
>>> f.clean(' manitoba ')
|
||||
u'MB'
|
||||
>>> f.clean('T2S 2H7')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a Canadian province or territory.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = CAProvinceField(required=False)
|
||||
>>> f.clean('ab')
|
||||
u'AB'
|
||||
>>> f.clean('BC')
|
||||
u'BC'
|
||||
>>> f.clean('nova scotia')
|
||||
u'NS'
|
||||
>>> f.clean(' manitoba ')
|
||||
u'MB'
|
||||
>>> f.clean('T2S 2H7')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a Canadian province or territory.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# CAProvinceSelect ###############################################################
|
||||
|
||||
CAProvinceSelect is a Select widget that uses a list of Canadian provinces/territories
|
||||
as its choices.
|
||||
>>> from django.contrib.localflavor.ca.forms import CAProvinceSelect
|
||||
>>> w = CAProvinceSelect()
|
||||
>>> print w.render('province', 'AB')
|
||||
<select name="province">
|
||||
<option value="AB" selected="selected">Alberta</option>
|
||||
<option value="BC">British Columbia</option>
|
||||
<option value="MB">Manitoba</option>
|
||||
<option value="NB">New Brunswick</option>
|
||||
<option value="NF">Newfoundland and Labrador</option>
|
||||
<option value="NT">Northwest Territories</option>
|
||||
<option value="NS">Nova Scotia</option>
|
||||
<option value="NU">Nunavut</option>
|
||||
<option value="ON">Ontario</option>
|
||||
<option value="PE">Prince Edward Island</option>
|
||||
<option value="QC">Quebec</option>
|
||||
<option value="SK">Saskatchewan</option>
|
||||
<option value="YK">Yukon</option>
|
||||
</select>
|
||||
|
||||
# CASocialInsuranceNumberField #################################################
|
||||
>>> from django.contrib.localflavor.ca.forms import CASocialInsuranceNumberField
|
||||
>>> f = CASocialInsuranceNumberField()
|
||||
>>> f.clean('046-454-286')
|
||||
u'046-454-286'
|
||||
>>> f.clean('046-454-287')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('046 454 286')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('046-44-286')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
|
||||
"""
|
58
tests/regressiontests/forms/localflavor/ch.py
Normal file
58
tests/regressiontests/forms/localflavor/ch.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ CH form fields.
|
||||
|
||||
tests = r"""
|
||||
# CHZipCodeField ############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ch.forms import CHZipCodeField
|
||||
>>> f = CHZipCodeField()
|
||||
>>> f.clean('800x')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXX.']
|
||||
>>> f.clean('80 00')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXX.']
|
||||
>>> f.clean('8000')
|
||||
u'8000'
|
||||
|
||||
# CHPhoneNumberField ########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ch.forms import CHPhoneNumberField
|
||||
>>> f = CHPhoneNumberField()
|
||||
>>> f.clean('01234567890')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
|
||||
>>> f.clean('1234567890')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
|
||||
>>> f.clean('0123456789')
|
||||
u'012 345 67 89'
|
||||
|
||||
# CHIdentityCardNumberField #################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ch.forms import CHIdentityCardNumberField
|
||||
>>> f = CHIdentityCardNumberField()
|
||||
>>> f.clean('C1234567<0')
|
||||
u'C1234567<0'
|
||||
>>> f.clean('C1234567<1')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
|
||||
>>> f.clean('2123456700')
|
||||
u'2123456700'
|
||||
>>> f.clean('2123456701')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
|
||||
|
||||
# CHStateSelect #############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.ch.forms import CHStateSelect
|
||||
>>> w = CHStateSelect()
|
||||
>>> w.render('state', 'AG')
|
||||
u'<select name="state">\n<option value="AG" selected="selected">Aargau</option>\n<option value="AI">Appenzell Innerrhoden</option>\n<option value="AR">Appenzell Ausserrhoden</option>\n<option value="BS">Basel-Stadt</option>\n<option value="BL">Basel-Land</option>\n<option value="BE">Berne</option>\n<option value="FR">Fribourg</option>\n<option value="GE">Geneva</option>\n<option value="GL">Glarus</option>\n<option value="GR">Graubuenden</option>\n<option value="JU">Jura</option>\n<option value="LU">Lucerne</option>\n<option value="NE">Neuchatel</option>\n<option value="NW">Nidwalden</option>\n<option value="OW">Obwalden</option>\n<option value="SH">Schaffhausen</option>\n<option value="SZ">Schwyz</option>\n<option value="SO">Solothurn</option>\n<option value="SG">St. Gallen</option>\n<option value="TG">Thurgau</option>\n<option value="TI">Ticino</option>\n<option value="UR">Uri</option>\n<option value="VS">Valais</option>\n<option value="VD">Vaud</option>\n<option value="ZG">Zug</option>\n<option value="ZH">Zurich</option>\n</select>'
|
||||
"""
|
74
tests/regressiontests/forms/localflavor/cl.py
Normal file
74
tests/regressiontests/forms/localflavor/cl.py
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
# Tests for the contrib/localflavor/ CL form fields.
|
||||
|
||||
tests = r"""
|
||||
## CLRutField #############################################################
|
||||
|
||||
CLRutField is a Field that checks the validity of the Chilean
|
||||
personal identification number (RUT). It has two modes relaxed (default) and
|
||||
strict.
|
||||
|
||||
>>> from django.contrib.localflavor.cl.forms import CLRutField
|
||||
>>> rut = CLRutField()
|
||||
|
||||
>>> rut.clean('11-6')
|
||||
u'11-6'
|
||||
>>> rut.clean('116')
|
||||
u'11-6'
|
||||
|
||||
# valid format, bad verifier.
|
||||
>>> rut.clean('11.111.111-0')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'The Chilean RUT is not valid.']
|
||||
>>> rut.clean('111')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'The Chilean RUT is not valid.']
|
||||
|
||||
>>> rut.clean('767484100')
|
||||
u'76.748.410-0'
|
||||
>>> rut.clean('78.412.790-7')
|
||||
u'78.412.790-7'
|
||||
>>> rut.clean('8.334.6043')
|
||||
u'8.334.604-3'
|
||||
>>> rut.clean('76793310-K')
|
||||
u'76.793.310-K'
|
||||
|
||||
Strict RUT usage (does not allow imposible values)
|
||||
>>> rut = CLRutField(strict=True)
|
||||
|
||||
>>> rut.clean('11-6')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
|
||||
|
||||
# valid format, bad verifier.
|
||||
>>> rut.clean('11.111.111-0')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'The Chilean RUT is not valid.']
|
||||
|
||||
# Correct input, invalid format.
|
||||
>>> rut.clean('767484100')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
|
||||
>>> rut.clean('78.412.790-7')
|
||||
u'78.412.790-7'
|
||||
>>> rut.clean('8.334.6043')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
|
||||
>>> rut.clean('76793310-K')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
|
||||
|
||||
## CLRegionSelect #########################################################
|
||||
>>> from django.contrib.localflavor.cl.forms import CLRegionSelect
|
||||
>>> f = CLRegionSelect()
|
||||
|
||||
>>> f.render('foo', 'bar')
|
||||
u'<select name="foo">\n<option value="RM">Regi\xf3n Metropolitana de Santiago</option>\n<option value="I">Regi\xf3n de Tarapac\xe1</option>\n<option value="II">Regi\xf3n de Antofagasta</option>\n<option value="III">Regi\xf3n de Atacama</option>\n<option value="IV">Regi\xf3n de Coquimbo</option>\n<option value="V">Regi\xf3n de Valpara\xedso</option>\n<option value="VI">Regi\xf3n del Libertador Bernardo O'Higgins</option>\n<option value="VII">Regi\xf3n del Maule</option>\n<option value="VIII">Regi\xf3n del B\xedo B\xedo</option>\n<option value="IX">Regi\xf3n de la Araucan\xeda</option>\n<option value="X">Regi\xf3n de los Lagos</option>\n<option value="XI">Regi\xf3n de Ays\xe9n del General Carlos Ib\xe1\xf1ez del Campo</option>\n<option value="XII">Regi\xf3n de Magallanes y la Ant\xe1rtica Chilena</option>\n<option value="XIV">Regi\xf3n de Los R\xedos</option>\n<option value="XV">Regi\xf3n de Arica-Parinacota</option>\n</select>'
|
||||
"""
|
35
tests/regressiontests/forms/localflavor/de.py
Normal file
35
tests/regressiontests/forms/localflavor/de.py
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ DE form fields.
|
||||
|
||||
tests = r"""
|
||||
# DEZipCodeField ##############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.de.forms import DEZipCodeField
|
||||
>>> f = DEZipCodeField()
|
||||
>>> f.clean('99423')
|
||||
u'99423'
|
||||
>>> f.clean(' 99423')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX.']
|
||||
|
||||
# DEStateSelect #############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.de.forms import DEStateSelect
|
||||
>>> w = DEStateSelect()
|
||||
>>> w.render('states', 'TH')
|
||||
u'<select name="states">\n<option value="BW">Baden-Wuerttemberg</option>\n<option value="BY">Bavaria</option>\n<option value="BE">Berlin</option>\n<option value="BB">Brandenburg</option>\n<option value="HB">Bremen</option>\n<option value="HH">Hamburg</option>\n<option value="HE">Hessen</option>\n<option value="MV">Mecklenburg-Western Pomerania</option>\n<option value="NI">Lower Saxony</option>\n<option value="NW">North Rhine-Westphalia</option>\n<option value="RP">Rhineland-Palatinate</option>\n<option value="SL">Saarland</option>\n<option value="SN">Saxony</option>\n<option value="ST">Saxony-Anhalt</option>\n<option value="SH">Schleswig-Holstein</option>\n<option value="TH" selected="selected">Thuringia</option>\n</select>'
|
||||
|
||||
# DEIdentityCardNumberField #################################################
|
||||
|
||||
>>> from django.contrib.localflavor.de.forms import DEIdentityCardNumberField
|
||||
>>> f = DEIdentityCardNumberField()
|
||||
>>> f.clean('7549313035D-6004103-0903042-0')
|
||||
u'7549313035D-6004103-0903042-0'
|
||||
>>> f.clean('9786324830D 6104243 0910271 2')
|
||||
u'9786324830D-6104243-0910271-2'
|
||||
>>> f.clean('0434657485D-6407276-0508137-9')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.']
|
||||
"""
|
99
tests/regressiontests/forms/localflavor/fi.py
Normal file
99
tests/regressiontests/forms/localflavor/fi.py
Normal file
File diff suppressed because one or more lines are too long
224
tests/regressiontests/forms/localflavor/fr.py
Normal file
224
tests/regressiontests/forms/localflavor/fr.py
Normal file
@ -0,0 +1,224 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ FR form fields.
|
||||
|
||||
tests = r"""
|
||||
# FRZipCodeField #############################################################
|
||||
|
||||
FRZipCodeField validates that the data is a valid FR zipcode.
|
||||
>>> from django.contrib.localflavor.fr.forms import FRZipCodeField
|
||||
>>> f = FRZipCodeField()
|
||||
>>> f.clean('75001')
|
||||
u'75001'
|
||||
>>> f.clean('93200')
|
||||
u'93200'
|
||||
>>> f.clean('2A200')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX.']
|
||||
>>> f.clean('980001')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = FRZipCodeField(required=False)
|
||||
>>> f.clean('75001')
|
||||
u'75001'
|
||||
>>> f.clean('93200')
|
||||
u'93200'
|
||||
>>> f.clean('2A200')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX.']
|
||||
>>> f.clean('980001')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
|
||||
# FRPhoneNumberField ##########################################################
|
||||
|
||||
FRPhoneNumberField validates that the data is a valid french phone number.
|
||||
It's normalized to 0X XX XX XX XX format. Dots are valid too.
|
||||
>>> from django.contrib.localflavor.fr.forms import FRPhoneNumberField
|
||||
>>> f = FRPhoneNumberField()
|
||||
>>> f.clean('01 55 44 58 64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('0155445864')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01 5544 5864')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01 55.44.58.64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01.55.44.58.64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01,55,44,58,64')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
|
||||
>>> f.clean('555 015 544')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = FRPhoneNumberField(required=False)
|
||||
>>> f.clean('01 55 44 58 64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('0155445864')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01 5544 5864')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01 55.44.58.64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01.55.44.58.64')
|
||||
u'01 55 44 58 64'
|
||||
>>> f.clean('01,55,44,58,64')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
|
||||
>>> f.clean('555 015 544')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# FRDepartmentSelect ###############################################################
|
||||
|
||||
FRDepartmentSelect is a Select widget that uses a list of french departments
|
||||
including DOM TOM
|
||||
>>> from django.contrib.localflavor.fr.forms import FRDepartmentSelect
|
||||
>>> w = FRDepartmentSelect()
|
||||
>>> print w.render('dep', 'Paris')
|
||||
<select name="dep">
|
||||
<option value="01">01 - Ain</option>
|
||||
<option value="02">02 - Aisne</option>
|
||||
<option value="03">03 - Allier</option>
|
||||
<option value="04">04 - Alpes-de-Haute-Provence</option>
|
||||
<option value="05">05 - Hautes-Alpes</option>
|
||||
<option value="06">06 - Alpes-Maritimes</option>
|
||||
<option value="07">07 - Ardeche</option>
|
||||
<option value="08">08 - Ardennes</option>
|
||||
<option value="09">09 - Ariege</option>
|
||||
<option value="10">10 - Aube</option>
|
||||
<option value="11">11 - Aude</option>
|
||||
<option value="12">12 - Aveyron</option>
|
||||
<option value="13">13 - Bouches-du-Rhone</option>
|
||||
<option value="14">14 - Calvados</option>
|
||||
<option value="15">15 - Cantal</option>
|
||||
<option value="16">16 - Charente</option>
|
||||
<option value="17">17 - Charente-Maritime</option>
|
||||
<option value="18">18 - Cher</option>
|
||||
<option value="19">19 - Correze</option>
|
||||
<option value="21">21 - Cote-d'Or</option>
|
||||
<option value="22">22 - Cotes-d'Armor</option>
|
||||
<option value="23">23 - Creuse</option>
|
||||
<option value="24">24 - Dordogne</option>
|
||||
<option value="25">25 - Doubs</option>
|
||||
<option value="26">26 - Drome</option>
|
||||
<option value="27">27 - Eure</option>
|
||||
<option value="28">28 - Eure-et-Loire</option>
|
||||
<option value="29">29 - Finistere</option>
|
||||
<option value="2A">2A - Corse-du-Sud</option>
|
||||
<option value="2B">2B - Haute-Corse</option>
|
||||
<option value="30">30 - Gard</option>
|
||||
<option value="31">31 - Haute-Garonne</option>
|
||||
<option value="32">32 - Gers</option>
|
||||
<option value="33">33 - Gironde</option>
|
||||
<option value="34">34 - Herault</option>
|
||||
<option value="35">35 - Ille-et-Vilaine</option>
|
||||
<option value="36">36 - Indre</option>
|
||||
<option value="37">37 - Indre-et-Loire</option>
|
||||
<option value="38">38 - Isere</option>
|
||||
<option value="39">39 - Jura</option>
|
||||
<option value="40">40 - Landes</option>
|
||||
<option value="41">41 - Loir-et-Cher</option>
|
||||
<option value="42">42 - Loire</option>
|
||||
<option value="43">43 - Haute-Loire</option>
|
||||
<option value="44">44 - Loire-Atlantique</option>
|
||||
<option value="45">45 - Loiret</option>
|
||||
<option value="46">46 - Lot</option>
|
||||
<option value="47">47 - Lot-et-Garonne</option>
|
||||
<option value="48">48 - Lozere</option>
|
||||
<option value="49">49 - Maine-et-Loire</option>
|
||||
<option value="50">50 - Manche</option>
|
||||
<option value="51">51 - Marne</option>
|
||||
<option value="52">52 - Haute-Marne</option>
|
||||
<option value="53">53 - Mayenne</option>
|
||||
<option value="54">54 - Meurthe-et-Moselle</option>
|
||||
<option value="55">55 - Meuse</option>
|
||||
<option value="56">56 - Morbihan</option>
|
||||
<option value="57">57 - Moselle</option>
|
||||
<option value="58">58 - Nievre</option>
|
||||
<option value="59">59 - Nord</option>
|
||||
<option value="60">60 - Oise</option>
|
||||
<option value="61">61 - Orne</option>
|
||||
<option value="62">62 - Pas-de-Calais</option>
|
||||
<option value="63">63 - Puy-de-Dome</option>
|
||||
<option value="64">64 - Pyrenees-Atlantiques</option>
|
||||
<option value="65">65 - Hautes-Pyrenees</option>
|
||||
<option value="66">66 - Pyrenees-Orientales</option>
|
||||
<option value="67">67 - Bas-Rhin</option>
|
||||
<option value="68">68 - Haut-Rhin</option>
|
||||
<option value="69">69 - Rhone</option>
|
||||
<option value="70">70 - Haute-Saone</option>
|
||||
<option value="71">71 - Saone-et-Loire</option>
|
||||
<option value="72">72 - Sarthe</option>
|
||||
<option value="73">73 - Savoie</option>
|
||||
<option value="74">74 - Haute-Savoie</option>
|
||||
<option value="75">75 - Paris</option>
|
||||
<option value="76">76 - Seine-Maritime</option>
|
||||
<option value="77">77 - Seine-et-Marne</option>
|
||||
<option value="78">78 - Yvelines</option>
|
||||
<option value="79">79 - Deux-Sevres</option>
|
||||
<option value="80">80 - Somme</option>
|
||||
<option value="81">81 - Tarn</option>
|
||||
<option value="82">82 - Tarn-et-Garonne</option>
|
||||
<option value="83">83 - Var</option>
|
||||
<option value="84">84 - Vaucluse</option>
|
||||
<option value="85">85 - Vendee</option>
|
||||
<option value="86">86 - Vienne</option>
|
||||
<option value="87">87 - Haute-Vienne</option>
|
||||
<option value="88">88 - Vosges</option>
|
||||
<option value="89">89 - Yonne</option>
|
||||
<option value="90">90 - Territoire de Belfort</option>
|
||||
<option value="91">91 - Essonne</option>
|
||||
<option value="92">92 - Hauts-de-Seine</option>
|
||||
<option value="93">93 - Seine-Saint-Denis</option>
|
||||
<option value="94">94 - Val-de-Marne</option>
|
||||
<option value="95">95 - Val-d'Oise</option>
|
||||
<option value="2A">2A - Corse du sud</option>
|
||||
<option value="2B">2B - Haute Corse</option>
|
||||
<option value="971">971 - Guadeloupe</option>
|
||||
<option value="972">972 - Martinique</option>
|
||||
<option value="973">973 - Guyane</option>
|
||||
<option value="974">974 - La Reunion</option>
|
||||
<option value="975">975 - Saint-Pierre-et-Miquelon</option>
|
||||
<option value="976">976 - Mayotte</option>
|
||||
<option value="984">984 - Terres Australes et Antarctiques</option>
|
||||
<option value="986">986 - Wallis et Futuna</option>
|
||||
<option value="987">987 - Polynesie Francaise</option>
|
||||
<option value="988">988 - Nouvelle-Caledonie</option>
|
||||
</select>
|
||||
"""
|
163
tests/regressiontests/forms/localflavor/generic.py
Normal file
163
tests/regressiontests/forms/localflavor/generic.py
Normal file
@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ generic form fields.
|
||||
|
||||
tests = r"""
|
||||
## Generic DateField ##########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.generic.forms import *
|
||||
|
||||
A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
|
||||
appropriate.
|
||||
|
||||
>>> import datetime
|
||||
>>> f = DateField()
|
||||
>>> f.clean(datetime.date(2006, 10, 25))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('2006-10-25')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('25/10/2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('25/10/06')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('Oct 25 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('October 25 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('October 25, 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('25 October 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('25 October, 2006')
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('2006-4-31')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.clean('200a-10-25')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.clean('10/25/06')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = DateField(required=False)
|
||||
>>> f.clean(None)
|
||||
>>> repr(f.clean(None))
|
||||
'None'
|
||||
>>> f.clean('')
|
||||
>>> repr(f.clean(''))
|
||||
'None'
|
||||
|
||||
DateField accepts an optional input_formats parameter:
|
||||
>>> f = DateField(input_formats=['%Y %m %d'])
|
||||
>>> f.clean(datetime.date(2006, 10, 25))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.date(2006, 10, 25)
|
||||
>>> f.clean('2006 10 25')
|
||||
datetime.date(2006, 10, 25)
|
||||
|
||||
The input_formats parameter overrides all default input formats,
|
||||
so the default formats won't work unless you specify them:
|
||||
>>> f.clean('2006-10-25')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.clean('25/10/2006')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
>>> f.clean('25/10/06')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date.']
|
||||
|
||||
## Generic DateTimeField ######################################################
|
||||
|
||||
A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
|
||||
appropriate.
|
||||
|
||||
>>> import datetime
|
||||
>>> f = DateTimeField()
|
||||
>>> f.clean(datetime.date(2006, 10, 25))
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
|
||||
>>> f.clean('2006-10-25 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.clean('2006-10-25 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('2006-10-25 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('2006-10-25')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.clean('25/10/2006 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.clean('25/10/2006 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('25/10/2006 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('25/10/2006')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.clean('25/10/06 14:30:45')
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 45)
|
||||
>>> f.clean('25/10/06 14:30:00')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('25/10/06 14:30')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean('25/10/06')
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.clean('hello')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
>>> f.clean('2006-10-25 4:30 p.m.')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
|
||||
DateField accepts an optional input_formats parameter:
|
||||
>>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
|
||||
>>> f.clean(datetime.date(2006, 10, 25))
|
||||
datetime.datetime(2006, 10, 25, 0, 0)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59)
|
||||
>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
|
||||
datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
|
||||
>>> f.clean('2006 10 25 2:30 PM')
|
||||
datetime.datetime(2006, 10, 25, 14, 30)
|
||||
|
||||
The input_formats parameter overrides all default input formats,
|
||||
so the default formats won't work unless you specify them:
|
||||
>>> f.clean('2006-10-25 14:30:45')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid date/time.']
|
||||
|
||||
>>> f = DateTimeField(required=False)
|
||||
>>> f.clean(None)
|
||||
>>> repr(f.clean(None))
|
||||
'None'
|
||||
>>> f.clean('')
|
||||
>>> repr(f.clean(''))
|
||||
'None'
|
||||
|
||||
"""
|
103
tests/regressiontests/forms/localflavor/is_.py
Normal file
103
tests/regressiontests/forms/localflavor/is_.py
Normal file
File diff suppressed because one or more lines are too long
62
tests/regressiontests/forms/localflavor/it.py
Normal file
62
tests/regressiontests/forms/localflavor/it.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ IT form fields.
|
||||
|
||||
tests = r"""
|
||||
# ITZipCodeField #############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.it.forms import ITZipCodeField
|
||||
>>> f = ITZipCodeField()
|
||||
>>> f.clean('00100')
|
||||
u'00100'
|
||||
>>> f.clean(' 00100')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid zip code.']
|
||||
|
||||
# ITRegionSelect #############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.it.forms import ITRegionSelect
|
||||
>>> w = ITRegionSelect()
|
||||
>>> w.render('regions', 'PMN')
|
||||
u'<select name="regions">\n<option value="ABR">Abruzzo</option>\n<option value="BAS">Basilicata</option>\n<option value="CAL">Calabria</option>\n<option value="CAM">Campania</option>\n<option value="EMR">Emilia-Romagna</option>\n<option value="FVG">Friuli-Venezia Giulia</option>\n<option value="LAZ">Lazio</option>\n<option value="LIG">Liguria</option>\n<option value="LOM">Lombardia</option>\n<option value="MAR">Marche</option>\n<option value="MOL">Molise</option>\n<option value="PMN" selected="selected">Piemonte</option>\n<option value="PUG">Puglia</option>\n<option value="SAR">Sardegna</option>\n<option value="SIC">Sicilia</option>\n<option value="TOS">Toscana</option>\n<option value="TAA">Trentino-Alto Adige</option>\n<option value="UMB">Umbria</option>\n<option value="VAO">Valle d\u2019Aosta</option>\n<option value="VEN">Veneto</option>\n</select>'
|
||||
|
||||
# ITSocialSecurityNumberField #################################################
|
||||
|
||||
>>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField
|
||||
>>> f = ITSocialSecurityNumberField()
|
||||
>>> f.clean('LVSGDU99T71H501L')
|
||||
u'LVSGDU99T71H501L'
|
||||
>>> f.clean('LBRRME11A01L736W')
|
||||
u'LBRRME11A01L736W'
|
||||
>>> f.clean('lbrrme11a01l736w')
|
||||
u'LBRRME11A01L736W'
|
||||
>>> f.clean('LBR RME 11A01 L736W')
|
||||
u'LBRRME11A01L736W'
|
||||
>>> f.clean('LBRRME11A01L736A')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Social Security number.']
|
||||
>>> f.clean('%BRRME11A01L736W')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid Social Security number.']
|
||||
|
||||
# ITVatNumberField ###########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.it.forms import ITVatNumberField
|
||||
>>> f = ITVatNumberField()
|
||||
>>> f.clean('07973780013')
|
||||
u'07973780013'
|
||||
>>> f.clean('7973780013')
|
||||
u'07973780013'
|
||||
>>> f.clean(7973780013)
|
||||
u'07973780013'
|
||||
>>> f.clean('07973780014')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid VAT number.']
|
||||
>>> f.clean('A7973780013')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid VAT number.']
|
||||
"""
|
106
tests/regressiontests/forms/localflavor/jp.py
Normal file
106
tests/regressiontests/forms/localflavor/jp.py
Normal file
@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ JP form fields.
|
||||
|
||||
tests = r"""
|
||||
# JPPostalCodeField ###############################################################
|
||||
|
||||
A form field that validates its input is a Japanese postcode.
|
||||
|
||||
Accepts 7 digits(with/out hyphen).
|
||||
>>> from django.contrib.localflavor.jp.forms import JPPostalCodeField
|
||||
>>> f = JPPostalCodeField()
|
||||
>>> f.clean('251-0032')
|
||||
u'2510032'
|
||||
>>> f.clean('2510032')
|
||||
u'2510032'
|
||||
>>> f.clean('2510-032')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
|
||||
>>> f.clean('251a0032')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
|
||||
>>> f.clean('a51-0032')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
|
||||
>>> f.clean('25100321')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = JPPostalCodeField(required=False)
|
||||
>>> f.clean('251-0032')
|
||||
u'2510032'
|
||||
>>> f.clean('2510032')
|
||||
u'2510032'
|
||||
>>> f.clean('2510-032')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
|
||||
# JPPrefectureSelect ###############################################################
|
||||
|
||||
A Select widget that uses a list of Japanese prefectures as its choices.
|
||||
>>> from django.contrib.localflavor.jp.forms import JPPrefectureSelect
|
||||
>>> w = JPPrefectureSelect()
|
||||
>>> print w.render('prefecture', 'kanagawa')
|
||||
<select name="prefecture">
|
||||
<option value="hokkaido">Hokkaido</option>
|
||||
<option value="aomori">Aomori</option>
|
||||
<option value="iwate">Iwate</option>
|
||||
<option value="miyagi">Miyagi</option>
|
||||
<option value="akita">Akita</option>
|
||||
<option value="yamagata">Yamagata</option>
|
||||
<option value="fukushima">Fukushima</option>
|
||||
<option value="ibaraki">Ibaraki</option>
|
||||
<option value="tochigi">Tochigi</option>
|
||||
<option value="gunma">Gunma</option>
|
||||
<option value="saitama">Saitama</option>
|
||||
<option value="chiba">Chiba</option>
|
||||
<option value="tokyo">Tokyo</option>
|
||||
<option value="kanagawa" selected="selected">Kanagawa</option>
|
||||
<option value="yamanashi">Yamanashi</option>
|
||||
<option value="nagano">Nagano</option>
|
||||
<option value="niigata">Niigata</option>
|
||||
<option value="toyama">Toyama</option>
|
||||
<option value="ishikawa">Ishikawa</option>
|
||||
<option value="fukui">Fukui</option>
|
||||
<option value="gifu">Gifu</option>
|
||||
<option value="shizuoka">Shizuoka</option>
|
||||
<option value="aichi">Aichi</option>
|
||||
<option value="mie">Mie</option>
|
||||
<option value="shiga">Shiga</option>
|
||||
<option value="kyoto">Kyoto</option>
|
||||
<option value="osaka">Osaka</option>
|
||||
<option value="hyogo">Hyogo</option>
|
||||
<option value="nara">Nara</option>
|
||||
<option value="wakayama">Wakayama</option>
|
||||
<option value="tottori">Tottori</option>
|
||||
<option value="shimane">Shimane</option>
|
||||
<option value="okayama">Okayama</option>
|
||||
<option value="hiroshima">Hiroshima</option>
|
||||
<option value="yamaguchi">Yamaguchi</option>
|
||||
<option value="tokushima">Tokushima</option>
|
||||
<option value="kagawa">Kagawa</option>
|
||||
<option value="ehime">Ehime</option>
|
||||
<option value="kochi">Kochi</option>
|
||||
<option value="fukuoka">Fukuoka</option>
|
||||
<option value="saga">Saga</option>
|
||||
<option value="nagasaki">Nagasaki</option>
|
||||
<option value="kumamoto">Kumamoto</option>
|
||||
<option value="oita">Oita</option>
|
||||
<option value="miyazaki">Miyazaki</option>
|
||||
<option value="kagoshima">Kagoshima</option>
|
||||
<option value="okinawa">Okinawa</option>
|
||||
</select>
|
||||
"""
|
72
tests/regressiontests/forms/localflavor/nl.py
Normal file
72
tests/regressiontests/forms/localflavor/nl.py
Normal file
@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ NL form fields.
|
||||
|
||||
tests = r"""
|
||||
# NLPhoneNumberField ########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.nl.forms import NLPhoneNumberField
|
||||
>>> f = NLPhoneNumberField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean('012-3456789')
|
||||
'012-3456789'
|
||||
>>> f.clean('0123456789')
|
||||
'0123456789'
|
||||
>>> f.clean('+31-12-3456789')
|
||||
'+31-12-3456789'
|
||||
>>> f.clean('(0123) 456789')
|
||||
'(0123) 456789'
|
||||
>>> f.clean('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid phone number']
|
||||
|
||||
# NLZipCodeField ############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.nl.forms import NLZipCodeField
|
||||
>>> f = NLZipCodeField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean('1234ab')
|
||||
u'1234 AB'
|
||||
>>> f.clean('1234 ab')
|
||||
u'1234 AB'
|
||||
>>> f.clean('1234 AB')
|
||||
u'1234 AB'
|
||||
>>> f.clean('0123AB')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid postal code']
|
||||
>>> f.clean('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid postal code']
|
||||
|
||||
# NLSoFiNumberField #########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.nl.forms import NLSoFiNumberField
|
||||
>>> f = NLSoFiNumberField(required=False)
|
||||
>>> f.clean('')
|
||||
u''
|
||||
>>> f.clean('123456782')
|
||||
'123456782'
|
||||
>>> f.clean('000000000')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid SoFi number']
|
||||
>>> f.clean('123456789')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid SoFi number']
|
||||
>>> f.clean('foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid SoFi number']
|
||||
|
||||
# NLProvinceSelect ##########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.nl.forms import NLProvinceSelect
|
||||
>>> s = NLProvinceSelect()
|
||||
>>> s.render('provinces', 'OV')
|
||||
u'<select name="provinces">\n<option value="DR">Drente</option>\n<option value="FL">Flevoland</option>\n<option value="FR">Friesland</option>\n<option value="GL">Gelderland</option>\n<option value="GR">Groningen</option>\n<option value="LB">Limburg</option>\n<option value="NB">Noord-Brabant</option>\n<option value="NH">Noord-Holland</option>\n<option value="OV" selected="selected">Overijssel</option>\n<option value="UT">Utrecht</option>\n<option value="ZE">Zeeland</option>\n<option value="ZH">Zuid-Holland</option>\n</select>'
|
||||
"""
|
61
tests/regressiontests/forms/localflavor/pl.py
Normal file
61
tests/regressiontests/forms/localflavor/pl.py
Normal file
File diff suppressed because one or more lines are too long
31
tests/regressiontests/forms/localflavor/sk.py
Normal file
31
tests/regressiontests/forms/localflavor/sk.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ SK form fields.
|
||||
|
||||
tests = r"""
|
||||
# SKPostalCodeField #########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.sk.forms import SKPostalCodeField
|
||||
>>> f = SKPostalCodeField()
|
||||
>>> f.clean('84545x')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
|
||||
>>> f.clean('91909')
|
||||
u'91909'
|
||||
>>> f.clean('917 01')
|
||||
u'91701'
|
||||
|
||||
# SKRegionSelect ############################################################
|
||||
|
||||
>>> from django.contrib.localflavor.sk.forms import SKRegionSelect
|
||||
>>> w = SKRegionSelect()
|
||||
>>> w.render('regions', 'TT')
|
||||
u'<select name="regions">\n<option value="BB">Banska Bystrica region</option>\n<option value="BA">Bratislava region</option>\n<option value="KE">Kosice region</option>\n<option value="NR">Nitra region</option>\n<option value="PO">Presov region</option>\n<option value="TN">Trencin region</option>\n<option value="TT" selected="selected">Trnava region</option>\n<option value="ZA">Zilina region</option>\n</select>'
|
||||
|
||||
# SKDistrictSelect ##########################################################
|
||||
|
||||
>>> from django.contrib.localflavor.sk.forms import SKDistrictSelect
|
||||
>>> w = SKDistrictSelect()
|
||||
>>> w.render('Districts', 'RK')
|
||||
u'<select name="Districts">\n<option value="BB">Banska Bystrica</option>\n<option value="BS">Banska Stiavnica</option>\n<option value="BJ">Bardejov</option>\n<option value="BN">Banovce nad Bebravou</option>\n<option value="BR">Brezno</option>\n<option value="BA1">Bratislava I</option>\n<option value="BA2">Bratislava II</option>\n<option value="BA3">Bratislava III</option>\n<option value="BA4">Bratislava IV</option>\n<option value="BA5">Bratislava V</option>\n<option value="BY">Bytca</option>\n<option value="CA">Cadca</option>\n<option value="DT">Detva</option>\n<option value="DK">Dolny Kubin</option>\n<option value="DS">Dunajska Streda</option>\n<option value="GA">Galanta</option>\n<option value="GL">Gelnica</option>\n<option value="HC">Hlohovec</option>\n<option value="HE">Humenne</option>\n<option value="IL">Ilava</option>\n<option value="KK">Kezmarok</option>\n<option value="KN">Komarno</option>\n<option value="KE1">Kosice I</option>\n<option value="KE2">Kosice II</option>\n<option value="KE3">Kosice III</option>\n<option value="KE4">Kosice IV</option>\n<option value="KEO">Kosice - okolie</option>\n<option value="KA">Krupina</option>\n<option value="KM">Kysucke Nove Mesto</option>\n<option value="LV">Levice</option>\n<option value="LE">Levoca</option>\n<option value="LM">Liptovsky Mikulas</option>\n<option value="LC">Lucenec</option>\n<option value="MA">Malacky</option>\n<option value="MT">Martin</option>\n<option value="ML">Medzilaborce</option>\n<option value="MI">Michalovce</option>\n<option value="MY">Myjava</option>\n<option value="NO">Namestovo</option>\n<option value="NR">Nitra</option>\n<option value="NM">Nove Mesto nad Vahom</option>\n<option value="NZ">Nove Zamky</option>\n<option value="PE">Partizanske</option>\n<option value="PK">Pezinok</option>\n<option value="PN">Piestany</option>\n<option value="PT">Poltar</option>\n<option value="PP">Poprad</option>\n<option value="PB">Povazska Bystrica</option>\n<option value="PO">Presov</option>\n<option value="PD">Prievidza</option>\n<option value="PU">Puchov</option>\n<option value="RA">Revuca</option>\n<option value="RS">Rimavska Sobota</option>\n<option value="RV">Roznava</option>\n<option value="RK" selected="selected">Ruzomberok</option>\n<option value="SB">Sabinov</option>\n<option value="SC">Senec</option>\n<option value="SE">Senica</option>\n<option value="SI">Skalica</option>\n<option value="SV">Snina</option>\n<option value="SO">Sobrance</option>\n<option value="SN">Spisska Nova Ves</option>\n<option value="SL">Stara Lubovna</option>\n<option value="SP">Stropkov</option>\n<option value="SK">Svidnik</option>\n<option value="SA">Sala</option>\n<option value="TO">Topolcany</option>\n<option value="TV">Trebisov</option>\n<option value="TN">Trencin</option>\n<option value="TT">Trnava</option>\n<option value="TR">Turcianske Teplice</option>\n<option value="TS">Tvrdosin</option>\n<option value="VK">Velky Krtis</option>\n<option value="VT">Vranov nad Toplou</option>\n<option value="ZM">Zlate Moravce</option>\n<option value="ZV">Zvolen</option>\n<option value="ZC">Zarnovica</option>\n<option value="ZH">Ziar nad Hronom</option>\n<option value="ZA">Zilina</option>\n</select>'
|
||||
"""
|
48
tests/regressiontests/forms/localflavor/uk.py
Normal file
48
tests/regressiontests/forms/localflavor/uk.py
Normal file
@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ UK form fields.
|
||||
|
||||
tests = r"""
|
||||
# UKPostcodeField #############################################################
|
||||
|
||||
UKPostcodeField validates that the data is a valid UK postcode.
|
||||
>>> from django.contrib.localflavor.uk.forms import UKPostcodeField
|
||||
>>> f = UKPostcodeField()
|
||||
>>> f.clean('BT32 4PX')
|
||||
u'BT32 4PX'
|
||||
>>> f.clean('GIR 0AA')
|
||||
u'GIR 0AA'
|
||||
>>> f.clean('BT324PX')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
||||
>>> f.clean('1NV 4L1D')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = UKPostcodeField(required=False)
|
||||
>>> f.clean('BT32 4PX')
|
||||
u'BT32 4PX'
|
||||
>>> f.clean('GIR 0AA')
|
||||
u'GIR 0AA'
|
||||
>>> f.clean('1NV 4L1D')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
||||
>>> f.clean('BT324PX')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
"""
|
260
tests/regressiontests/forms/localflavor/us.py
Normal file
260
tests/regressiontests/forms/localflavor/us.py
Normal file
@ -0,0 +1,260 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests for the contrib/localflavor/ US form fields.
|
||||
|
||||
tests = r"""
|
||||
# USZipCodeField ##############################################################
|
||||
|
||||
USZipCodeField validates that the data is either a five-digit U.S. zip code or
|
||||
a zip+4.
|
||||
>>> from django.contrib.localflavor.us.forms import USZipCodeField
|
||||
>>> f = USZipCodeField()
|
||||
>>> f.clean('60606')
|
||||
u'60606'
|
||||
>>> f.clean(60606)
|
||||
u'60606'
|
||||
>>> f.clean('04000')
|
||||
u'04000'
|
||||
>>> f.clean('4000')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean('60606-1234')
|
||||
u'60606-1234'
|
||||
>>> f.clean('6060-1234')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean('60606-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = USZipCodeField(required=False)
|
||||
>>> f.clean('60606')
|
||||
u'60606'
|
||||
>>> f.clean(60606)
|
||||
u'60606'
|
||||
>>> f.clean('04000')
|
||||
u'04000'
|
||||
>>> f.clean('4000')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean('60606-1234')
|
||||
u'60606-1234'
|
||||
>>> f.clean('6060-1234')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean('60606-')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# USPhoneNumberField ##########################################################
|
||||
|
||||
USPhoneNumberField validates that the data is a valid U.S. phone number,
|
||||
including the area code. It's normalized to XXX-XXX-XXXX format.
|
||||
>>> from django.contrib.localflavor.us.forms import USPhoneNumberField
|
||||
>>> f = USPhoneNumberField()
|
||||
>>> f.clean('312-555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('3125551212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312 555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('(312) 555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312 555 1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312.555.1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312.555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean(' (312) 555.1212 ')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('555-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('312-55-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = USPhoneNumberField(required=False)
|
||||
>>> f.clean('312-555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('3125551212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312 555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('(312) 555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312 555 1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312.555.1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('312.555-1212')
|
||||
u'312-555-1212'
|
||||
>>> f.clean(' (312) 555.1212 ')
|
||||
u'312-555-1212'
|
||||
>>> f.clean('555-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean('312-55-1212')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# USStateField ################################################################
|
||||
|
||||
USStateField validates that the data is either an abbreviation or name of a
|
||||
U.S. state.
|
||||
>>> from django.contrib.localflavor.us.forms import USStateField
|
||||
>>> f = USStateField()
|
||||
>>> f.clean('il')
|
||||
u'IL'
|
||||
>>> f.clean('IL')
|
||||
u'IL'
|
||||
>>> f.clean('illinois')
|
||||
u'IL'
|
||||
>>> f.clean(' illinois ')
|
||||
u'IL'
|
||||
>>> f.clean(60606)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a U.S. state or territory.']
|
||||
>>> f.clean(None)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
>>> f.clean('')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'This field is required.']
|
||||
|
||||
>>> f = USStateField(required=False)
|
||||
>>> f.clean('il')
|
||||
u'IL'
|
||||
>>> f.clean('IL')
|
||||
u'IL'
|
||||
>>> f.clean('illinois')
|
||||
u'IL'
|
||||
>>> f.clean(' illinois ')
|
||||
u'IL'
|
||||
>>> f.clean(60606)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a U.S. state or territory.']
|
||||
>>> f.clean(None)
|
||||
u''
|
||||
>>> f.clean('')
|
||||
u''
|
||||
|
||||
# USStateSelect ###############################################################
|
||||
|
||||
USStateSelect is a Select widget that uses a list of U.S. states/territories
|
||||
as its choices.
|
||||
>>> from django.contrib.localflavor.us.forms import USStateSelect
|
||||
>>> w = USStateSelect()
|
||||
>>> print w.render('state', 'IL')
|
||||
<select name="state">
|
||||
<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="FM">Federated States of Micronesia</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="GA">Georgia</option>
|
||||
<option value="GU">Guam</option>
|
||||
<option value="HI">Hawaii</option>
|
||||
<option value="ID">Idaho</option>
|
||||
<option value="IL" selected="selected">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="MH">Marshall Islands</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="PW">Palau</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>
|
||||
|
||||
# USSocialSecurityNumberField #################################################
|
||||
>>> from django.contrib.localflavor.us.forms import USSocialSecurityNumberField
|
||||
>>> f = USSocialSecurityNumberField()
|
||||
>>> f.clean('987-65-4330')
|
||||
u'987-65-4330'
|
||||
>>> f.clean('987654330')
|
||||
u'987-65-4330'
|
||||
>>> f.clean('078-05-1120')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValidationError: [u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.']
|
||||
"""
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Tests to prevent against recurrences of earlier bugs.
|
||||
|
||||
regression_tests = r"""
|
||||
tests = r"""
|
||||
It should be possible to re-use attribute dictionaries (#3810)
|
||||
>>> from django.newforms import *
|
||||
>>> extra_attrs = {'class': 'special'}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
Tests for newforms/util.py module.
|
||||
"""
|
||||
|
||||
util_tests = r"""
|
||||
tests = r"""
|
||||
>>> from django.newforms.util import *
|
||||
>>> from django.utils.translation import ugettext_lazy
|
||||
|
||||
|
848
tests/regressiontests/forms/widgets.py
Normal file
848
tests/regressiontests/forms/widgets.py
Normal file
@ -0,0 +1,848 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
tests = r"""
|
||||
>>> from django.newforms import *
|
||||
>>> from django.newforms.widgets import RadioFieldRenderer
|
||||
>>> import datetime
|
||||
>>> import time
|
||||
>>> import re
|
||||
>>> try:
|
||||
... from decimal import Decimal
|
||||
... except ImportError:
|
||||
... from django.utils._decimal import Decimal
|
||||
|
||||
###########
|
||||
# Widgets #
|
||||
###########
|
||||
|
||||
Each Widget class corresponds to an HTML form widget. A Widget knows how to
|
||||
render itself, given a field name and some data. Widgets don't perform
|
||||
validation.
|
||||
|
||||
# TextInput Widget ############################################################
|
||||
|
||||
>>> w = TextInput()
|
||||
>>> w.render('email', '')
|
||||
u'<input type="text" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="text" name="email" />'
|
||||
>>> w.render('email', 'test@example.com')
|
||||
u'<input type="text" name="email" value="test@example.com" />'
|
||||
>>> w.render('email', 'some "quoted" & ampersanded value')
|
||||
u'<input type="text" name="email" value="some "quoted" & ampersanded value" />'
|
||||
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
|
||||
u'<input type="text" name="email" value="test@example.com" class="fun" />'
|
||||
|
||||
# Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii
|
||||
# characters in output, so we're displaying the repr() here.
|
||||
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
|
||||
u'<input type="text" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = TextInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', '')
|
||||
u'<input type="text" class="fun" name="email" />'
|
||||
>>> w.render('email', 'foo@example.com')
|
||||
u'<input type="text" class="fun" value="foo@example.com" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = TextInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', '', attrs={'class': 'special'})
|
||||
u'<input type="text" class="special" name="email" />'
|
||||
|
||||
# PasswordInput Widget ############################################################
|
||||
|
||||
>>> w = PasswordInput()
|
||||
>>> w.render('email', '')
|
||||
u'<input type="password" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="password" name="email" />'
|
||||
>>> w.render('email', 'test@example.com')
|
||||
u'<input type="password" name="email" value="test@example.com" />'
|
||||
>>> w.render('email', 'some "quoted" & ampersanded value')
|
||||
u'<input type="password" name="email" value="some "quoted" & ampersanded value" />'
|
||||
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
|
||||
u'<input type="password" name="email" value="test@example.com" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = PasswordInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', '')
|
||||
u'<input type="password" class="fun" name="email" />'
|
||||
>>> w.render('email', 'foo@example.com')
|
||||
u'<input type="password" class="fun" value="foo@example.com" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = PasswordInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', '', attrs={'class': 'special'})
|
||||
u'<input type="password" class="special" name="email" />'
|
||||
|
||||
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
|
||||
u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
|
||||
|
||||
The render_value argument lets you specify whether the widget should render
|
||||
its value. You may want to do this for security reasons.
|
||||
>>> w = PasswordInput(render_value=True)
|
||||
>>> w.render('email', 'secret')
|
||||
u'<input type="password" name="email" value="secret" />'
|
||||
>>> w = PasswordInput(render_value=False)
|
||||
>>> w.render('email', '')
|
||||
u'<input type="password" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="password" name="email" />'
|
||||
>>> w.render('email', 'secret')
|
||||
u'<input type="password" name="email" />'
|
||||
>>> w = PasswordInput(attrs={'class': 'fun'}, render_value=False)
|
||||
>>> w.render('email', 'secret')
|
||||
u'<input type="password" class="fun" name="email" />'
|
||||
|
||||
# HiddenInput Widget ############################################################
|
||||
|
||||
>>> w = HiddenInput()
|
||||
>>> w.render('email', '')
|
||||
u'<input type="hidden" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="hidden" name="email" />'
|
||||
>>> w.render('email', 'test@example.com')
|
||||
u'<input type="hidden" name="email" value="test@example.com" />'
|
||||
>>> w.render('email', 'some "quoted" & ampersanded value')
|
||||
u'<input type="hidden" name="email" value="some "quoted" & ampersanded value" />'
|
||||
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
|
||||
u'<input type="hidden" name="email" value="test@example.com" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = HiddenInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', '')
|
||||
u'<input type="hidden" class="fun" name="email" />'
|
||||
>>> w.render('email', 'foo@example.com')
|
||||
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = HiddenInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', '', attrs={'class': 'special'})
|
||||
u'<input type="hidden" class="special" name="email" />'
|
||||
|
||||
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
|
||||
u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = HiddenInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', '', attrs={'class': 'special'})
|
||||
u'<input type="hidden" class="special" name="email" />'
|
||||
|
||||
# MultipleHiddenInput Widget ##################################################
|
||||
|
||||
>>> w = MultipleHiddenInput()
|
||||
>>> w.render('email', [])
|
||||
u''
|
||||
>>> w.render('email', None)
|
||||
u''
|
||||
>>> w.render('email', ['test@example.com'])
|
||||
u'<input type="hidden" name="email" value="test@example.com" />'
|
||||
>>> w.render('email', ['some "quoted" & ampersanded value'])
|
||||
u'<input type="hidden" name="email" value="some "quoted" & ampersanded value" />'
|
||||
>>> w.render('email', ['test@example.com', 'foo@example.com'])
|
||||
u'<input type="hidden" name="email" value="test@example.com" />\n<input type="hidden" name="email" value="foo@example.com" />'
|
||||
>>> w.render('email', ['test@example.com'], attrs={'class': 'fun'})
|
||||
u'<input type="hidden" name="email" value="test@example.com" class="fun" />'
|
||||
>>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'})
|
||||
u'<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = MultipleHiddenInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', [])
|
||||
u''
|
||||
>>> w.render('email', ['foo@example.com'])
|
||||
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />'
|
||||
>>> w.render('email', ['foo@example.com', 'test@example.com'])
|
||||
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />\n<input type="hidden" class="fun" value="test@example.com" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
|
||||
u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
|
||||
|
||||
>>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
|
||||
u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
|
||||
u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
|
||||
|
||||
# FileInput Widget ############################################################
|
||||
|
||||
FileInput widgets don't ever show the value, because the old value is of no use
|
||||
if you are updating the form or if the provided file generated an error.
|
||||
>>> w = FileInput()
|
||||
>>> w.render('email', '')
|
||||
u'<input type="file" name="email" />'
|
||||
>>> w.render('email', None)
|
||||
u'<input type="file" name="email" />'
|
||||
>>> w.render('email', 'test@example.com')
|
||||
u'<input type="file" name="email" />'
|
||||
>>> w.render('email', 'some "quoted" & ampersanded value')
|
||||
u'<input type="file" name="email" />'
|
||||
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
|
||||
u'<input type="file" name="email" class="fun" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = FileInput(attrs={'class': 'fun'})
|
||||
>>> w.render('email', '')
|
||||
u'<input type="file" class="fun" name="email" />'
|
||||
>>> w.render('email', 'foo@example.com')
|
||||
u'<input type="file" class="fun" name="email" />'
|
||||
|
||||
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
|
||||
u'<input type="file" class="fun" name="email" />'
|
||||
|
||||
# Textarea Widget #############################################################
|
||||
|
||||
>>> w = Textarea()
|
||||
>>> w.render('msg', '')
|
||||
u'<textarea rows="10" cols="40" name="msg"></textarea>'
|
||||
>>> w.render('msg', None)
|
||||
u'<textarea rows="10" cols="40" name="msg"></textarea>'
|
||||
>>> w.render('msg', 'value')
|
||||
u'<textarea rows="10" cols="40" name="msg">value</textarea>'
|
||||
>>> w.render('msg', 'some "quoted" & ampersanded value')
|
||||
u'<textarea rows="10" cols="40" name="msg">some "quoted" & ampersanded value</textarea>'
|
||||
>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
|
||||
u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = Textarea(attrs={'class': 'pretty'})
|
||||
>>> w.render('msg', '')
|
||||
u'<textarea rows="10" cols="40" name="msg" class="pretty"></textarea>'
|
||||
>>> w.render('msg', 'example')
|
||||
u'<textarea rows="10" cols="40" name="msg" class="pretty">example</textarea>'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = Textarea(attrs={'class': 'pretty'})
|
||||
>>> w.render('msg', '', attrs={'class': 'special'})
|
||||
u'<textarea rows="10" cols="40" name="msg" class="special"></textarea>'
|
||||
|
||||
>>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
|
||||
u'<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>'
|
||||
|
||||
# CheckboxInput Widget ########################################################
|
||||
|
||||
>>> w = CheckboxInput()
|
||||
>>> w.render('is_cool', '')
|
||||
u'<input type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', None)
|
||||
u'<input type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', False)
|
||||
u'<input type="checkbox" name="is_cool" />'
|
||||
>>> w.render('is_cool', True)
|
||||
u'<input checked="checked" type="checkbox" name="is_cool" />'
|
||||
|
||||
Using any value that's not in ('', None, False, True) will check the checkbox
|
||||
and set the 'value' attribute.
|
||||
>>> w.render('is_cool', 'foo')
|
||||
u'<input checked="checked" type="checkbox" name="is_cool" value="foo" />'
|
||||
|
||||
>>> w.render('is_cool', False, attrs={'class': 'pretty'})
|
||||
u'<input type="checkbox" name="is_cool" class="pretty" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor:
|
||||
>>> w = CheckboxInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('is_cool', '')
|
||||
u'<input type="checkbox" class="pretty" name="is_cool" />'
|
||||
|
||||
'attrs' passed to render() get precedence over those passed to the constructor:
|
||||
>>> w = CheckboxInput(attrs={'class': 'pretty'})
|
||||
>>> w.render('is_cool', '', attrs={'class': 'special'})
|
||||
u'<input type="checkbox" class="special" name="is_cool" />'
|
||||
|
||||
You can pass 'check_test' to the constructor. This is a callable that takes the
|
||||
value and returns True if the box should be checked.
|
||||
>>> w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
|
||||
>>> w.render('greeting', '')
|
||||
u'<input type="checkbox" name="greeting" />'
|
||||
>>> w.render('greeting', 'hello')
|
||||
u'<input checked="checked" type="checkbox" name="greeting" value="hello" />'
|
||||
>>> w.render('greeting', 'hello there')
|
||||
u'<input checked="checked" type="checkbox" name="greeting" value="hello there" />'
|
||||
>>> w.render('greeting', 'hello & goodbye')
|
||||
u'<input checked="checked" type="checkbox" name="greeting" value="hello & goodbye" />'
|
||||
|
||||
A subtlety: If the 'check_test' argument cannot handle a value and raises any
|
||||
exception during its __call__, then the exception will be swallowed and the box
|
||||
will not be checked. In this example, the 'check_test' assumes the value has a
|
||||
startswith() method, which fails for the values True, False and None.
|
||||
>>> w.render('greeting', True)
|
||||
u'<input type="checkbox" name="greeting" />'
|
||||
>>> w.render('greeting', False)
|
||||
u'<input type="checkbox" name="greeting" />'
|
||||
>>> w.render('greeting', None)
|
||||
u'<input type="checkbox" name="greeting" />'
|
||||
|
||||
# Select Widget ###############################################################
|
||||
|
||||
>>> w = Select()
|
||||
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select name="beatle">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value is None, none of the options are selected:
|
||||
>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select name="beatle">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value corresponds to a label (but not to an option value), none of the options are selected:
|
||||
>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select name="beatle">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
The value is compared to its str():
|
||||
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
|
||||
<select name="num">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select name="num">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select name="num">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
The 'choices' argument can be any iterable:
|
||||
>>> from itertools import chain
|
||||
>>> def get_choices():
|
||||
... for i in range(5):
|
||||
... yield (i, i)
|
||||
>>> print w.render('num', 2, choices=get_choices())
|
||||
<select name="num">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
>>> things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
|
||||
>>> class SomeForm(Form):
|
||||
... somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
|
||||
>>> f = SomeForm()
|
||||
>>> f.as_table()
|
||||
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>'
|
||||
>>> f.as_table()
|
||||
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>'
|
||||
>>> f = SomeForm({'somechoice': 2})
|
||||
>>> f.as_table()
|
||||
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="">---------</option>\n<option value="1">And Boom</option>\n<option value="2" selected="selected">One More Thing!</option>\n</select></td></tr>'
|
||||
|
||||
You can also pass 'choices' to the constructor:
|
||||
>>> w = Select(choices=[(1, 1), (2, 2), (3, 3)])
|
||||
>>> print w.render('num', 2)
|
||||
<select name="num">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
|
||||
>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
|
||||
<select name="num">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
|
||||
>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
|
||||
u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
|
||||
|
||||
If choices is passed to the constructor and is a generator, it can be iterated
|
||||
over multiple times without getting consumed:
|
||||
>>> w = Select(choices=get_choices())
|
||||
>>> print w.render('num', 2)
|
||||
<select name="num">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
>>> print w.render('num', 3)
|
||||
<select name="num">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3" selected="selected">3</option>
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
|
||||
# NullBooleanSelect Widget ####################################################
|
||||
|
||||
>>> w = NullBooleanSelect()
|
||||
>>> print w.render('is_cool', True)
|
||||
<select name="is_cool">
|
||||
<option value="1">Unknown</option>
|
||||
<option value="2" selected="selected">Yes</option>
|
||||
<option value="3">No</option>
|
||||
</select>
|
||||
>>> print w.render('is_cool', False)
|
||||
<select name="is_cool">
|
||||
<option value="1">Unknown</option>
|
||||
<option value="2">Yes</option>
|
||||
<option value="3" selected="selected">No</option>
|
||||
</select>
|
||||
>>> print w.render('is_cool', None)
|
||||
<select name="is_cool">
|
||||
<option value="1" selected="selected">Unknown</option>
|
||||
<option value="2">Yes</option>
|
||||
<option value="3">No</option>
|
||||
</select>
|
||||
>>> print w.render('is_cool', '2')
|
||||
<select name="is_cool">
|
||||
<option value="1">Unknown</option>
|
||||
<option value="2" selected="selected">Yes</option>
|
||||
<option value="3">No</option>
|
||||
</select>
|
||||
>>> print w.render('is_cool', '3')
|
||||
<select name="is_cool">
|
||||
<option value="1">Unknown</option>
|
||||
<option value="2">Yes</option>
|
||||
<option value="3" selected="selected">No</option>
|
||||
</select>
|
||||
|
||||
""" + \
|
||||
r""" # [This concatenation is to keep the string below the jython's 32K limit].
|
||||
# SelectMultiple Widget #######################################################
|
||||
|
||||
>>> w = SelectMultiple()
|
||||
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P" selected="selected">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R" selected="selected">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value is None, none of the options are selected:
|
||||
>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If the value corresponds to a label (but not to an option value), none of the options are selected:
|
||||
>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
If multiple values are given, but some of them are not valid, the valid ones are selected:
|
||||
>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<select multiple="multiple" name="beatles">
|
||||
<option value="J" selected="selected">John</option>
|
||||
<option value="P">Paul</option>
|
||||
<option value="G" selected="selected">George</option>
|
||||
<option value="R">Ringo</option>
|
||||
</select>
|
||||
|
||||
The value is compared to its str():
|
||||
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
The 'choices' argument can be any iterable:
|
||||
>>> def get_choices():
|
||||
... for i in range(5):
|
||||
... yield (i, i)
|
||||
>>> print w.render('nums', [2], choices=get_choices())
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
</select>
|
||||
|
||||
You can also pass 'choices' to the constructor:
|
||||
>>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
|
||||
>>> print w.render('nums', [2])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
</select>
|
||||
|
||||
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
|
||||
>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
|
||||
<select multiple="multiple" name="nums">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected="selected">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
|
||||
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
|
||||
u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
|
||||
|
||||
# RadioSelect Widget ##########################################################
|
||||
|
||||
>>> w = RadioSelect()
|
||||
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="radio" name="beatle" value="J" /> John</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
If the value is None, none of the options are checked:
|
||||
>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
If the value corresponds to a label (but not to an option value), none of the options are checked:
|
||||
>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
|
||||
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
The value is compared to its str():
|
||||
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
|
||||
The 'choices' argument can be any iterable:
|
||||
>>> def get_choices():
|
||||
... for i in range(5):
|
||||
... yield (i, i)
|
||||
>>> print w.render('num', 2, choices=get_choices())
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="0" /> 0</label></li>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
|
||||
</ul>
|
||||
|
||||
You can also pass 'choices' to the constructor:
|
||||
>>> w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
|
||||
>>> print w.render('num', 2)
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
|
||||
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
|
||||
>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
|
||||
<ul>
|
||||
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
|
||||
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
|
||||
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
|
||||
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
|
||||
</ul>
|
||||
|
||||
RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
|
||||
You can manipulate that object directly to customize the way the RadioSelect
|
||||
is rendered.
|
||||
>>> w = RadioSelect()
|
||||
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
>>> for inp in r:
|
||||
... print inp
|
||||
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
||||
<label><input type="radio" name="beatle" value="G" /> George</label>
|
||||
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
|
||||
>>> for inp in r:
|
||||
... print '%s<br />' % inp
|
||||
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label><br />
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
|
||||
<label><input type="radio" name="beatle" value="G" /> George</label><br />
|
||||
<label><input type="radio" name="beatle" value="R" /> Ringo</label><br />
|
||||
>>> for inp in r:
|
||||
... print '<p>%s %s</p>' % (inp.tag(), inp.choice_label)
|
||||
<p><input checked="checked" type="radio" name="beatle" value="J" /> John</p>
|
||||
<p><input type="radio" name="beatle" value="P" /> Paul</p>
|
||||
<p><input type="radio" name="beatle" value="G" /> George</p>
|
||||
<p><input type="radio" name="beatle" value="R" /> Ringo</p>
|
||||
>>> for inp in r:
|
||||
... print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
|
||||
beatle J J John True
|
||||
beatle J P Paul False
|
||||
beatle J G George False
|
||||
beatle J R Ringo False
|
||||
|
||||
You can create your own custom renderers for RadioSelect to use.
|
||||
>>> class MyRenderer(RadioFieldRenderer):
|
||||
... def render(self):
|
||||
... return u'<br />\n'.join([unicode(choice) for choice in self])
|
||||
>>> w = RadioSelect(renderer=MyRenderer)
|
||||
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<label><input type="radio" name="beatle" value="J" /> John</label><br />
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
|
||||
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
|
||||
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
|
||||
|
||||
A RadioFieldRenderer object also allows index access to individual RadioInput
|
||||
objects.
|
||||
>>> w = RadioSelect()
|
||||
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
>>> print r[1]
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
||||
>>> print r[0]
|
||||
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
|
||||
>>> r[0].is_checked()
|
||||
True
|
||||
>>> r[1].is_checked()
|
||||
False
|
||||
>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
|
||||
('beatle', u'J', u'P', u'Paul')
|
||||
>>> r[10]
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
IndexError: list index out of range
|
||||
|
||||
# Unicode choices are correctly rendered as HTML
|
||||
>>> w = RadioSelect()
|
||||
>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
|
||||
u'<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
|
||||
|
||||
# Attributes provided at instantiation are passed to the constituent inputs
|
||||
>>> w = RadioSelect(attrs={'id':'foo'})
|
||||
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="radio" id="foo_0" value="J" name="beatle" /> John</label></li>
|
||||
<li><label><input type="radio" id="foo_1" value="P" name="beatle" /> Paul</label></li>
|
||||
<li><label><input type="radio" id="foo_2" value="G" name="beatle" /> George</label></li>
|
||||
<li><label><input type="radio" id="foo_3" value="R" name="beatle" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
# Attributes provided at render-time are passed to the constituent inputs
|
||||
>>> w = RadioSelect()
|
||||
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'})
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></li>
|
||||
<li><label><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></li>
|
||||
<li><label><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></li>
|
||||
<li><label><input type="radio" id="bar_3" value="R" name="beatle" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
# CheckboxSelectMultiple Widget ###############################################
|
||||
|
||||
>>> w = CheckboxSelectMultiple()
|
||||
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
If the value is None, none of the options are selected:
|
||||
>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
If the value corresponds to a label (but not to an option value), none of the options are selected:
|
||||
>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
If multiple values are given, but some of them are not valid, the valid ones are selected:
|
||||
>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
|
||||
<ul>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li>
|
||||
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
|
||||
</ul>
|
||||
|
||||
The value is compared to its str():
|
||||
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
|
||||
The 'choices' argument can be any iterable:
|
||||
>>> def get_choices():
|
||||
... for i in range(5):
|
||||
... yield (i, i)
|
||||
>>> print w.render('nums', [2], choices=get_choices())
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="0" /> 0</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
|
||||
</ul>
|
||||
|
||||
You can also pass 'choices' to the constructor:
|
||||
>>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
|
||||
>>> print w.render('nums', [2])
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
</ul>
|
||||
|
||||
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
|
||||
>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
|
||||
<ul>
|
||||
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
|
||||
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
|
||||
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
|
||||
</ul>
|
||||
|
||||
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
|
||||
u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
|
||||
|
||||
# MultiWidget #################################################################
|
||||
|
||||
>>> class MyMultiWidget(MultiWidget):
|
||||
... def decompress(self, value):
|
||||
... if value:
|
||||
... return value.split('__')
|
||||
... return ['', '']
|
||||
... def format_output(self, rendered_widgets):
|
||||
... return u'<br />'.join(rendered_widgets)
|
||||
>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
|
||||
>>> w.render('name', ['john', 'lennon'])
|
||||
u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />'
|
||||
>>> w.render('name', 'john__lennon')
|
||||
u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />'
|
||||
>>> w.render('name', 'john__lennon', attrs={'id':'foo'})
|
||||
u'<input id="foo_0" type="text" class="big" value="john" name="name_0" /><br /><input id="foo_1" type="text" class="small" value="lennon" name="name_1" />'
|
||||
>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
|
||||
>>> w.render('name', ['john', 'lennon'])
|
||||
u'<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />'
|
||||
|
||||
# SplitDateTimeWidget #########################################################
|
||||
|
||||
>>> w = SplitDateTimeWidget()
|
||||
>>> w.render('date', '')
|
||||
u'<input type="text" name="date_0" /><input type="text" name="date_1" />'
|
||||
>>> w.render('date', None)
|
||||
u'<input type="text" name="date_0" /><input type="text" name="date_1" />'
|
||||
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
|
||||
u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />'
|
||||
>>> w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)])
|
||||
u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />'
|
||||
|
||||
You can also pass 'attrs' to the constructor. In this case, the attrs will be
|
||||
included on both widgets.
|
||||
>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
|
||||
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
|
||||
u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />'
|
||||
"""
|
1
tests/regressiontests/max_lengths/__init__.py
Normal file
1
tests/regressiontests/max_lengths/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
|
13
tests/regressiontests/max_lengths/models.py
Normal file
13
tests/regressiontests/max_lengths/models.py
Normal file
@ -0,0 +1,13 @@
|
||||
from django.db import models
|
||||
|
||||
class PersonWithDefaultMaxLengths(models.Model):
|
||||
email = models.EmailField()
|
||||
vcard = models.FileField(upload_to='/tmp')
|
||||
homepage = models.URLField()
|
||||
avatar = models.FilePathField()
|
||||
|
||||
class PersonWithCustomMaxLengths(models.Model):
|
||||
email = models.EmailField(max_length=384)
|
||||
vcard = models.FileField(upload_to='/tmp', max_length=1024)
|
||||
homepage = models.URLField(max_length=256)
|
||||
avatar = models.FilePathField(max_length=512)
|
36
tests/regressiontests/max_lengths/tests.py
Normal file
36
tests/regressiontests/max_lengths/tests.py
Normal file
@ -0,0 +1,36 @@
|
||||
from unittest import TestCase
|
||||
from django.db import DatabaseError
|
||||
from regressiontests.max_lengths.models import PersonWithDefaultMaxLengths, PersonWithCustomMaxLengths
|
||||
|
||||
class MaxLengthArgumentsTests(TestCase):
|
||||
|
||||
def verify_max_length(self, model,field,length):
|
||||
self.assertEquals(model._meta.get_field(field).max_length,length)
|
||||
|
||||
def test_default_max_lengths(self):
|
||||
self.verify_max_length(PersonWithDefaultMaxLengths, 'email', 75)
|
||||
self.verify_max_length(PersonWithDefaultMaxLengths, 'vcard', 100)
|
||||
self.verify_max_length(PersonWithDefaultMaxLengths, 'homepage', 200)
|
||||
self.verify_max_length(PersonWithDefaultMaxLengths, 'avatar', 100)
|
||||
|
||||
def test_custom_maxlengths(self):
|
||||
self.verify_max_length(PersonWithCustomMaxLengths, 'email', 384)
|
||||
self.verify_max_length(PersonWithCustomMaxLengths, 'vcard', 1024)
|
||||
self.verify_max_length(PersonWithCustomMaxLengths, 'homepage', 256)
|
||||
self.verify_max_length(PersonWithCustomMaxLengths, 'avatar', 512)
|
||||
|
||||
class MaxLengthORMTests(TestCase):
|
||||
|
||||
def test_custom_max_lengths(self):
|
||||
args = {
|
||||
"email": "someone@example.com",
|
||||
"vcard": "vcard",
|
||||
"homepage": "http://example.com/",
|
||||
"avatar": "me.jpg"
|
||||
}
|
||||
|
||||
for field in ("email", "vcard", "homepage", "avatar"):
|
||||
new_args = args.copy()
|
||||
new_args[field] = "X" * 250 # a value longer than any of the default fields could hold.
|
||||
p = PersonWithCustomMaxLengths.objects.create(**new_args)
|
||||
self.assertEqual(getattr(p, field), ("X" * 250))
|
@ -771,6 +771,10 @@ class Templates(unittest.TestCase):
|
||||
# Check that timezone is respected
|
||||
'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'),
|
||||
|
||||
# Check times in the future.
|
||||
'timesince07' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=1, seconds=10)}, '0 minutes'),
|
||||
'timesince08' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(days=1, minutes=1)}, '0 minutes'),
|
||||
|
||||
### TIMEUNTIL TAG ##################################################
|
||||
# Default compare with datetime.now()
|
||||
'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
|
||||
@ -781,6 +785,10 @@ class Templates(unittest.TestCase):
|
||||
'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
|
||||
'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),
|
||||
|
||||
# Check times in the past.
|
||||
'timeuntil07' : ('{{ a|timeuntil }}', {'a':datetime.now() - timedelta(minutes=1, seconds=10)}, '0 minutes'),
|
||||
'timeuntil08' : ('{{ a|timeuntil }}', {'a':datetime.now() - timedelta(days=1, minutes=1)}, '0 minutes'),
|
||||
|
||||
### URL TAG ########################################################
|
||||
# Successes
|
||||
'url01' : ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
||||
|
@ -6,6 +6,8 @@ from unittest import TestCase
|
||||
|
||||
from django.utils import html
|
||||
|
||||
from timesince import timesince_tests
|
||||
|
||||
class TestUtilsHtml(TestCase):
|
||||
|
||||
def check_output(self, function, value, output=None):
|
||||
@ -113,3 +115,11 @@ class TestUtilsHtml(TestCase):
|
||||
)
|
||||
for value, output in items:
|
||||
self.check_output(f, value, output)
|
||||
|
||||
__test__ = {
|
||||
'timesince_tests': timesince_tests,
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
77
tests/regressiontests/utils/timesince.py
Normal file
77
tests/regressiontests/utils/timesince.py
Normal file
@ -0,0 +1,77 @@
|
||||
timesince_tests = """
|
||||
>>> from datetime import datetime, timedelta
|
||||
>>> from django.utils.timesince import timesince
|
||||
|
||||
>>> t = datetime(2007, 8, 14, 13, 46, 0)
|
||||
|
||||
>>> onemicrosecond = timedelta(microseconds=1)
|
||||
>>> onesecond = timedelta(seconds=1)
|
||||
>>> oneminute = timedelta(minutes=1)
|
||||
>>> onehour = timedelta(hours=1)
|
||||
>>> oneday = timedelta(days=1)
|
||||
>>> oneweek = timedelta(days=7)
|
||||
>>> onemonth = timedelta(days=30)
|
||||
>>> oneyear = timedelta(days=365)
|
||||
|
||||
# equal datetimes.
|
||||
>>> timesince(t, t)
|
||||
u'0 minutes'
|
||||
|
||||
# Microseconds and seconds are ignored.
|
||||
>>> timesince(t, t+onemicrosecond)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t+onesecond)
|
||||
u'0 minutes'
|
||||
|
||||
# Test other units.
|
||||
>>> timesince(t, t+oneminute)
|
||||
u'1 minute'
|
||||
>>> timesince(t, t+onehour)
|
||||
u'1 hour'
|
||||
>>> timesince(t, t+oneday)
|
||||
u'1 day'
|
||||
>>> timesince(t, t+oneweek)
|
||||
u'1 week'
|
||||
>>> timesince(t, t+onemonth)
|
||||
u'1 month'
|
||||
>>> timesince(t, t+oneyear)
|
||||
u'1 year'
|
||||
|
||||
# Test multiple units.
|
||||
>>> timesince(t, t+2*oneday+6*onehour)
|
||||
u'2 days, 6 hours'
|
||||
>>> timesince(t, t+2*oneweek+2*oneday)
|
||||
u'2 weeks, 2 days'
|
||||
|
||||
# If the two differing units aren't adjacent, only the first unit is displayed.
|
||||
>>> timesince(t, t+2*oneweek+3*onehour+4*oneminute)
|
||||
u'2 weeks'
|
||||
>>> timesince(t, t+4*oneday+5*oneminute)
|
||||
u'4 days'
|
||||
|
||||
# When the second date occurs before the first, we should always get 0 minutes.
|
||||
>>> timesince(t, t-onemicrosecond)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-onesecond)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-oneminute)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-onehour)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-oneday)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-oneweek)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-onemonth)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-oneyear)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-2*oneday-6*onehour)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-2*oneweek-2*oneday)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-2*oneweek-3*onehour-4*oneminute)
|
||||
u'0 minutes'
|
||||
>>> timesince(t, t-4*oneday-5*oneminute)
|
||||
u'0 minutes'
|
||||
"""
|
0
tests/regressiontests/views/__init__.py
Normal file
0
tests/regressiontests/views/__init__.py
Normal file
48
tests/regressiontests/views/fixtures/testdata.json
Normal file
48
tests/regressiontests/views/fixtures/testdata.json
Normal file
@ -0,0 +1,48 @@
|
||||
[
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "views.article",
|
||||
"fields": {
|
||||
"author": 1,
|
||||
"title": "Old Article",
|
||||
"slug": "old_article",
|
||||
"date_created": "2001-01-01 21:22:23"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "views.article",
|
||||
"fields": {
|
||||
"author": 1,
|
||||
"title": "Current Article",
|
||||
"slug": "current_article",
|
||||
"date_created": "2007-09-17 21:22:23"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "views.article",
|
||||
"fields": {
|
||||
"author": 1,
|
||||
"title": "Future Article",
|
||||
"slug": "future_article",
|
||||
"date_created": "3000-01-01 21:22:23"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "views.author",
|
||||
"fields": {
|
||||
"name": "Boris"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "sites.site",
|
||||
"fields": {
|
||||
"domain": "testserver",
|
||||
"name": "testserver"
|
||||
}
|
||||
}
|
||||
]
|
BIN
tests/regressiontests/views/locale/en/LC_MESSAGES/djangojs.mo
Normal file
BIN
tests/regressiontests/views/locale/en/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
@ -0,0 +1,20 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-09-15 16:45+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "this is to be translated"
|
||||
msgstr "this is to be translated in english"
|
BIN
tests/regressiontests/views/locale/es/LC_MESSAGES/djangojs.mo
Normal file
BIN
tests/regressiontests/views/locale/es/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
@ -0,0 +1,21 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-09-15 16:45+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: media/js/translate.js:1
|
||||
msgid "this is to be translated"
|
||||
msgstr "esto tiene que ser traducido"
|
BIN
tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.mo
Normal file
BIN
tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.mo
Normal file
Binary file not shown.
@ -0,0 +1,20 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-09-15 19:15+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "this is to be translated"
|
||||
msgstr "il faut le traduire"
|
1
tests/regressiontests/views/media/file.txt
Normal file
1
tests/regressiontests/views/media/file.txt
Normal file
@ -0,0 +1 @@
|
||||
An example media file.
|
26
tests/regressiontests/views/models.py
Normal file
26
tests/regressiontests/views/models.py
Normal file
@ -0,0 +1,26 @@
|
||||
"""
|
||||
Regression tests for Django built-in views
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
class Author(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def get_absolute_url(self):
|
||||
return '/views/authors/%s/' % self.id
|
||||
|
||||
|
||||
class Article(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
slug = models.SlugField()
|
||||
author = models.ForeignKey(Author)
|
||||
date_created = models.DateTimeField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
4
tests/regressiontests/views/tests/__init__.py
Normal file
4
tests/regressiontests/views/tests/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from defaults import *
|
||||
from i18n import *
|
||||
from static import *
|
||||
from generic.date_based import *
|
39
tests/regressiontests/views/tests/defaults.py
Normal file
39
tests/regressiontests/views/tests/defaults.py
Normal file
@ -0,0 +1,39 @@
|
||||
from os import path
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from regressiontests.views.models import Author, Article
|
||||
|
||||
class DefaultsTests(TestCase):
|
||||
"""Test django views in django/views/defaults.py"""
|
||||
fixtures = ['testdata.json']
|
||||
|
||||
def test_shorcut_with_absolute_url(self):
|
||||
"Can view a shortcut an Author object that has with a get_absolute_url method"
|
||||
for obj in Author.objects.all():
|
||||
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk)
|
||||
response = self.client.get(short_url)
|
||||
self.assertRedirects(response, 'http://testserver%s' % obj.get_absolute_url(),
|
||||
status_code=302, target_status_code=404)
|
||||
|
||||
def test_shortcut_no_absolute_url(self):
|
||||
"Shortcuts for an object that has with a get_absolute_url method raises 404"
|
||||
for obj in Article.objects.all():
|
||||
short_url = '/views/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk)
|
||||
response = self.client.get(short_url)
|
||||
self.assertEquals(response.status_code, 404)
|
||||
|
||||
def test_page_not_found(self):
|
||||
"A 404 status is returned by the page_not_found view"
|
||||
non_existing_urls = ['/views/non_existing_url/', # this is in urls.py
|
||||
'/views/other_non_existing_url/'] # this NOT in urls.py
|
||||
for url in non_existing_urls:
|
||||
response = self.client.get(url)
|
||||
self.assertEquals(response.status_code, 404)
|
||||
|
||||
def test_server_error(self):
|
||||
"The server_error view raises a 500 status"
|
||||
response = self.client.get('/views/server_error/')
|
||||
self.assertEquals(response.status_code, 500)
|
71
tests/regressiontests/views/tests/generic/date_based.py
Normal file
71
tests/regressiontests/views/tests/generic/date_based.py
Normal file
@ -0,0 +1,71 @@
|
||||
# coding: utf-8
|
||||
from django.test import TestCase
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from regressiontests.views.models import Article, Author
|
||||
|
||||
class ObjectDetailTest(TestCase):
|
||||
fixtures = ['testdata.json']
|
||||
def setUp(self):
|
||||
# Correct the date for the current article
|
||||
current_article = Article.objects.get(title="Current Article")
|
||||
current_article.date_created = datetime.now()
|
||||
current_article.save()
|
||||
|
||||
def test_finds_past(self):
|
||||
"date_based.object_detail can view a page in the past"
|
||||
response = self.client.get('/views/date_based/object_detail/2001/01/01/old_article/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context['object'].title, "Old Article")
|
||||
|
||||
def test_object_detail_finds_today(self):
|
||||
"date_based.object_detail can view a page from today"
|
||||
today_url = datetime.now().strftime('%Y/%m/%d')
|
||||
response = self.client.get('/views/date_based/object_detail/%s/current_article/' % today_url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context['object'].title, "Current Article")
|
||||
|
||||
def test_object_detail_ignores_future(self):
|
||||
"date_based.object_detail can view a page from the future, but only if allowed."
|
||||
response = self.client.get('/views/date_based/object_detail/3000/01/01/future_article/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_object_detail_allowed_future_if_enabled(self):
|
||||
"date_based.object_detail can view a page from the future if explicitly allowed."
|
||||
response = self.client.get('/views/date_based/object_detail/3000/01/01/future_article/allow_future/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context['object'].title, "Future Article")
|
||||
|
||||
class MonthArchiveTest(TestCase):
|
||||
def test_archive_month_includes_only_month(self):
|
||||
"Regression for #3031: Archives around Feburary include only one month"
|
||||
author = Author(name="John Smith")
|
||||
author.save()
|
||||
|
||||
# 2004 was a leap year, so it should be weird enough to not cheat
|
||||
first_second_of_feb = datetime(2004, 2, 1, 0, 0, 0)
|
||||
first_second_of_mar = datetime(2004, 3, 1, 0, 0, 0)
|
||||
one_microsecond = timedelta(0, 0, 1)
|
||||
article = Article(title="example", author=author)
|
||||
|
||||
article.date_created = first_second_of_feb
|
||||
article.save()
|
||||
response = self.client.get('/views/date_based/archive_month/2004/02/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
article.date_created = first_second_of_feb-one_microsecond
|
||||
article.save()
|
||||
response = self.client.get('/views/date_based/archive_month/2004/02/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
article.date_created = first_second_of_mar-one_microsecond
|
||||
article.save()
|
||||
response = self.client.get('/views/date_based/archive_month/2004/02/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
article.date_created = first_second_of_mar
|
||||
article.save()
|
||||
response = self.client.get('/views/date_based/archive_month/2004/02/')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
|
30
tests/regressiontests/views/tests/i18n.py
Normal file
30
tests/regressiontests/views/tests/i18n.py
Normal file
@ -0,0 +1,30 @@
|
||||
from os import path
|
||||
import gettext
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.utils.translation import activate
|
||||
|
||||
from regressiontests.views.urls import locale_dir
|
||||
|
||||
class I18NTests(TestCase):
|
||||
""" Tests django views in django/views/i18n.py """
|
||||
|
||||
def test_setlang(self):
|
||||
"""The set_language view can be used to change the session language"""
|
||||
for lang_code, lang_name in settings.LANGUAGES:
|
||||
post_data = dict(language=lang_code, next='/views/')
|
||||
response = self.client.post('/views/i18n/setlang/', data=post_data)
|
||||
self.assertRedirects(response, 'http://testserver/views/')
|
||||
self.assertEquals(self.client.session['django_language'], lang_code)
|
||||
|
||||
def test_jsi18n(self):
|
||||
"""The javascript_catalog can be deployed with language settings"""
|
||||
for lang_code in ['es', 'fr', 'en']:
|
||||
activate(lang_code)
|
||||
catalog = gettext.translation('djangojs', locale_dir, [lang_code])
|
||||
trans_txt = catalog.ugettext('this is to be translated')
|
||||
response = self.client.get('/views/jsi18n/')
|
||||
# in response content must to be a line like that:
|
||||
# catalog['this is to be translated'] = 'same_that_trans_txt'
|
||||
self.assertContains(response, trans_txt, 1)
|
15
tests/regressiontests/views/tests/static.py
Normal file
15
tests/regressiontests/views/tests/static.py
Normal file
@ -0,0 +1,15 @@
|
||||
from os import path
|
||||
|
||||
from django.test import TestCase
|
||||
from regressiontests.views.urls import media_dir
|
||||
|
||||
class StaticTests(TestCase):
|
||||
"""Tests django views in django/views/static.py"""
|
||||
|
||||
def test_serve(self):
|
||||
"The static view can serve static media"
|
||||
media_files = ['file.txt',]
|
||||
for filename in media_files:
|
||||
response = self.client.get('/views/site_media/%s' % filename)
|
||||
file = open(path.join(media_dir, filename))
|
||||
self.assertEquals(file.read(), response.content)
|
48
tests/regressiontests/views/urls.py
Normal file
48
tests/regressiontests/views/urls.py
Normal file
@ -0,0 +1,48 @@
|
||||
from os import path
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
from models import *
|
||||
import views
|
||||
|
||||
base_dir = path.dirname(path.abspath(__file__))
|
||||
media_dir = path.join(base_dir, 'media')
|
||||
locale_dir = path.join(base_dir, 'locale')
|
||||
|
||||
js_info_dict = {
|
||||
'domain': 'djangojs',
|
||||
'packages': ('regressiontests.views',),
|
||||
}
|
||||
|
||||
date_based_info_dict = {
|
||||
'queryset': Article.objects.all(),
|
||||
'date_field': 'date_created',
|
||||
'month_format': '%m',
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', views.index_page),
|
||||
|
||||
# Default views
|
||||
(r'^shortcut/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
|
||||
(r'^non_existing_url/', 'django.views.defaults.page_not_found'),
|
||||
(r'^server_error/', 'django.views.defaults.server_error'),
|
||||
|
||||
# i18n views
|
||||
(r'^i18n/', include('django.conf.urls.i18n')),
|
||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
||||
|
||||
# Static views
|
||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': media_dir}),
|
||||
|
||||
# Date-based generic views
|
||||
(r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$',
|
||||
'django.views.generic.date_based.object_detail',
|
||||
dict(slug_field='slug', **date_based_info_dict)),
|
||||
(r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/allow_future/$',
|
||||
'django.views.generic.date_based.object_detail',
|
||||
dict(allow_future=True, slug_field='slug', **date_based_info_dict)),
|
||||
(r'^date_based/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',
|
||||
'django.views.generic.date_based.archive_month',
|
||||
date_based_info_dict),
|
||||
)
|
7
tests/regressiontests/views/views.py
Normal file
7
tests/regressiontests/views/views.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.http import HttpResponse
|
||||
from django.template import RequestContext
|
||||
|
||||
def index_page(request):
|
||||
"""Dummy index page"""
|
||||
return HttpResponse('<html><body>Dummy page</body></html>')
|
||||
|
1
tests/templates/views/article_archive_month.html
Normal file
1
tests/templates/views/article_archive_month.html
Normal file
@ -0,0 +1 @@
|
||||
This template intentionally left blank
|
1
tests/templates/views/article_detail.html
Normal file
1
tests/templates/views/article_detail.html
Normal file
@ -0,0 +1 @@
|
||||
This template intentionally left blank
|
@ -11,4 +11,7 @@ urlpatterns = patterns('',
|
||||
|
||||
# test urlconf for {% url %} template tag
|
||||
(r'^url_tag/', include('regressiontests.templates.urls')),
|
||||
|
||||
# django built-in views
|
||||
(r'^views/', include('regressiontests.views.urls')),
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user