1
0
mirror of https://github.com/django/django.git synced 2025-07-04 01:39:20 +00:00

newforms-admin: Merged to [6416]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6417 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2007-09-25 00:08:38 +00:00
parent afb8f0a619
commit 609eaf130d
86 changed files with 7202 additions and 6410 deletions

View File

@ -49,6 +49,7 @@ answer newbie questions, and generally made Django that much better:
andy@jadedplanet.net andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com> Fabrice Aneche <akh@nobugware.com>
ant9000@netwise.it ant9000@netwise.it
Florian Apolloner
David Ascher <http://ascher.ca/> David Ascher <http://ascher.ca/>
david@kazserve.org david@kazserve.org
Arthur <avandorp@gmail.com> Arthur <avandorp@gmail.com>
@ -244,7 +245,6 @@ answer newbie questions, and generally made Django that much better:
phil@produxion.net phil@produxion.net
phil.h.smith@gmail.com phil.h.smith@gmail.com
Gustavo Picon Gustavo Picon
pigletto
Luke Plant <http://lukeplant.me.uk/> Luke Plant <http://lukeplant.me.uk/>
plisk plisk
Daniel Poelzleithner <http://poelzi.org/> Daniel Poelzleithner <http://poelzi.org/>
@ -281,6 +281,7 @@ answer newbie questions, and generally made Django that much better:
sopel sopel
Leo Soto <leo.soto@gmail.com> Leo Soto <leo.soto@gmail.com>
Wiliam Alves de Souza <wiliamsouza83@gmail.com> Wiliam Alves de Souza <wiliamsouza83@gmail.com>
Don Spaulding <donspauldingii@gmail.com>
Bjørn Stabell <bjorn@exoweb.net> Bjørn Stabell <bjorn@exoweb.net>
Georgi Stanojevski <glisha@gmail.com> Georgi Stanojevski <glisha@gmail.com>
Vasiliy Stavenko <stavenko@gmail.com> Vasiliy Stavenko <stavenko@gmail.com>
@ -325,6 +326,7 @@ answer newbie questions, and generally made Django that much better:
Rachel Willmer <http://www.willmer.com/kb/> Rachel Willmer <http://www.willmer.com/kb/>
Gary Wilson <gary.wilson@gmail.com> Gary Wilson <gary.wilson@gmail.com>
Jakub Wiśniowski <restless.being@gmail.com> Jakub Wiśniowski <restless.being@gmail.com>
Maciej Wiśniowski <pigletto@gmail.com>
wojtek wojtek
ye7cakf02@sneakemail.com ye7cakf02@sneakemail.com
ymasuda@ethercube.com ymasuda@ethercube.com

View File

@ -40,7 +40,7 @@ class FieldWidgetNode(template.Node):
default = None default = None
def __init__(self, bound_field_var): def __init__(self, bound_field_var):
self.bound_field_var = bound_field_var self.bound_field_var = template.Variable(bound_field_var)
def get_nodelist(cls, klass): def get_nodelist(cls, klass):
if klass not in cls.nodelists: if klass not in cls.nodelists:
@ -64,7 +64,7 @@ class FieldWidgetNode(template.Node):
get_nodelist = classmethod(get_nodelist) get_nodelist = classmethod(get_nodelist)
def render(self, context): def render(self, context):
bound_field = template.resolve_variable(self.bound_field_var, context) bound_field = self.bound_field_var.resolve(context)
context.push() context.push()
context['bound_field'] = bound_field context['bound_field'] = bound_field

View File

@ -1,3 +1,4 @@
from django.db import connection
from django.contrib.auth.models import User from django.contrib.auth.models import User
class ModelBackend: class ModelBackend:
@ -14,6 +15,49 @@ class ModelBackend:
except User.DoesNotExist: except User.DoesNotExist:
return None 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): def get_user(self, user_id):
try: try:
return User.objects.get(pk=user_id) return User.objects.get(pk=user_id)

View File

@ -1,6 +1,7 @@
from django.contrib import auth
from django.core import validators from django.core import validators
from django.core.exceptions import ImproperlyConfigured 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.db.models.manager import EmptyManager
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
@ -195,64 +196,68 @@ class User(models.Model):
return self.password != UNUSABLE_PASSWORD return self.password != UNUSABLE_PASSWORD
def get_group_permissions(self): 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'): Returns a list of permission strings that this user has through
cursor = connection.cursor() his/her groups. This method queries all available auth backends.
# The SQL below works out to the following, after DB quoting: """
# cursor.execute(""" permissions = set()
# SELECT ct."app_label", p."codename" for backend in auth.get_backends():
# FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct if hasattr(backend, "get_group_permissions"):
# WHERE p."id" = gp."permission_id" permissions.update(backend.get_group_permissions(self))
# AND gp."group_id" = ug."group_id" return permissions
# 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
def get_all_permissions(self): def get_all_permissions(self):
if not hasattr(self, '_perm_cache'): permissions = set()
self._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()]) for backend in auth.get_backends():
self._perm_cache.update(self.get_group_permissions()) if hasattr(backend, "get_all_permissions"):
return self._perm_cache permissions.update(backend.get_all_permissions(self))
return permissions
def has_perm(self, perm): 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: if not self.is_active:
return False return False
# Superusers have all permissions.
if self.is_superuser: if self.is_superuser:
return True 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): 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: for perm in perm_list:
if not self.has_perm(perm): if not self.has_perm(perm):
return False return False
return True return True
def has_module_perms(self, app_label): 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: if not self.is_active:
return False return False
if self.is_superuser: if self.is_superuser:
return True 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): def get_and_delete_messages(self):
messages = [] messages = []
@ -285,7 +290,12 @@ class User(models.Model):
class Message(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) user = models.ForeignKey(User)
message = models.TextField(_('message')) message = models.TextField(_('message'))

View File

@ -19,6 +19,8 @@ class CommentFormNode(template.Node):
ratings_optional=False, ratings_required=False, rating_options='', ratings_optional=False, ratings_required=False, rating_options='',
is_public=True): is_public=True):
self.content_type = content_type self.content_type = content_type
if obj_id_lookup_var is not None:
obj_id_lookup_var = template.Variable(obj_id_lookup_var)
self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free
self.photos_optional, self.photos_required = photos_optional, photos_required self.photos_optional, self.photos_required = photos_optional, photos_required
self.ratings_optional, self.ratings_required = ratings_optional, ratings_required self.ratings_optional, self.ratings_required = ratings_optional, ratings_required
@ -32,7 +34,7 @@ class CommentFormNode(template.Node):
context.push() context.push()
if self.obj_id_lookup_var is not None: if self.obj_id_lookup_var is not None:
try: try:
self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context) self.obj_id = self.obj_id_lookup_var.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' return ''
# Validate that this object ID is valid for this content-type. # Validate that this object ID is valid for this content-type.
@ -75,6 +77,8 @@ class CommentFormNode(template.Node):
class CommentCountNode(template.Node): class CommentCountNode(template.Node):
def __init__(self, package, module, context_var_name, obj_id, var_name, free): def __init__(self, package, module, context_var_name, obj_id, var_name, free):
self.package, self.module = package, module self.package, self.module = package, module
if context_var_name is not None:
context_var_name = template.Variable(context_var_name)
self.context_var_name, self.obj_id = context_var_name, obj_id self.context_var_name, self.obj_id = context_var_name, obj_id
self.var_name, self.free = var_name, free self.var_name, self.free = var_name, free
@ -82,7 +86,7 @@ class CommentCountNode(template.Node):
from django.conf import settings from django.conf import settings
manager = self.free and FreeComment.objects or Comment.objects manager = self.free and FreeComment.objects or Comment.objects
if self.context_var_name is not None: if self.context_var_name is not None:
self.obj_id = template.resolve_variable(self.context_var_name, context) self.obj_id = self.context_var_name.resolve(context)
comment_count = manager.filter(object_id__exact=self.obj_id, comment_count = manager.filter(object_id__exact=self.obj_id,
content_type__app_label__exact=self.package, content_type__app_label__exact=self.package,
content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
@ -92,6 +96,8 @@ class CommentCountNode(template.Node):
class CommentListNode(template.Node): class CommentListNode(template.Node):
def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
self.package, self.module = package, module self.package, self.module = package, module
if context_var_name is not None:
context_var_name = template.Variable(context_var_name)
self.context_var_name, self.obj_id = context_var_name, obj_id self.context_var_name, self.obj_id = context_var_name, obj_id
self.var_name, self.free = var_name, free self.var_name, self.free = var_name, free
self.ordering = ordering self.ordering = ordering
@ -102,7 +108,7 @@ class CommentListNode(template.Node):
get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
if self.context_var_name is not None: if self.context_var_name is not None:
try: try:
self.obj_id = template.resolve_variable(self.context_var_name, context) self.obj_id = self.context_var_name.resolve(context)
except template.VariableDoesNotExist: except template.VariableDoesNotExist:
return '' return ''
kwargs = { kwargs = {

View File

@ -16,7 +16,6 @@ class SessionBase(object):
""" """
Base class for all Session classes. Base class for all Session classes.
""" """
TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked' TEST_COOKIE_VALUE = 'worked'
@ -59,7 +58,7 @@ class SessionBase(object):
def delete_test_cookie(self): def delete_test_cookie(self):
del self[self.TEST_COOKIE_NAME] del self[self.TEST_COOKIE_NAME]
def encode(self, session_dict): def encode(self, session_dict):
"Returns the given session dictionary pickled and encoded as a string." "Returns the given session dictionary pickled and encoded as a string."
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL) pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
@ -77,28 +76,33 @@ class SessionBase(object):
# just return an empty dictionary (an empty session). # just return an empty dictionary (an empty session).
except: except:
return {} return {}
def _get_new_session_key(self): def _get_new_session_key(self):
"Returns session key that isn't being used." "Returns session key that isn't being used."
# The random module is seeded when this Apache child is created. # The random module is seeded when this Apache child is created.
# Use settings.SECRET_KEY as added salt. # Use settings.SECRET_KEY as added salt.
try:
pid = os.getpid()
except AttributeError:
# No getpid() in Jython, for example
pid = 1
while 1: while 1:
session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest() pid, time.time(), settings.SECRET_KEY)).hexdigest()
if not self.exists(session_key): if not self.exists(session_key):
break break
return session_key return session_key
def _get_session_key(self): def _get_session_key(self):
if self._session_key: if self._session_key:
return self._session_key return self._session_key
else: else:
self._session_key = self._get_new_session_key() self._session_key = self._get_new_session_key()
return self._session_key return self._session_key
def _set_session_key(self, session_key): def _set_session_key(self, session_key):
self._session_key = session_key self._session_key = session_key
session_key = property(_get_session_key, _set_session_key) session_key = property(_get_session_key, _set_session_key)
def _get_session(self): def _get_session(self):
@ -114,9 +118,9 @@ class SessionBase(object):
return self._session_cache return self._session_cache
_session = property(_get_session) _session = property(_get_session)
# Methods that child classes must implement. # Methods that child classes must implement.
def exists(self, session_key): def exists(self, session_key):
""" """
Returns True if the given session_key already exists. Returns True if the given session_key already exists.
@ -140,4 +144,3 @@ class SessionBase(object):
Loads the session data and returns a dictionary. Loads the session data and returns a dictionary.
""" """
raise NotImplementedError raise NotImplementedError

View File

@ -1,18 +1,104 @@
import django import django
from django.core.management.base import BaseCommand, CommandError, handle_default_options
from optparse import OptionParser from optparse import OptionParser
import os import os
import sys import sys
from imp import find_module
# For backwards compatibility: get_version() used to be in this module. # For backwards compatibility: get_version() used to be in this module.
get_version = django.get_version get_version = django.get_version
def load_command_class(name): # A cache of loaded commands, so that call_command
# doesn't have to reload every time it is called
_commands = None
def find_commands(management_dir):
""" """
Given a command name, returns the Command class instance. Raises Given a path to a management directory, return a list of all the command names
ImportError if it doesn't exist. that are available. Returns an empty list if no commands are defined.
""" """
# Let the ImportError propogate. command_dir = os.path.join(management_dir,'commands')
return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() try:
return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
except OSError:
return []
def find_management_module(app_name):
"""
Determine the path to the management module for the application named,
without acutally importing the application or the management module.
Raises ImportError if the management module cannot be found for any reason.
"""
parts = app_name.split('.')
parts.append('management')
parts.reverse()
path = None
while parts:
part = parts.pop()
f,path,descr = find_module(part, path and [path] or None)
return path
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns the Command
class instance. All errors raised by the importation process
(ImportError, AttributeError) are allowed to propagate.
"""
return getattr(__import__('%s.management.commands.%s' % (app_name, name),
{}, {}, ['Command']), 'Command')()
def get_commands(load_user_commands=True, project_directory=None):
"""
Returns a dictionary of commands against the application in which
those commands can be found. This works by looking for a
management.commands package in django.core, and in each installed
application -- if a commands package exists, all commands in that
package are registered.
Core commands are always included; user-defined commands will also
be included if ``load_user_commands`` is True. If a project directory
is provided, the startproject command will be disabled, and the
startapp command will be modified to use that directory.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e.g., with the
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
The dictionary is cached on the first call, and reused on subsequent
calls.
"""
global _commands
if _commands is None:
_commands = dict([(name, 'django.core')
for name in find_commands(__path__[0])])
if load_user_commands:
# Get commands from all installed apps
from django.conf import settings
for app_name in settings.INSTALLED_APPS:
try:
path = find_management_module(app_name)
_commands.update(dict([(name, app_name)
for name in find_commands(path)]))
except ImportError:
pass # No management module - ignore this app
if project_directory:
# Remove the "startproject" command from self.commands, because
# that's a django-admin.py command, not a manage.py command.
del _commands['startproject']
# Override the startapp command so that it always uses the
# project_directory, not the current working directory
# (which is default).
from django.core.management.commands.startapp import ProjectCommand
_commands['startapp'] = ProjectCommand(project_directory)
return _commands
def call_command(name, *args, **options): def call_command(name, *args, **options):
""" """
@ -25,8 +111,26 @@ def call_command(name, *args, **options):
call_command('shell', plain=True) call_command('shell', plain=True)
call_command('sqlall', 'myapp') call_command('sqlall', 'myapp')
""" """
klass = load_command_class(name) try:
app_name = get_commands()[name]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
else:
klass = load_command_class(app_name, name)
except KeyError:
raise CommandError, "Unknown command: %r" % name
return klass.execute(*args, **options) return klass.execute(*args, **options)
class LaxOptionParser(OptionParser):
"""
An option parser that doesn't raise any errors on unknown options.
This is needed because the --settings and --pythonpath options affect
the commands (and thus the options) that are available to the user.
"""
def error(self, msg):
pass
class ManagementUtility(object): class ManagementUtility(object):
""" """
@ -38,21 +142,9 @@ class ManagementUtility(object):
def __init__(self, argv=None): def __init__(self, argv=None):
self.argv = argv or sys.argv[:] self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0]) self.prog_name = os.path.basename(self.argv[0])
self.commands = self.default_commands() self.project_directory = None
self.user_commands = False
def default_commands(self):
"""
Returns a dictionary of instances of all available Command classes.
This works by looking for and loading all Python modules in the
django.core.management.commands package.
The dictionary is in the format {name: command_instance}.
"""
command_dir = os.path.join(__path__[0], 'commands')
names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
return dict([(name, load_command_class(name)) for name in names])
def main_help_text(self): def main_help_text(self):
""" """
Returns the script's main help text, as a string. Returns the script's main help text, as a string.
@ -61,7 +153,7 @@ class ManagementUtility(object):
usage.append('Django command line tool, version %s' % django.get_version()) usage.append('Django command line tool, version %s' % django.get_version())
usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name) usage.append("Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name)
usage.append('Available subcommands:') usage.append('Available subcommands:')
commands = self.commands.keys() commands = get_commands(self.user_commands, self.project_directory).keys()
commands.sort() commands.sort()
for cmd in commands: for cmd in commands:
usage.append(' %s' % cmd) usage.append(' %s' % cmd)
@ -74,16 +166,33 @@ class ManagementUtility(object):
django-admin.py or manage.py) if it can't be found. django-admin.py or manage.py) if it can't be found.
""" """
try: try:
return self.commands[subcommand] app_name = get_commands(self.user_commands, self.project_directory)[subcommand]
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
klass = app_name
else:
klass = load_command_class(app_name, subcommand)
except KeyError: except KeyError:
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name)) sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % (subcommand, self.prog_name))
sys.exit(1) sys.exit(1)
return klass
def execute(self): def execute(self):
""" """
Given the command-line arguments, this figures out which subcommand is Given the command-line arguments, this figures out which subcommand is
being run, creates a parser appropriate to that command, and runs it. being run, creates a parser appropriate to that command, and runs it.
""" """
# Preprocess options to extract --settings and --pythonpath. These options
# could affect the commands that are available, so they must be processed
# early
parser = LaxOptionParser(version=get_version(),
option_list=BaseCommand.option_list)
try:
options, args = parser.parse_args(self.argv)
handle_default_options(options)
except:
pass # Ignore any option errors at this point.
try: try:
subcommand = self.argv[1] subcommand = self.argv[1]
except IndexError: except IndexError:
@ -91,8 +200,8 @@ class ManagementUtility(object):
sys.exit(1) sys.exit(1)
if subcommand == 'help': if subcommand == 'help':
if len(self.argv) > 2: if len(args) > 2:
self.fetch_command(self.argv[2]).print_help(self.prog_name, self.argv[2]) self.fetch_command(args[2]).print_help(self.prog_name, args[2])
else: else:
sys.stderr.write(self.main_help_text() + '\n') sys.stderr.write(self.main_help_text() + '\n')
sys.exit(1) sys.exit(1)
@ -116,16 +225,9 @@ class ProjectManagementUtility(ManagementUtility):
""" """
def __init__(self, argv, project_directory): def __init__(self, argv, project_directory):
super(ProjectManagementUtility, self).__init__(argv) super(ProjectManagementUtility, self).__init__(argv)
self.project_directory = project_directory
# Remove the "startproject" command from self.commands, because self.user_commands = True
# that's a django-admin.py command, not a manage.py command.
del self.commands['startproject']
# Override the startapp command so that it always uses the
# project_directory, not the current working directory (which is default).
from django.core.management.commands.startapp import ProjectCommand
self.commands['startapp'] = ProjectCommand(project_directory)
def setup_environ(settings_mod): def setup_environ(settings_mod):
""" """
Configure the runtime environment. This can also be used by external Configure the runtime environment. This can also be used by external

View File

@ -9,6 +9,17 @@ import os
class CommandError(Exception): class CommandError(Exception):
pass pass
def handle_default_options(options):
"""
Include any default options that all commands should accept
here so that ManagementUtility can handle them before searching
for user commands.
"""
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
class BaseCommand(object): class BaseCommand(object):
# Metadata about this command. # Metadata about this command.
option_list = ( option_list = (
@ -55,10 +66,7 @@ class BaseCommand(object):
def run_from_argv(self, argv): def run_from_argv(self, argv):
parser = self.create_parser(argv[0], argv[1]) parser = self.create_parser(argv[0], argv[1])
options, args = parser.parse_args(argv[2:]) options, args = parser.parse_args(argv[2:])
if options.settings: handle_default_options(options)
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
if options.pythonpath:
sys.path.insert(0, options.pythonpath)
self.execute(*args, **options.__dict__) self.execute(*args, **options.__dict__)
def execute(self, *args, **options): def execute(self, *args, **options):

View File

@ -6,10 +6,10 @@ DATA_TYPES = {
'DateField': 'smalldatetime', 'DateField': 'smalldatetime',
'DateTimeField': 'smalldatetime', 'DateTimeField': 'smalldatetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)', 'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(100)', 'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision', 'FloatField': 'double precision',
'ImageField': 'varchar(100)', 'ImageField': 'varchar(%(max_length)s)',
'IntegerField': 'int', 'IntegerField': 'int',
'IPAddressField': 'char(15)', 'IPAddressField': 'char(15)',
'NullBooleanField': 'bit', 'NullBooleanField': 'bit',

View File

@ -10,10 +10,10 @@ DATA_TYPES = {
'DateField': 'date', 'DateField': 'date',
'DateTimeField': 'datetime', 'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)', 'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(100)', 'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision', 'FloatField': 'double precision',
'ImageField': 'varchar(100)', 'ImageField': 'varchar(%(max_length)s)',
'IntegerField': 'integer', 'IntegerField': 'integer',
'IPAddressField': 'char(15)', 'IPAddressField': 'char(15)',
'NullBooleanField': 'bool', 'NullBooleanField': 'bool',

View File

@ -10,10 +10,10 @@ DATA_TYPES = {
'DateField': 'date', 'DateField': 'date',
'DateTimeField': 'datetime', 'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)', 'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(100)', 'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision', 'FloatField': 'double precision',
'ImageField': 'varchar(100)', 'ImageField': 'varchar(%(max_length)s)',
'IntegerField': 'integer', 'IntegerField': 'integer',
'IPAddressField': 'char(15)', 'IPAddressField': 'char(15)',
'NullBooleanField': 'bool', 'NullBooleanField': 'bool',

View File

@ -13,10 +13,10 @@ DATA_TYPES = {
'DateField': 'DATE', 'DateField': 'DATE',
'DateTimeField': 'TIMESTAMP', 'DateTimeField': 'TIMESTAMP',
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
'FileField': 'NVARCHAR2(100)', 'FileField': 'NVARCHAR2(%(max_length)s)',
'FilePathField': 'NVARCHAR2(100)', 'FilePathField': 'NVARCHAR2(%(max_length)s)',
'FloatField': 'DOUBLE PRECISION', 'FloatField': 'DOUBLE PRECISION',
'ImageField': 'NVARCHAR2(100)', 'ImageField': 'NVARCHAR2(%(max_length)s)',
'IntegerField': 'NUMBER(11)', 'IntegerField': 'NUMBER(11)',
'IPAddressField': 'VARCHAR2(15)', 'IPAddressField': 'VARCHAR2(15)',
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', 'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
@ -28,7 +28,7 @@ DATA_TYPES = {
'SmallIntegerField': 'NUMBER(11)', 'SmallIntegerField': 'NUMBER(11)',
'TextField': 'NCLOB', 'TextField': 'NCLOB',
'TimeField': 'TIMESTAMP', 'TimeField': 'TIMESTAMP',
'URLField': 'VARCHAR2(200)', 'URLField': 'VARCHAR2(%(max_length)s)',
'USStateField': 'CHAR(2)', 'USStateField': 'CHAR(2)',
} }

View File

@ -10,10 +10,10 @@ DATA_TYPES = {
'DateField': 'date', 'DateField': 'date',
'DateTimeField': 'timestamp with time zone', 'DateTimeField': 'timestamp with time zone',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)', 'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(100)', 'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision', 'FloatField': 'double precision',
'ImageField': 'varchar(100)', 'ImageField': 'varchar(%(max_length)s)',
'IntegerField': 'integer', 'IntegerField': 'integer',
'IPAddressField': 'inet', 'IPAddressField': 'inet',
'NullBooleanField': 'boolean', 'NullBooleanField': 'boolean',

View File

@ -9,10 +9,10 @@ DATA_TYPES = {
'DateField': 'date', 'DateField': 'date',
'DateTimeField': 'datetime', 'DateTimeField': 'datetime',
'DecimalField': 'decimal', 'DecimalField': 'decimal',
'FileField': 'varchar(100)', 'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(100)', 'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'real', 'FloatField': 'real',
'ImageField': 'varchar(100)', 'ImageField': 'varchar(%(max_length)s)',
'IntegerField': 'integer', 'IntegerField': 'integer',
'IPAddressField': 'char(15)', 'IPAddressField': 'char(15)',
'NullBooleanField': 'bool', 'NullBooleanField': 'bool',

View File

@ -684,8 +684,7 @@ class DecimalField(Field):
class EmailField(CharField): class EmailField(CharField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if 'max_length' not in kwargs: kwargs['max_length'] = kwargs.get('max_length', 75)
kwargs['max_length'] = 75
CharField.__init__(self, *args, **kwargs) CharField.__init__(self, *args, **kwargs)
def get_internal_type(self): def get_internal_type(self):
@ -705,6 +704,7 @@ class EmailField(CharField):
class FileField(Field): class FileField(Field):
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs): def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
self.upload_to = upload_to self.upload_to = upload_to
kwargs['max_length'] = kwargs.get('max_length', 100)
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
@ -806,6 +806,7 @@ class FileField(Field):
class FilePathField(Field): class FilePathField(Field):
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs): def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
self.path, self.match, self.recursive = path, match, recursive self.path, self.match, self.recursive = path, match, recursive
kwargs['max_length'] = kwargs.get('max_length', 100)
Field.__init__(self, verbose_name, name, **kwargs) Field.__init__(self, verbose_name, name, **kwargs)
def get_manipulator_field_objs(self): def get_manipulator_field_objs(self):

View File

@ -1180,7 +1180,7 @@ def delete_objects(seen_objs):
if field.rel and field.null and field.rel.to in seen_objs: if field.rel and field.null and field.rel.to in seen_objs:
setattr(instance, field.attname, None) setattr(instance, field.attname, None)
setattr(instance, cls._meta.pk.attname, None)
dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance) dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance)
setattr(instance, cls._meta.pk.attname, None)
transaction.commit_unless_managed() transaction.commit_unless_managed()

View File

@ -54,8 +54,7 @@ class SetRemoteAddrFromForwardedFor(object):
except KeyError: except KeyError:
return None return None
else: else:
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. The
# Take just the last one. # client's IP will be the first one.
# See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/ real_ip = real_ip.split(",")[0].strip()
real_ip = real_ip.split(",")[-1].strip()
request.META['REMOTE_ADDR'] = real_ip request.META['REMOTE_ADDR'] = real_ip

View File

@ -447,7 +447,7 @@ class LargeTextField(TextField):
self.field_name, self.rows, self.cols, escape(data)) self.field_name, self.rows, self.cols, escape(data))
class HiddenField(FormField): 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 = [] if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required self.field_name, self.is_required = field_name, is_required
self.validator_list = validator_list[:] self.validator_list = validator_list[:]
@ -674,7 +674,7 @@ class CheckboxSelectMultipleField(SelectMultipleField):
#################### ####################
class FileUploadField(FormField): 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 = [] if validator_list is None: validator_list = []
self.field_name, self.is_required = field_name, is_required self.field_name, self.is_required = field_name, is_required
self.validator_list = [self.isNonEmptyFile] + validator_list self.validator_list = [self.isNonEmptyFile] + validator_list
@ -946,7 +946,7 @@ class IPAddressField(TextField):
class FilePathField(SelectField): class FilePathField(SelectField):
"A SelectField whose choices are the files in a given directory." "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 import os
from django.db.models import BLANK_CHOICE_DASH from django.db.models import BLANK_CHOICE_DASH
if match is not None: if match is not None:

View File

@ -88,8 +88,6 @@ UNKNOWN_SOURCE="&lt;unknown source&gt;"
tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
# matches if the string is valid number
number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
# global dictionary of libraries that have been loaded using get_library # global dictionary of libraries that have been loaded using get_library
libraries = {} libraries = {}
@ -564,18 +562,19 @@ class FilterExpression(object):
elif constant_arg is not None: elif constant_arg is not None:
args.append((False, constant_arg.replace(r'\"', '"'))) args.append((False, constant_arg.replace(r'\"', '"')))
elif var_arg: elif var_arg:
args.append((True, var_arg)) args.append((True, Variable(var_arg)))
filter_func = parser.find_filter(filter_name) filter_func = parser.find_filter(filter_name)
self.args_check(filter_name,filter_func, args) self.args_check(filter_name,filter_func, args)
filters.append( (filter_func,args)) filters.append( (filter_func,args))
upto = match.end() upto = match.end()
if upto != len(token): if upto != len(token):
raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token) raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
self.var, self.filters = var, filters self.filters = filters
self.var = Variable(var)
def resolve(self, context, ignore_failures=False): def resolve(self, context, ignore_failures=False):
try: try:
obj = resolve_variable(self.var, context) obj = self.var.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
if ignore_failures: if ignore_failures:
obj = None obj = None
@ -595,7 +594,7 @@ class FilterExpression(object):
if not lookup: if not lookup:
arg_vals.append(arg) arg_vals.append(arg)
else: else:
arg_vals.append(resolve_variable(arg, context)) arg_vals.append(arg.resolve(context))
obj = func(obj, *arg_vals) obj = func(obj, *arg_vals)
return obj return obj
@ -637,37 +636,98 @@ class FilterExpression(object):
def resolve_variable(path, context): def resolve_variable(path, context):
""" """
Returns the resolved variable, which may contain attribute syntax, within Returns the resolved variable, which may contain attribute syntax, within
the given context. The variable may be a hard-coded string (if it begins the given context.
and ends with single or double quote marks).
Deprecated; use the Variable class instead.
"""
return Variable(path).resolve(context)
>>> c = {'article': {'section':'News'}} class Variable(object):
>>> resolve_variable('article.section', c) """
u'News' A template variable, resolvable against a given context. The variable may be
>>> resolve_variable('article', c) a hard-coded string (if it begins and ends with single or double quote
{'section': 'News'} marks)::
>>> class AClass: pass
>>> c = AClass() >>> c = {'article': {'section':'News'}}
>>> c.article = AClass() >>> Variable('article.section').resolve(c)
>>> c.article.section = 'News' u'News'
>>> resolve_variable('article.section', c) >>> Variable('article').resolve(c)
u'News' {'section': 'News'}
>>> class AClass: pass
>>> c = AClass()
>>> c.article = AClass()
>>> c.article.section = 'News'
>>> Variable('article.section').resolve(c)
u'News'
(The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
""" """
if number_re.match(path):
number_type = '.' in path and float or int def __init__(self, var):
current = number_type(path) self.var = var
elif path[0] in ('"', "'") and path[0] == path[-1]: self.literal = None
current = path[1:-1] self.lookups = None
else:
try:
# First try to treat this variable as a number.
#
# Note that this could cause an OverflowError here that we're not
# catching. Since this should only happen at compile time, that's
# probably OK.
self.literal = float(var)
# So it's a float... is it an int? If the original value contained a
# dot or an "e" then it was a float, not an int.
if '.' not in var and 'e' not in var.lower():
self.literal = int(self.literal)
# "2." is invalid
if var.endswith('.'):
raise ValueError
except ValueError:
# A ValueError means that the variable isn't a number.
# If it's wrapped with quotes (single or double), then
# we're also dealing with a literal.
if var[0] in "\"'" and var[0] == var[-1]:
self.literal = var[1:-1]
else:
# Otherwise we'll set self.lookups so that resolve() knows we're
# dealing with a bonafide variable
self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR))
def resolve(self, context):
"""Resolve this variable against a given context."""
if self.lookups is not None:
# We're dealing with a variable that needs to be resolved
return self._resolve_lookup(context)
else:
# We're dealing with a literal, so it's already been "resolved"
return self.literal
def __repr__(self):
return "<%s: %r>" % (self.__class__.__name__, self.var)
def __str__(self):
return self.var
def _resolve_lookup(self, context):
"""
Performs resolution of a real variable (i.e. not a literal) against the
given context.
As indicated by the method's name, this method is an implementation
detail and shouldn't be called by external code. Use Variable.resolve()
instead.
"""
current = context current = context
bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) for bit in self.lookups:
while bits:
try: # dictionary lookup try: # dictionary lookup
current = current[bits[0]] current = current[bit]
except (TypeError, AttributeError, KeyError): except (TypeError, AttributeError, KeyError):
try: # attribute lookup try: # attribute lookup
current = getattr(current, bits[0]) current = getattr(current, bit)
if callable(current): if callable(current):
if getattr(current, 'alters_data', False): if getattr(current, 'alters_data', False):
current = settings.TEMPLATE_STRING_IF_INVALID current = settings.TEMPLATE_STRING_IF_INVALID
@ -685,27 +745,27 @@ def resolve_variable(path, context):
raise raise
except (TypeError, AttributeError): except (TypeError, AttributeError):
try: # list-index lookup try: # list-index lookup
current = current[int(bits[0])] current = current[int(bit)]
except (IndexError, # list index out of range except (IndexError, # list index out of range
ValueError, # invalid literal for int() ValueError, # invalid literal for int()
KeyError, # current is a dict without `int(bits[0])` key KeyError, # current is a dict without `int(bit)` key
TypeError, # unsubscriptable object TypeError, # unsubscriptable object
): ):
raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
except Exception, e: except Exception, e:
if getattr(e, 'silent_variable_failure', False): if getattr(e, 'silent_variable_failure', False):
current = settings.TEMPLATE_STRING_IF_INVALID current = settings.TEMPLATE_STRING_IF_INVALID
else: else:
raise raise
del bits[0]
if isinstance(current, (basestring, Promise)): if isinstance(current, (basestring, Promise)):
try: try:
current = force_unicode(current) current = force_unicode(current)
except UnicodeDecodeError: except UnicodeDecodeError:
# Failing to convert to unicode can happen sometimes (e.g. debug # Failing to convert to unicode can happen sometimes (e.g. debug
# tracebacks). So we allow it in this particular instance. # tracebacks). So we allow it in this particular instance.
pass pass
return current return current
class Node(object): class Node(object):
def render(self, context): def render(self, context):
@ -861,10 +921,10 @@ class Library(object):
class SimpleNode(Node): class SimpleNode(Node):
def __init__(self, vars_to_resolve): def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve self.vars_to_resolve = map(Variable, vars_to_resolve)
def render(self, context): def render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
return func(*resolved_vars) return func(*resolved_vars)
compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode) compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
@ -883,10 +943,10 @@ class Library(object):
class InclusionNode(Node): class InclusionNode(Node):
def __init__(self, vars_to_resolve): def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve self.vars_to_resolve = map(Variable, vars_to_resolve)
def render(self, context): def render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
if takes_context: if takes_context:
args = [context] + resolved_vars args = [context] + resolved_vars
else: else:

View File

@ -1,6 +1,6 @@
"Default variable filters" "Default variable filters"
from django.template import resolve_variable, Library from django.template import Variable, Library
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext, ungettext from django.utils.translation import ugettext, ungettext
from django.utils.encoding import force_unicode, smart_str, iri_to_uri from django.utils.encoding import force_unicode, smart_str, iri_to_uri
@ -297,7 +297,8 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in Takes a list of dicts, returns that list sorted by the property given in
the argument. the argument.
""" """
decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] var_resolve = Variable(arg).resolve
decorated = [(var_resolve(item), item) for item in value]
decorated.sort() decorated.sort()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -306,7 +307,8 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument. property given in the argument.
""" """
decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] var_resolve = Variable(arg).resolve
decorated = [(var_resolve(item), item) for item in value]
decorated.sort() decorated.sort()
decorated.reverse() decorated.reverse()
return [item[1] for item in decorated] return [item[1] for item in decorated]

View File

@ -1,6 +1,6 @@
"Default tags used by the template system, available to all templates." "Default tags used by the template system, available to all templates."
from django.template import Node, NodeList, Template, Context, resolve_variable from django.template import Node, NodeList, Template, Context, Variable
from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
from django.template import get_library, Library, InvalidTemplateLibrary from django.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings from django.conf import settings
@ -30,7 +30,7 @@ class CycleNode(Node):
def render(self, context): def render(self, context):
self.counter += 1 self.counter += 1
value = self.cyclevars[self.counter % self.cyclevars_len] value = self.cyclevars[self.counter % self.cyclevars_len]
value = resolve_variable(value, context) value = Variable(value).resolve(context)
if self.variable_name: if self.variable_name:
context[self.variable_name] = value context[self.variable_name] = value
return value return value
@ -57,12 +57,12 @@ class FilterNode(Node):
class FirstOfNode(Node): class FirstOfNode(Node):
def __init__(self, vars): def __init__(self, vars):
self.vars = vars self.vars = map(Variable, vars)
def render(self, context): def render(self, context):
for var in self.vars: for var in self.vars:
try: try:
value = resolve_variable(var, context) value = var.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
continue continue
if value: if value:
@ -147,7 +147,7 @@ class IfChangedNode(Node):
def __init__(self, nodelist, *varlist): def __init__(self, nodelist, *varlist):
self.nodelist = nodelist self.nodelist = nodelist
self._last_seen = None self._last_seen = None
self._varlist = varlist self._varlist = map(Variable, varlist)
def render(self, context): def render(self, context):
if 'forloop' in context and context['forloop']['first']: if 'forloop' in context and context['forloop']['first']:
@ -156,7 +156,7 @@ class IfChangedNode(Node):
if self._varlist: if self._varlist:
# Consider multiple parameters. # Consider multiple parameters.
# This automatically behaves like a OR evaluation of the multiple variables. # This automatically behaves like a OR evaluation of the multiple variables.
compare_to = [resolve_variable(var, context) for var in self._varlist] compare_to = [var.resolve(context) for var in self._varlist]
else: else:
compare_to = self.nodelist.render(context) compare_to = self.nodelist.render(context)
except VariableDoesNotExist: except VariableDoesNotExist:
@ -175,7 +175,7 @@ class IfChangedNode(Node):
class IfEqualNode(Node): class IfEqualNode(Node):
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
self.var1, self.var2 = var1, var2 self.var1, self.var2 = Variable(var1), Variable(var2)
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.negate = negate self.negate = negate
@ -184,11 +184,11 @@ class IfEqualNode(Node):
def render(self, context): def render(self, context):
try: try:
val1 = resolve_variable(self.var1, context) val1 = self.var1.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
val1 = None val1 = None
try: try:
val2 = resolve_variable(self.var2, context) val2 = self.var2.resolve(context)
except VariableDoesNotExist: except VariableDoesNotExist:
val2 = None val2 = None
if (self.negate and val1 != val2) or (not self.negate and val1 == val2): if (self.negate and val1 != val2) or (not self.negate and val1 == val2):

View File

@ -1,4 +1,4 @@
from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
from django.template import Library, Node from django.template import Library, Node
from django.template.loader import get_template, get_template_from_string, find_template_source from django.template.loader import get_template, get_template_from_string, find_template_source
from django.conf import settings from django.conf import settings
@ -99,11 +99,11 @@ class ConstantIncludeNode(Node):
class IncludeNode(Node): class IncludeNode(Node):
def __init__(self, template_name): def __init__(self, template_name):
self.template_name = template_name self.template_name = Variable(template_name)
def render(self, context): def render(self, context):
try: try:
template_name = resolve_variable(self.template_name, context) template_name = self.template_name.resolve(context)
t = get_template(template_name) t = get_template(template_name)
return t.render(context) return t.render(context)
except TemplateSyntaxError, e: except TemplateSyntaxError, e:

View File

@ -1,4 +1,4 @@
from django.template import Node, resolve_variable from django.template import Node, Variable
from django.template import TemplateSyntaxError, TokenParser, Library from django.template import TemplateSyntaxError, TokenParser, Library
from django.template import TOKEN_TEXT, TOKEN_VAR from django.template import TOKEN_TEXT, TOKEN_VAR
from django.utils import translation from django.utils import translation
@ -32,11 +32,11 @@ class GetCurrentLanguageBidiNode(Node):
class TranslateNode(Node): class TranslateNode(Node):
def __init__(self, value, noop): def __init__(self, value, noop):
self.value = value self.value = Variable(value)
self.noop = noop self.noop = noop
def render(self, context): def render(self, context):
value = resolve_variable(self.value, context) value = self.value.resolve(context)
if self.noop: if self.noop:
return value return value
else: else:

View File

@ -149,7 +149,7 @@ class MultiValueDict(dict):
dict.__init__(self, key_to_list_mapping) dict.__init__(self, key_to_list_mapping)
def __repr__(self): def __repr__(self):
return "<MultiValueDict: %s>" % dict.__repr__(self) return "<%s: %s>" % (self.__class__.__name__, dict.__repr__(self))
def __getitem__(self, key): def __getitem__(self, key):
""" """

View File

@ -1,5 +1,6 @@
import types import types
import urllib import urllib
import datetime
from django.utils.functional import Promise from django.utils.functional import Promise
class StrAndUnicode(object): class StrAndUnicode(object):
@ -30,7 +31,7 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
If strings_only is True, don't convert (some) non-string-like objects. If strings_only is True, don't convert (some) non-string-like objects.
""" """
if strings_only and isinstance(s, (types.NoneType, int, long)): if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.time, float)):
return s return s
if not isinstance(s, basestring,): if not isinstance(s, basestring,):
if hasattr(s, '__unicode__'): if hasattr(s, '__unicode__'):

View File

@ -1062,3 +1062,40 @@ object the first time a user authenticates::
return User.objects.get(pk=user_id) return User.objects.get(pk=user_id)
except User.DoesNotExist: except User.DoesNotExist:
return None 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

View File

@ -952,7 +952,7 @@ Example::
If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary. If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary.
``iterator()`` ``iterator()``
~~~~~~~~~~~~ ~~~~~~~~~~~~~~
Evaluates the ``QuerySet`` (by performing the query) and returns an Evaluates the ``QuerySet`` (by performing the query) and returns an
`iterator`_ over the results. A ``QuerySet`` typically reads all of `iterator`_ over the results. A ``QuerySet`` typically reads all of

View File

@ -735,3 +735,32 @@ distribution. It enables tab-completion of ``django-admin.py`` and
* Press [TAB] to see all available options. * Press [TAB] to see all available options.
* Type ``sql``, then [TAB], to see all available options whose names start * Type ``sql``, then [TAB], to see all available options whose names start
with ``sql``. with ``sql``.
Customized actions
==================
**New in Django development version**
If you want to add an action of your own to ``manage.py``, you can.
Simply add a ``management/commands`` directory to your application.
Each python module in that directory will be discovered and registered as
a command that can be executed as an action when you run ``manage.py``::
/fancy_blog
__init__.py
models.py
/management
__init__.py
/commands
__init__.py
explode.py
views.py
In this example, ``explode`` command will be made available to any project
that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``.
The ``explode.py`` module has only one requirement -- it must define a class
called ``Command`` that extends ``django.core.management.base.BaseCommand``.
For more details on how to define your own commands, look at the code for the
existing ``django-admin.py`` commands, in ``/django/core/management/commands``.

View File

@ -100,31 +100,31 @@ mail_admins()
============= =============
``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the ``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the
site admins, as defined in the `ADMINS setting`_. Here's the definition:: site admins, as defined in the `ADMINS`_ setting. Here's the definition::
mail_admins(subject, message, fail_silently=False) mail_admins(subject, message, fail_silently=False)
``mail_admins()`` prefixes the subject with the value of the ``mail_admins()`` prefixes the subject with the value of the
`EMAIL_SUBJECT_PREFIX setting`_, which is ``"[Django] "`` by default. `EMAIL_SUBJECT_PREFIX`_ setting, which is ``"[Django] "`` by default.
The "From:" header of the e-mail will be the value of the `SERVER_EMAIL setting`_. The "From:" header of the e-mail will be the value of the `SERVER_EMAIL`_ setting.
This method exists for convenience and readability. This method exists for convenience and readability.
.. _ADMINS setting: ../settings/#admins .. _ADMINS: ../settings/#admins
.. _EMAIL_SUBJECT_PREFIX setting: ../settings/#email-subject-prefix .. _EMAIL_SUBJECT_PREFIX: ../settings/#email-subject-prefix
.. _SERVER_EMAIL setting: ../settings/#server-email .. _SERVER_EMAIL: ../settings/#server-email
mail_managers() function mail_managers() function
======================== ========================
``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it ``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it
sends an e-mail to the site managers, as defined in the `MANAGERS setting`_. sends an e-mail to the site managers, as defined in the `MANAGERS`_ setting.
Here's the definition:: Here's the definition::
mail_managers(subject, message, fail_silently=False) mail_managers(subject, message, fail_silently=False)
.. _MANAGERS setting: ../settings/#managers .. _MANAGERS: ../settings/#managers
Examples Examples
======== ========
@ -225,7 +225,7 @@ optional and can be set at any time prior to calling the ``send()`` method.
* ``from_email``: The sender's address. Both ``fred@example.com`` and * ``from_email``: The sender's address. Both ``fred@example.com`` and
``Fred <fred@example.com>`` forms are legal. If omitted, the ``Fred <fred@example.com>`` forms are legal. If omitted, the
``DEFAULT_FROM_EMAIL`` setting is used. `DEFAULT_FROM_EMAIL`_ setting is used.
* ``to``: A list or tuple of recipient addresses. * ``to``: A list or tuple of recipient addresses.
@ -297,6 +297,8 @@ The class has the following methods:
message.attach_file('/images/weather_map.png') message.attach_file('/images/weather_map.png')
.. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email
Sending alternative content types Sending alternative content types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -800,9 +800,14 @@ specify the page number in the URL in one of two ways:
variable. You can iterate over the list provided by ``page_range`` variable. You can iterate over the list provided by ``page_range``
to create a link to every page of results. to create a link to every page of results.
These values and lists are is 1-based, not 0-based, so the first page would be These values and lists are 1-based, not 0-based, so the first page would be
represented as page ``1``. represented as page ``1``.
An example of the use of pagination can be found in the `object pagination`_
example model.
.. _`object pagination`: ../models/pagination/
**New in Django development version:** **New in Django development version:**
As a special case, you are also permitted to use As a special case, you are also permitted to use

View File

@ -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 .. _`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`` ``FilePathField``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -330,6 +334,10 @@ not the full path. So, this example::
because the ``match`` applies to the base filename (``foo.gif`` and because the ``match`` applies to the base filename (``foo.gif`` and
``bar.gif``). ``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`` ``FloatField``
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
@ -361,6 +369,11 @@ Requires the `Python Imaging Library`_.
.. _Python Imaging Library: http://www.pythonware.com/products/pil/ .. _Python Imaging Library: http://www.pythonware.com/products/pil/
.. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width .. _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`` ``IntegerField``
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

View File

@ -1926,11 +1926,22 @@ of the model fields:
.. note:: .. note::
If you specify ``fields`` when creating a form with ``form_for_model()``, If you specify ``fields`` when creating a form with ``form_for_model()``,
make sure that the fields that are *not* specified can provide default then the fields that are *not* specified will not be set by the form's
values, or are allowed to have a value of ``None``. If a field isn't ``save()`` method. Django will prevent any attempt to save an incomplete
specified on a form, the object created from the form can't provide model, so if the model does not allow the missing fields to be empty, and
a value for that attribute, which will prevent the new instance from does not provide a default value for the missing fields, any attempt to
being saved. ``save()`` a ``form_for_model`` with missing fields will fail. To avoid
this failure, you must use ``save(commit=False)`` and manually set any
extra required fields::
instance = form.save(commit=False)
instance.required_field = 'new value'
instance.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.
.. _section on saving forms: `The save() method`_
Overriding the default field types Overriding the default field types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -190,7 +190,7 @@ necessary because some HTML form elements, notably
That means you can't change attributes of ``request.POST`` and ``request.GET`` That means you can't change attributes of ``request.POST`` and ``request.GET``
directly. directly.
``QueryDict`` implements the all standard dictionary methods, because it's a ``QueryDict`` implements all the standard dictionary methods, because it's a
subclass of dictionary. Exceptions are outlined here: subclass of dictionary. Exceptions are outlined here:
* ``__getitem__(key)`` -- Returns the value for the given key. If the key * ``__getitem__(key)`` -- Returns the value for the given key. If the key

View File

@ -198,14 +198,14 @@ Using sessions out of views
An API is available to manipulate session data outside of a view:: An API is available to manipulate session data outside of a view::
>>> from django.contrib.sessions.engines.db import SessionStore >>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead') >>> 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, 10)
>>> s['last_login'] >>> s['last_login']
datetime.datetime(2005, 8, 20, 13, 35, 0) datetime.datetime(2005, 8, 20, 13, 35, 0)
>>> s.save() >>> s.save()
If you're using the ``django.contrib.sessions.engine.db`` backend, each If you're using the ``django.contrib.sessions.backends.db`` backend, each
session is just a normal Django model. The ``Session`` model is defined in 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 ``django/contrib/sessions/models.py``. Because it's a normal model, you can
access sessions using the normal Django database API:: access sessions using the normal Django database API::

View File

@ -363,7 +363,7 @@ regular expression which will hide from the DEBUG view anything that contains
be able to give backtraces without seeing sensitive (or offensive) settings. be able to give backtraces without seeing sensitive (or offensive) settings.
Still, note that there are always going to be sections of your debug output that Still, note that there are always going to be sections of your debug output that
are inapporpriate for public consumption. File paths, configuration options, and are inappropriate for public consumption. File paths, configuration options, and
the like all give attackers extra information about your server. Never deploy a the like all give attackers extra information about your server. Never deploy a
site with ``DEBUG`` turned on. site with ``DEBUG`` turned on.

View File

@ -928,10 +928,36 @@ current context, available in the ``render`` method::
``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then ``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then
format it accordingly. format it accordingly.
.. note:: .. admonition:: New in development version:
The ``resolve_variable()`` function will throw a ``VariableDoesNotExist``
exception if it cannot resolve the string passed to it in the current Variable resolution has changed in the development version of Django.
context of the page. ``template.resolve_variable()`` is still available, but has been deprecated
in favor of a new ``template.Variable`` class. Using this class will usually
be more efficient than calling ``template.resolve_variable``
To use the ``Variable`` class, simply instantiate it with the name of the
variable to be resolved, and then call ``variable.resolve(context)``. So,
in the development version, the above example would be more correctly
written as:
.. parsed-literal::
class FormatTimeNode(template.Node):
def __init__(self, date_to_be_formatted, format_string):
self.date_to_be_formatted = **Variable(date_to_be_formatted)**
self.format_string = format_string
def render(self, context):
try:
actual_date = **self.date_to_be_formatted.resolve(context)**
return actual_date.strftime(self.format_string)
except template.VariableDoesNotExist:
return ''
Changes are highlighted in bold.
Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot
resolve the string passed to it in the current context of the page.
Shortcut for simple tags Shortcut for simple tags
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -63,6 +63,9 @@ class Movie(models.Model):
def __unicode__(self): def __unicode__(self):
return self.title return self.title
class Score(models.Model):
score = models.FloatField()
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
# Create some data: # Create some data:
@ -83,7 +86,7 @@ __test__ = {'API_TESTS':"""
>>> a2 = Article( >>> a2 = Article(
... author = joe, ... author = joe,
... headline = "Time to reform copyright", ... headline = "Time to reform copyright",
... pub_date = datetime(2006, 6, 16, 13, 00)) ... pub_date = datetime(2006, 6, 16, 13, 00, 11, 345))
>>> a1.save(); a2.save() >>> a1.save(); a2.save()
>>> a1.categories = [sports, op_ed] >>> a1.categories = [sports, op_ed]
>>> a2.categories = [music, op_ed] >>> a2.categories = [music, op_ed]
@ -181,7 +184,7 @@ __test__ = {'API_TESTS':"""
# Serializer output can be restricted to a subset of fields # Serializer output can be restricted to a subset of fields
>>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date')) >>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date'))
[{"pk": 1, "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 2, "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 3, "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}] [{"pk": 1, "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 2, "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:11"}}, {"pk": 3, "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}]
# Every string is serialized as a unicode object, also primary key # Every string is serialized as a unicode object, also primary key
# which is 'varchar' # which is 'varchar'
@ -207,4 +210,11 @@ u'G\u0119\u015bl\u0105 ja\u017a\u0144'
>>> print list(serializers.deserialize('json', serializers.serialize('json', [mv2])))[0].object.id >>> print list(serializers.deserialize('json', serializers.serialize('json', [mv2])))[0].object.id
None None
# Serialization and deserialization of floats:
>>> sc = Score(score=3.4)
>>> print serializers.serialize("json", [sc])
[{"pk": null, "model": "serializers.score", "fields": {"score": 3.4}}]
>>> print list(serializers.deserialize('json', serializers.serialize('json', [sc])))[0].object.score
3.4
"""} """}

View File

@ -54,7 +54,7 @@ Is updated
pre_delete signal, Tom Smith pre_delete signal, Tom Smith
instance.id is not None: True instance.id is not None: True
post_delete signal, Tom Smith post_delete signal, Tom Smith
instance.id is None: True instance.id is None: False
>>> p2 = Person(first_name='James', last_name='Jones') >>> p2 = Person(first_name='James', last_name='Jones')
>>> p2.id = 99999 >>> p2.id = 99999
@ -73,7 +73,7 @@ Is created
pre_delete signal, James Jones pre_delete signal, James Jones
instance.id is not None: True instance.id is not None: True
post_delete signal, James Jones post_delete signal, James Jones
instance.id is None: True instance.id is None: False
>>> Person.objects.all() >>> Person.objects.all()
[<Person: James Jones>] [<Person: James Jones>]

View File

@ -0,0 +1,9 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Dance around like a madman."
args = ''
requires_model_validation = True
def handle(self, *args, **options):
print "I don't feel like dancing."

View File

@ -0,0 +1,30 @@
"""
37. User-registered management commands
The manage.py utility provides a number of useful commands for managing a
Django project. If you want to add a utility command of your own, you can.
The user-defined command 'dance' is defined in the management/commands
subdirectory of this test application. It is a simple command that responds
with a printed message when invoked.
For more details on how to define your own manage.py commands, look at the
django.core.management.commands directory. This directory contains the
definitions for the base Django manage.py commands.
"""
__test__ = {'API_TESTS': """
>>> from django.core import management
# Invoke a simple user-defined command
>>> management.call_command('dance')
I don't feel like dancing.
# Invoke a command that doesn't exist
>>> management.call_command('explode')
Traceback (most recent call last):
...
CommandError: Unknown command: 'explode'
"""}

View 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
"""

View 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
"""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View 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''
"""

View 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>
"""

View 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.']
"""

View 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.']
"""

View 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>'
"""

View 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&#39;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>'
"""

View 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.']
"""

File diff suppressed because one or more lines are too long

View 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&#39;Or</option>
<option value="22">22 - Cotes-d&#39;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&#39;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>
"""

View 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'
"""

File diff suppressed because one or more lines are too long

View 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.']
"""

View 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>
"""

View 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>'
"""

File diff suppressed because one or more lines are too long

View 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>'
"""

View 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''
"""

View 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.']
"""

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Tests to prevent against recurrences of earlier bugs. # Tests to prevent against recurrences of earlier bugs.
regression_tests = r""" tests = r"""
It should be possible to re-use attribute dictionaries (#3810) It should be possible to re-use attribute dictionaries (#3810)
>>> from django.newforms import * >>> from django.newforms import *
>>> extra_attrs = {'class': 'special'} >>> extra_attrs = {'class': 'special'}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
Tests for newforms/util.py module. Tests for newforms/util.py module.
""" """
util_tests = r""" tests = r"""
>>> from django.newforms.util import * >>> from django.newforms.util import *
>>> from django.utils.translation import ugettext_lazy >>> from django.utils.translation import ugettext_lazy

View 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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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 &amp; 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" />'
"""

View File

@ -8,7 +8,7 @@
>>> q['foo'] >>> q['foo']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>" MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>"
>>> q['something'] = 'bar' >>> q['something'] = 'bar'
Traceback (most recent call last): Traceback (most recent call last):
@ -89,7 +89,7 @@ AttributeError: This QueryDict instance is immutable
>>> q['foo'] >>> q['foo']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>" MultiValueDictKeyError: "Key 'foo' not found in <QueryDict: {}>"
>>> q['name'] = 'john' >>> q['name'] = 'john'
@ -201,7 +201,7 @@ u'bar'
>>> q['bar'] >>> q['bar']
Traceback (most recent call last): Traceback (most recent call last):
... ...
MultiValueDictKeyError: "Key 'bar' not found in <MultiValueDict: {u'foo': [u'bar']}>" MultiValueDictKeyError: "Key 'bar' not found in <QueryDict: {u'foo': [u'bar']}>"
>>> q['something'] = 'bar' >>> q['something'] = 'bar'
Traceback (most recent call last): Traceback (most recent call last):

View File

@ -0,0 +1 @@

View 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)

View 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))

View File

@ -4,9 +4,32 @@
"model": "views.article", "model": "views.article",
"fields": { "fields": {
"author": 1, "author": 1,
"title": "An Article" "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, "pk": 1,
"model": "views.author", "model": "views.author",

View File

@ -17,8 +17,10 @@ class Author(models.Model):
class Article(models.Model): class Article(models.Model):
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
slug = models.SlugField()
author = models.ForeignKey(Author) author = models.ForeignKey(Author)
date_created = models.DateTimeField()
def __unicode__(self): def __unicode__(self):
return self.title return self.title

View File

@ -1,3 +1,4 @@
from defaults import * from defaults import *
from i18n import * from i18n import *
from static import * from static import *
from generic.date_based import *

View 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, 1)
first_second_of_mar = datetime(2004, 3, 1, 0, 0, 1)
two_seconds = timedelta(0, 2, 0)
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-two_seconds
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-two_seconds
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)

View File

@ -1,6 +1,8 @@
from os import path from os import path
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from models import *
import views import views
base_dir = path.dirname(path.abspath(__file__)) base_dir = path.dirname(path.abspath(__file__))
@ -12,15 +14,35 @@ js_info_dict = {
'packages': ('regressiontests.views',), 'packages': ('regressiontests.views',),
} }
date_based_info_dict = {
'queryset': Article.objects.all(),
'date_field': 'date_created',
'month_format': '%m',
}
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^$', views.index_page), (r'^$', views.index_page),
# Default views
(r'^shortcut/(\d+)/(.*)/$', 'django.views.defaults.shortcut'), (r'^shortcut/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
(r'^non_existing_url/', 'django.views.defaults.page_not_found'), (r'^non_existing_url/', 'django.views.defaults.page_not_found'),
(r'^server_error/', 'django.views.defaults.server_error'), (r'^server_error/', 'django.views.defaults.server_error'),
# i18n views
(r'^i18n/', include('django.conf.urls.i18n')), (r'^i18n/', include('django.conf.urls.i18n')),
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
(r'^jsi18n_test/$', views.jsi18n_test),
# Static views
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': media_dir}), (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),
) )

View File

@ -1,12 +1,7 @@
from django.http import HttpResponse from django.http import HttpResponse
from django.template import RequestContext from django.template import RequestContext
from django.shortcuts import render_to_response
def index_page(request): def index_page(request):
""" Dummy index page """ """Dummy index page"""
return HttpResponse('<html><body>Dummy page</body></html>') return HttpResponse('<html><body>Dummy page</body></html>')
def jsi18n_test(request):
""" View for testing javascript message files """
return render_to_response('js_i18n.html', {})

View File

@ -0,0 +1 @@
This template intentionally left blank

View File

@ -0,0 +1 @@
This template intentionally left blank