Fixed #23395 -- Limited line lengths to 119 characters.

This commit is contained in:
Dražen Odobašić 2015-09-11 19:33:12 -04:00 committed by Tim Graham
parent 84b0a8d2aa
commit b1e33ceced
130 changed files with 5259 additions and 1501 deletions

View File

@ -83,7 +83,11 @@ class UserAdmin(admin.ModelAdmin):
def get_urls(self): def get_urls(self):
return [ return [
url(r'^(.+)/password/$', self.admin_site.admin_view(self.user_change_password), name='auth_user_password_change'), url(
r'^(.+)/password/$',
self.admin_site.admin_view(self.user_change_password),
name='auth_user_password_change',
),
] + super(UserAdmin, self).get_urls() ] + super(UserAdmin, self).get_urls()
def lookup_allowed(self, lookup, value): def lookup_allowed(self, lookup, value):

View File

@ -58,16 +58,42 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(default=timezone.now, verbose_name='last login')), ('last_login', models.DateTimeField(default=timezone.now, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('is_superuser', models.BooleanField(
('username', models.CharField(help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, max_length=30, verbose_name='username', validators=[validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')])), default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
verbose_name='superuser status'
)),
('username', models.CharField(
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True,
max_length=30, verbose_name='username',
validators=[validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')]
)),
('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)), ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)), ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
('email', models.EmailField(max_length=75, verbose_name='email address', blank=True)), ('email', models.EmailField(max_length=75, verbose_name='email address', blank=True)),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_staff', models.BooleanField(
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), default=False, help_text='Designates whether the user can log into this admin site.',
verbose_name='staff status'
)),
('is_active', models.BooleanField(
default=True, verbose_name='active', help_text=(
'Designates whether this user should be treated as active. Unselect this instead of deleting '
'accounts.'
)
)),
('date_joined', models.DateTimeField(default=timezone.now, verbose_name='date joined')), ('date_joined', models.DateTimeField(default=timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(to='auth.Group', verbose_name='groups', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user')), ('groups', models.ManyToManyField(
('user_permissions', models.ManyToManyField(to='auth.Permission', verbose_name='user permissions', blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user')), to='auth.Group', verbose_name='groups', blank=True, related_name='user_set',
related_query_name='user', help_text=(
'The groups this user belongs to. A user will get all permissions granted to each of their '
'groups.'
)
)),
('user_permissions', models.ManyToManyField(
to='auth.Permission', verbose_name='user permissions', blank=True,
help_text='Specific permissions for this user.', related_name='user_set',
related_query_name='user')
),
], ],
options={ options={
'swappable': 'AUTH_USER_MODEL', 'swappable': 'AUTH_USER_MODEL',

View File

@ -16,6 +16,15 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='user', model_name='user',
name='username', name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username'), field=models.CharField(
error_messages={'unique': 'A user with that username already exists.'}, max_length=30,
validators=[django.core.validators.RegexValidator(
'^[\\w.@+-]+$',
'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.',
'invalid'
)],
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
unique=True, verbose_name='username'
),
), ),
] ]

View File

@ -19,8 +19,16 @@ class Migration(migrations.Migration):
('title', models.CharField(max_length=200, verbose_name='title')), ('title', models.CharField(max_length=200, verbose_name='title')),
('content', models.TextField(verbose_name='content', blank=True)), ('content', models.TextField(verbose_name='content', blank=True)),
('enable_comments', models.BooleanField(default=False, verbose_name='enable comments')), ('enable_comments', models.BooleanField(default=False, verbose_name='enable comments')),
('template_name', models.CharField(help_text="Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'.", max_length=70, verbose_name='template name', blank=True)), ('template_name', models.CharField(
('registration_required', models.BooleanField(default=False, help_text='If this is checked, only logged-in users will be able to view the page.', verbose_name='registration required')), help_text=(
"Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use "
"'flatpages/default.html'."
), max_length=70, verbose_name='template name', blank=True
)),
('registration_required', models.BooleanField(
default=False, help_text='If this is checked, only logged-in users will be able to view the page.',
verbose_name='registration required'
)),
('sites', models.ManyToManyField(to='sites.Site', verbose_name='sites')), ('sites', models.ManyToManyField(to='sites.Site', verbose_name='sites')),
], ],
options={ options={

View File

@ -21,8 +21,15 @@ class Migration(migrations.Migration):
on_delete=models.CASCADE, on_delete=models.CASCADE,
verbose_name='site', verbose_name='site',
)), )),
('old_path', models.CharField(help_text="This should be an absolute path, excluding the domain name. Example: '/events/search/'.", max_length=200, verbose_name='redirect from', db_index=True)), ('old_path', models.CharField(
('new_path', models.CharField(help_text="This can be either an absolute path (as above) or a full URL starting with 'http://'.", max_length=200, verbose_name='redirect to', blank=True)), help_text=(
"This should be an absolute path, excluding the domain name. Example: '/events/search/'."
), max_length=200, verbose_name='redirect from', db_index=True
)),
('new_path', models.CharField(
help_text="This can be either an absolute path (as above) or a full URL starting with 'http://'.",
max_length=200, verbose_name='redirect to', blank=True
)),
], ],
options={ options={
'ordering': ('old_path',), 'ordering': ('old_path',),

View File

@ -14,7 +14,9 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Session', name='Session',
fields=[ fields=[
('session_key', models.CharField(max_length=40, serialize=False, verbose_name='session key', primary_key=True)), ('session_key', models.CharField(
max_length=40, serialize=False, verbose_name='session key', primary_key=True
)),
('session_data', models.TextField(verbose_name='session data')), ('session_data', models.TextField(verbose_name='session data')),
('expire_date', models.DateTimeField(verbose_name='expire date', db_index=True)), ('expire_date', models.DateTimeField(verbose_name='expire date', db_index=True)),
], ],

View File

@ -15,7 +15,9 @@ class Migration(migrations.Migration):
name='Site', name='Site',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('domain', models.CharField(max_length=100, verbose_name='domain name', validators=[_simple_domain_name_validator])), ('domain', models.CharField(
max_length=100, verbose_name='domain name', validators=[_simple_domain_name_validator]
)),
('name', models.CharField(max_length=50, verbose_name='display name')), ('name', models.CharField(max_length=50, verbose_name='display name')),
], ],
options={ options={

View File

@ -15,6 +15,9 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='site', model_name='site',
name='domain', name='domain',
field=models.CharField(max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], verbose_name='domain name'), field=models.CharField(
max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator],
verbose_name='domain name'
),
), ),
] ]

View File

@ -92,7 +92,10 @@ class Command(BaseCommand):
extra_params['unique'] = True extra_params['unique'] = True
if is_relation: if is_relation:
rel_to = "self" if relations[column_name][1] == table_name else table2model(relations[column_name][1]) rel_to = (
"self" if relations[column_name][1] == table_name
else table2model(relations[column_name][1])
)
if rel_to in known_models: if rel_to in known_models:
field_type = 'ForeignKey(%s' % rel_to field_type = 'ForeignKey(%s' % rel_to
else: else:

View File

@ -124,14 +124,15 @@ def Deserializer(object_list, **options):
# Handle M2M relations # Handle M2M relations
if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel): if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'): model = field.remote_field.model
if hasattr(model._default_manager, 'get_by_natural_key'):
def m2m_convert(value): def m2m_convert(value):
if hasattr(value, '__iter__') and not isinstance(value, six.text_type): if hasattr(value, '__iter__') and not isinstance(value, six.text_type):
return field.remote_field.model._default_manager.db_manager(db).get_by_natural_key(*value).pk return model._default_manager.db_manager(db).get_by_natural_key(*value).pk
else: else:
return force_text(field.remote_field.model._meta.pk.to_python(value), strings_only=True) return force_text(model._meta.pk.to_python(value), strings_only=True)
else: else:
m2m_convert = lambda v: force_text(field.remote_field.model._meta.pk.to_python(v), strings_only=True) m2m_convert = lambda v: force_text(model._meta.pk.to_python(v), strings_only=True)
try: try:
m2m_data[field.name] = [] m2m_data[field.name] = []
@ -142,21 +143,24 @@ def Deserializer(object_list, **options):
# Handle FK fields # Handle FK fields
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel): elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
model = field.remote_field.model
if field_value is not None: if field_value is not None:
try: try:
if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'): default_manager = model._default_manager
field_name = field.remote_field.field_name
if hasattr(default_manager, 'get_by_natural_key'):
if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type): if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
obj = field.remote_field.model._default_manager.db_manager(db).get_by_natural_key(*field_value) obj = default_manager.db_manager(db).get_by_natural_key(*field_value)
value = getattr(obj, field.remote_field.field_name) value = getattr(obj, field.remote_field.field_name)
# If this is a natural foreign key to an object that # If this is a natural foreign key to an object that
# has a FK/O2O as the foreign key, use the FK value # has a FK/O2O as the foreign key, use the FK value
if field.remote_field.model._meta.pk.remote_field: if model._meta.pk.remote_field:
value = value.pk value = value.pk
else: else:
value = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value) value = model._meta.get_field(field_name).to_python(field_value)
data[field.attname] = value data[field.attname] = value
else: else:
data[field.attname] = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value) data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
except Exception as e: except Exception as e:
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value) raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
else: else:

View File

@ -236,12 +236,13 @@ class Deserializer(base.Deserializer):
if node.getElementsByTagName('None'): if node.getElementsByTagName('None'):
return None return None
else: else:
if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'): model = field.remote_field.model
if hasattr(model._default_manager, 'get_by_natural_key'):
keys = node.getElementsByTagName('natural') keys = node.getElementsByTagName('natural')
if keys: if keys:
# If there are 'natural' subelements, it must be a natural key # If there are 'natural' subelements, it must be a natural key
field_value = [getInnerText(k).strip() for k in keys] field_value = [getInnerText(k).strip() for k in keys]
obj = field.remote_field.model._default_manager.db_manager(self.db).get_by_natural_key(*field_value) obj = model._default_manager.db_manager(self.db).get_by_natural_key(*field_value)
obj_pk = getattr(obj, field.remote_field.field_name) obj_pk = getattr(obj, field.remote_field.field_name)
# If this is a natural foreign key to an object that # If this is a natural foreign key to an object that
# has a FK/O2O as the foreign key, use the FK value # has a FK/O2O as the foreign key, use the FK value
@ -250,29 +251,31 @@ class Deserializer(base.Deserializer):
else: else:
# Otherwise, treat like a normal PK # Otherwise, treat like a normal PK
field_value = getInnerText(node).strip() field_value = getInnerText(node).strip()
obj_pk = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value) obj_pk = model._meta.get_field(field.remote_field.field_name).to_python(field_value)
return obj_pk return obj_pk
else: else:
field_value = getInnerText(node).strip() field_value = getInnerText(node).strip()
return field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value) return model._meta.get_field(field.remote_field.field_name).to_python(field_value)
def _handle_m2m_field_node(self, node, field): def _handle_m2m_field_node(self, node, field):
""" """
Handle a <field> node for a ManyToManyField. Handle a <field> node for a ManyToManyField.
""" """
if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'): model = field.remote_field.model
default_manager = model._default_manager
if hasattr(default_manager, 'get_by_natural_key'):
def m2m_convert(n): def m2m_convert(n):
keys = n.getElementsByTagName('natural') keys = n.getElementsByTagName('natural')
if keys: if keys:
# If there are 'natural' subelements, it must be a natural key # If there are 'natural' subelements, it must be a natural key
field_value = [getInnerText(k).strip() for k in keys] field_value = [getInnerText(k).strip() for k in keys]
obj_pk = field.remote_field.model._default_manager.db_manager(self.db).get_by_natural_key(*field_value).pk obj_pk = default_manager.db_manager(self.db).get_by_natural_key(*field_value).pk
else: else:
# Otherwise, treat like a normal PK value. # Otherwise, treat like a normal PK value.
obj_pk = field.remote_field.model._meta.pk.to_python(n.getAttribute('pk')) obj_pk = model._meta.pk.to_python(n.getAttribute('pk'))
return obj_pk return obj_pk
else: else:
m2m_convert = lambda n: field.remote_field.model._meta.pk.to_python(n.getAttribute('pk')) m2m_convert = lambda n: model._meta.pk.to_python(n.getAttribute('pk'))
return [m2m_convert(c) for c in node.getElementsByTagName("object")] return [m2m_convert(c) for c in node.getElementsByTagName("object")]
def _get_model_from_node(self, node, attr): def _get_model_from_node(self, node, attr):

View File

@ -468,7 +468,11 @@ class MigrationAutodetector(object):
) )
) )
self.renamed_models[app_label, model_name] = rem_model_name self.renamed_models[app_label, model_name] = rem_model_name
self.renamed_models_rel['%s.%s' % (rem_model_state.app_label, rem_model_state.name)] = '%s.%s' % (model_state.app_label, model_state.name) renamed_models_rel_key = '%s.%s' % (rem_model_state.app_label, rem_model_state.name)
self.renamed_models_rel[renamed_models_rel_key] = '%s.%s' % (
model_state.app_label,
model_state.name,
)
self.old_model_keys.remove((rem_app_label, rem_model_name)) self.old_model_keys.remove((rem_app_label, rem_model_name))
self.old_model_keys.append((app_label, model_name)) self.old_model_keys.append((app_label, model_name))
break break
@ -505,7 +509,8 @@ class MigrationAutodetector(object):
related_fields[field.name] = field related_fields[field.name] = field
# through will be none on M2Ms on swapped-out models; # through will be none on M2Ms on swapped-out models;
# we can treat lack of through as auto_created=True, though. # we can treat lack of through as auto_created=True, though.
if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created: if (getattr(field.remote_field, "through", None)
and not field.remote_field.through._meta.auto_created):
related_fields[field.name] = field related_fields[field.name] = field
for field in model_opts.local_many_to_many: for field in model_opts.local_many_to_many:
if field.remote_field.model: if field.remote_field.model:
@ -681,7 +686,8 @@ class MigrationAutodetector(object):
related_fields[field.name] = field related_fields[field.name] = field
# through will be none on M2Ms on swapped-out models; # through will be none on M2Ms on swapped-out models;
# we can treat lack of through as auto_created=True, though. # we can treat lack of through as auto_created=True, though.
if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created: if (getattr(field.remote_field, "through", None)
and not field.remote_field.through._meta.auto_created):
related_fields[field.name] = field related_fields[field.name] = field
for field in model._meta.local_many_to_many: for field in model._meta.local_many_to_many:
if field.remote_field.model: if field.remote_field.model:

View File

@ -119,7 +119,10 @@ class MigrationLoader(object):
if hasattr(migration_module.Migration, "forwards"): if hasattr(migration_module.Migration, "forwards"):
south_style_migrations = True south_style_migrations = True
break break
self.disk_migrations[app_config.label, migration_name] = migration_module.Migration(migration_name, app_config.label) self.disk_migrations[app_config.label, migration_name] = migration_module.Migration(
migration_name,
app_config.label,
)
if south_style_migrations: if south_style_migrations:
self.unmigrated_apps.add(app_config.label) self.unmigrated_apps.add(app_config.label)

View File

@ -346,7 +346,10 @@ class RelatedField(Field):
return None return None
def set_attributes_from_rel(self): def set_attributes_from_rel(self):
self.name = self.name or (self.remote_field.model._meta.model_name + '_' + self.remote_field.model._meta.pk.name) self.name = (
self.name or
(self.remote_field.model._meta.model_name + '_' + self.remote_field.model._meta.pk.name)
)
if self.verbose_name is None: if self.verbose_name is None:
self.verbose_name = self.remote_field.model._meta.verbose_name self.verbose_name = self.remote_field.model._meta.verbose_name
self.remote_field.set_field_name() self.remote_field.set_field_name()
@ -830,7 +833,9 @@ def create_foreign_related_manager(superclass, rel):
if self.field.get_local_related_value(obj) == val: if self.field.get_local_related_value(obj) == val:
old_ids.add(obj.pk) old_ids.add(obj.pk)
else: else:
raise self.field.remote_field.model.DoesNotExist("%r is not related to %r." % (obj, self.instance)) raise self.field.remote_field.model.DoesNotExist(
"%r is not related to %r." % (obj, self.instance)
)
self._clear(self.filter(pk__in=old_ids), bulk) self._clear(self.filter(pk__in=old_ids), bulk)
remove.alters_data = True remove.alters_data = True
@ -955,7 +960,8 @@ def create_many_related_manager(superclass, rel, reverse):
self.core_filters = {} self.core_filters = {}
for lh_field, rh_field in self.source_field.related_fields: for lh_field, rh_field in self.source_field.related_fields:
self.core_filters['%s__%s' % (self.query_field_name, rh_field.name)] = getattr(instance, rh_field.attname) core_filter_key = '%s__%s' % (self.query_field_name, rh_field.name)
self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
self.related_val = self.source_field.get_foreign_related_value(instance) self.related_val = self.source_field.get_foreign_related_value(instance)
if None in self.related_val: if None in self.related_val:
@ -1688,7 +1694,10 @@ class ForeignObject(RelatedField):
if isinstance(self.remote_field.model, six.string_types): if isinstance(self.remote_field.model, six.string_types):
kwargs['to'] = self.remote_field.model kwargs['to'] = self.remote_field.model
else: else:
kwargs['to'] = "%s.%s" % (self.remote_field.model._meta.app_label, self.remote_field.model._meta.object_name) kwargs['to'] = "%s.%s" % (
self.remote_field.model._meta.app_label,
self.remote_field.model._meta.object_name,
)
# If swappable is True, then see if we're actually pointing to the target # If swappable is True, then see if we're actually pointing to the target
# of a swap. # of a swap.
swappable_setting = self.swappable_setting swappable_setting = self.swappable_setting
@ -1999,7 +2008,8 @@ class ForeignKey(ForeignObject):
kwargs['db_constraint'] = self.db_constraint kwargs['db_constraint'] = self.db_constraint
# Rel needs more work. # Rel needs more work.
to_meta = getattr(self.remote_field.model, "_meta", None) to_meta = getattr(self.remote_field.model, "_meta", None)
if self.remote_field.field_name and (not to_meta or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)): if self.remote_field.field_name and (
not to_meta or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)):
kwargs['to_field'] = self.remote_field.field_name kwargs['to_field'] = self.remote_field.field_name
return name, path, args, kwargs return name, path, args, kwargs

View File

@ -788,8 +788,12 @@ class BaseModelFormSet(BaseFormSet):
# True, so check for that as well. # True, so check for that as well.
def pk_is_not_editable(pk): def pk_is_not_editable(pk):
return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField)) return (
or (pk.remote_field and pk.remote_field.parent_link and pk_is_not_editable(pk.remote_field.model._meta.pk))) (not pk.editable) or (pk.auto_created or isinstance(pk, AutoField)) or (
pk.remote_field and pk.remote_field.parent_link
and pk_is_not_editable(pk.remote_field.model._meta.pk)
)
)
if pk_is_not_editable(pk) or pk.name not in form.fields: if pk_is_not_editable(pk) or pk.name not in form.fields:
if form.is_bound: if form.is_bound:
# If we're adding the related instance, ignore its primary key # If we're adding the related instance, ignore its primary key

View File

@ -655,7 +655,10 @@ class Client(RequestFactory):
def _parse_json(self, response, **extra): def _parse_json(self, response, **extra):
if 'application/json' not in response.get('Content-Type'): if 'application/json' not in response.get('Content-Type'):
raise ValueError('Content-Type header is "{0}", not "application/json"'.format(response.get('Content-Type'))) raise ValueError(
'Content-Type header is "{0}", not "application/json"'
.format(response.get('Content-Type'))
)
return json.loads(response.content.decode(), **extra) return json.loads(response.content.decode(), **extra)
def _handle_redirects(self, response, **extra): def _handle_redirects(self, response, **extra):

View File

@ -862,12 +862,12 @@ Installed Middleware:
{% if postmortem %}Django tried loading these templates, in this order: {% if postmortem %}Django tried loading these templates, in this order:
{% for entry in postmortem %} {% for entry in postmortem %}
Using engine {{ entry.backend.name }}: Using engine {{ entry.backend.name }}:
{% if entry.tried %}{% for attempt in entry.tried %} * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }}) {% if entry.tried %}{% for attempt in entry.tried %}"""
""" * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
{% endfor %}{% else %} This engine did not provide a list of tried templates. {% endfor %}{% else %} This engine did not provide a list of tried templates.
{% endif %}{% endfor %} {% endif %}{% endfor %}
{% else %}No templates were found because your 'TEMPLATES' setting is not configured. {% else %}No templates were found because your 'TEMPLATES' setting is not configured.
{% endif %} {% endif %}{% endif %}{% if template_info %}
{% endif %}{% if template_info %}
Template error: Template error:
In template {{ template_info.name }}, error at line {{ template_info.line }} In template {{ template_info.name }}, error at line {{ template_info.line }}
{{ template_info.message }}""" {{ template_info.message }}"""
@ -1044,7 +1044,8 @@ Exception Value: {{ exception_value|force_escape }}
</html> </html>
""") """)
TECHNICAL_500_TEXT_TEMPLATE = ("""{% firstof exception_type 'Report' %}{% if request %} at {{ request.path_info }}{% endif %} TECHNICAL_500_TEXT_TEMPLATE = (""""""
"""{% firstof exception_type 'Report' %}{% if request %} at {{ request.path_info }}{% endif %}
{% firstof exception_value 'No exception message supplied' %} {% firstof exception_value 'No exception message supplied' %}
{% if request %} {% if request %}
Request Method: {{ request.META.REQUEST_METHOD }} Request Method: {{ request.META.REQUEST_METHOD }}
@ -1062,7 +1063,8 @@ Installed Middleware:
{% if postmortem %}Django tried loading these templates, in this order: {% if postmortem %}Django tried loading these templates, in this order:
{% for entry in postmortem %} {% for entry in postmortem %}
Using engine {{ entry.backend.name }}: Using engine {{ entry.backend.name }}:
{% if entry.tried %}{% for attempt in entry.tried %} * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }}) {% if entry.tried %}{% for attempt in entry.tried %}"""
""" * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
{% endfor %}{% else %} This engine did not provide a list of tried templates. {% endfor %}{% else %} This engine did not provide a list of tried templates.
{% endif %}{% endfor %} {% endif %}{% endfor %}
{% else %}No templates were found because your 'TEMPLATES' setting is not configured. {% else %}No templates were found because your 'TEMPLATES' setting is not configured.

View File

@ -272,9 +272,13 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [(
('ref/django-admin', 'django-admin', 'Utility script for the Django Web framework', ['Django Software Foundation'], 1), 'ref/django-admin',
] 'django-admin',
'Utility script for the Django Web framework',
['Django Software Foundation'],
1
), ]
# -- Options for Texinfo output ------------------------------------------------ # -- Options for Texinfo output ------------------------------------------------

View File

@ -4,7 +4,7 @@ install-script = scripts/rpm-install.sh
[flake8] [flake8]
exclude = build,.git,./django/utils/lru_cache.py,./django/utils/six.py,./django/conf/app_template/*,./django/dispatch/weakref_backports.py,./tests/.env,./xmlrunner,tests/view_tests/tests/py3_test_debug.py exclude = build,.git,./django/utils/lru_cache.py,./django/utils/six.py,./django/conf/app_template/*,./django/dispatch/weakref_backports.py,./tests/.env,./xmlrunner,tests/view_tests/tests/py3_test_debug.py
ignore = E123,E128,E402,E501,W503,E731,W601 ignore = E123,E128,E402,W503,E731,W601
max-line-length = 119 max-line-length = 119
[isort] [isort]

View File

@ -227,12 +227,23 @@ class ChangeListTests(TestCase):
context = Context({'cl': cl}) context = Context({'cl': cl})
table_output = template.render(context) table_output = template.render(context)
# make sure that hidden fields are in the correct place # make sure that hidden fields are in the correct place
hiddenfields_div = '<div class="hiddenfields"><input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /></div>' % new_child.id hiddenfields_div = (
'<div class="hiddenfields">'
'<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" />'
'</div>'
) % new_child.id
self.assertInHTML(hiddenfields_div, table_output, msg_prefix='Failed to find hidden fields') self.assertInHTML(hiddenfields_div, table_output, msg_prefix='Failed to find hidden fields')
# make sure that list editable fields are rendered in divs correctly # make sure that list editable fields are rendered in divs correctly
editable_name_field = '<input name="form-0-name" value="name" class="vTextField" maxlength="30" type="text" id="id_form-0-name" />' editable_name_field = (
self.assertInHTML('<td class="field-name">%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field') '<input name="form-0-name" value="name" class="vTextField" '
'maxlength="30" type="text" id="id_form-0-name" />'
)
self.assertInHTML(
'<td class="field-name">%s</td>' % editable_name_field,
table_output,
msg_prefix='Failed to find "name" list_editable field',
)
def test_result_list_editable(self): def test_result_list_editable(self):
""" """

View File

@ -340,7 +340,10 @@ class SystemChecksTestCase(SimpleTestCase):
self.assertEqual(errors, expected) self.assertEqual(errors, expected)
def test_generic_inline_model_admin_non_gfk_ct_field(self): def test_generic_inline_model_admin_non_gfk_ct_field(self):
"A GenericInlineModelAdmin raises problems if the ct_field points to a field that isn't part of a GenericForeignKey" """
A GenericInlineModelAdmin raises problems if the ct_field points to a
field that isn't part of a GenericForeignKey.
"""
class InfluenceInline(GenericStackedInline): class InfluenceInline(GenericStackedInline):
model = Influence model = Influence
ct_field = 'name' ct_field = 'name'
@ -351,7 +354,8 @@ class SystemChecksTestCase(SimpleTestCase):
errors = SongAdmin(Song, AdminSite()).check() errors = SongAdmin(Song, AdminSite()).check()
expected = [ expected = [
checks.Error( checks.Error(
"'admin_checks.Influence' has no GenericForeignKey using content type field 'name' and object ID field 'object_id'.", "'admin_checks.Influence' has no GenericForeignKey using "
"content type field 'name' and object ID field 'object_id'.",
hint=None, hint=None,
obj=InfluenceInline, obj=InfluenceInline,
id='admin.E304', id='admin.E304',
@ -360,7 +364,10 @@ class SystemChecksTestCase(SimpleTestCase):
self.assertEqual(errors, expected) self.assertEqual(errors, expected)
def test_generic_inline_model_admin_non_gfk_fk_field(self): def test_generic_inline_model_admin_non_gfk_fk_field(self):
"A GenericInlineModelAdmin raises problems if the ct_fk_field points to a field that isn't part of a GenericForeignKey" """
A GenericInlineModelAdmin raises problems if the ct_fk_field points to
a field that isn't part of a GenericForeignKey.
"""
class InfluenceInline(GenericStackedInline): class InfluenceInline(GenericStackedInline):
model = Influence model = Influence
ct_fk_field = 'name' ct_fk_field = 'name'
@ -371,7 +378,8 @@ class SystemChecksTestCase(SimpleTestCase):
errors = SongAdmin(Song, AdminSite()).check() errors = SongAdmin(Song, AdminSite()).check()
expected = [ expected = [
checks.Error( checks.Error(
"'admin_checks.Influence' has no GenericForeignKey using content type field 'content_type' and object ID field 'name'.", "'admin_checks.Influence' has no GenericForeignKey using "
"content type field 'content_type' and object ID field 'name'.",
hint=None, hint=None,
obj=InfluenceInline, obj=InfluenceInline,
id='admin.E304', id='admin.E304',
@ -389,8 +397,8 @@ class SystemChecksTestCase(SimpleTestCase):
errors = RawIdNonexistingAdmin(Album, AdminSite()).check() errors = RawIdNonexistingAdmin(Album, AdminSite()).check()
expected = [ expected = [
checks.Error( checks.Error(
("The value of 'raw_id_fields[0]' refers to 'nonexisting', which is " "The value of 'raw_id_fields[0]' refers to 'nonexisting', "
"not an attribute of 'admin_checks.Album'."), "which is not an attribute of 'admin_checks.Album'.",
hint=None, hint=None,
obj=RawIdNonexistingAdmin, obj=RawIdNonexistingAdmin,
id='admin.E002', id='admin.E002',

View File

@ -20,10 +20,16 @@ class Book(models.Model):
related_name='books_authored', related_name='books_authored',
blank=True, null=True, blank=True, null=True,
) )
contributors = models.ManyToManyField(User, verbose_name="Verbose Contributors", related_name='books_contributed', blank=True) contributors = models.ManyToManyField(
User,
verbose_name="Verbose Contributors",
related_name='books_contributed',
blank=True,
)
is_best_seller = models.NullBooleanField(default=0) is_best_seller = models.NullBooleanField(default=0)
date_registered = models.DateField(null=True) date_registered = models.DateField(null=True)
no = models.IntegerField(verbose_name='number', blank=True, null=True) # This field is intentionally 2 characters long. See #16080. # This field name is intentionally 2 characters long (#16080).
no = models.IntegerField(verbose_name='number', blank=True, null=True)
def __str__(self): def __str__(self):
return self.title return self.title

View File

@ -129,11 +129,25 @@ class BookAdmin(ModelAdmin):
class BookAdminWithTupleBooleanFilter(BookAdmin): class BookAdminWithTupleBooleanFilter(BookAdmin):
list_filter = ('year', 'author', 'contributors', ('is_best_seller', BooleanFieldListFilter), 'date_registered', 'no') list_filter = (
'year',
'author',
'contributors',
('is_best_seller', BooleanFieldListFilter),
'date_registered',
'no',
)
class BookAdminWithUnderscoreLookupAndTuple(BookAdmin): class BookAdminWithUnderscoreLookupAndTuple(BookAdmin):
list_filter = ('year', ('author__email', AllValuesFieldListFilter), 'contributors', 'is_best_seller', 'date_registered', 'no') list_filter = (
'year',
('author__email', AllValuesFieldListFilter),
'contributors',
'is_best_seller',
'date_registered',
'no',
)
class BookAdminWithCustomQueryset(ModelAdmin): class BookAdminWithCustomQueryset(ModelAdmin):
@ -231,10 +245,22 @@ class ListFiltersTests(TestCase):
self.lisa = User.objects.create_user('lisa', 'lisa@example.com') self.lisa = User.objects.create_user('lisa', 'lisa@example.com')
# Books # Books
self.djangonaut_book = Book.objects.create(title='Djangonaut: an art of living', year=2009, author=self.alfred, is_best_seller=True, date_registered=self.today) self.djangonaut_book = Book.objects.create(
self.bio_book = Book.objects.create(title='Django: a biography', year=1999, author=self.alfred, is_best_seller=False, no=207) title='Djangonaut: an art of living', year=2009,
self.django_book = Book.objects.create(title='The Django Book', year=None, author=self.bob, is_best_seller=None, date_registered=self.today, no=103) author=self.alfred, is_best_seller=True, date_registered=self.today,
self.gipsy_book = Book.objects.create(title='Gipsy guitar for dummies', year=2002, is_best_seller=True, date_registered=self.one_week_ago) )
self.bio_book = Book.objects.create(
title='Django: a biography', year=1999, author=self.alfred,
is_best_seller=False, no=207,
)
self.django_book = Book.objects.create(
title='The Django Book', year=None, author=self.bob,
is_best_seller=None, date_registered=self.today, no=103,
)
self.gipsy_book = Book.objects.create(
title='Gipsy guitar for dummies', year=2002, is_best_seller=True,
date_registered=self.one_week_ago,
)
self.gipsy_book.contributors = [self.bob, self.lisa] self.gipsy_book.contributors = [self.bob, self.lisa]
self.gipsy_book.save() self.gipsy_book.save()
@ -247,9 +273,13 @@ class ListFiltersTests(TestCase):
self.jack = Employee.objects.create(name='Jack Red', department=self.design) self.jack = Employee.objects.create(name='Jack Red', department=self.design)
def get_changelist(self, request, model, modeladmin): def get_changelist(self, request, model, modeladmin):
return ChangeList(request, model, modeladmin.list_display, modeladmin.list_display_links, return ChangeList(
modeladmin.list_filter, modeladmin.date_hierarchy, modeladmin.search_fields, request, model, modeladmin.list_display,
modeladmin.list_select_related, modeladmin.list_per_page, modeladmin.list_max_show_all, modeladmin.list_editable, modeladmin) modeladmin.list_display_links, modeladmin.list_filter,
modeladmin.date_hierarchy, modeladmin.search_fields,
modeladmin.list_select_related, modeladmin.list_per_page,
modeladmin.list_max_show_all, modeladmin.list_editable, modeladmin,
)
def test_datefieldlistfilter(self): def test_datefieldlistfilter(self):
modeladmin = BookAdmin(Book, site) modeladmin = BookAdmin(Book, site)
@ -730,7 +760,10 @@ class ListFiltersTests(TestCase):
choices = list(filterspec.choices(changelist)) choices = list(filterspec.choices(changelist))
self.assertEqual(choices[3]['display'], 'the 2000\'s') self.assertEqual(choices[3]['display'], 'the 2000\'s')
self.assertEqual(choices[3]['selected'], True) self.assertEqual(choices[3]['selected'], True)
self.assertEqual(choices[3]['query_string'], '?author__id__exact=%s&publication-decade=the+00s' % self.alfred.pk) self.assertEqual(
choices[3]['query_string'],
'?author__id__exact=%s&publication-decade=the+00s' % self.alfred.pk
)
filterspec = changelist.get_filters(request)[0][0] filterspec = changelist.get_filters(request)[0][0]
self.assertEqual(force_text(filterspec.title), 'Verbose Author') self.assertEqual(force_text(filterspec.title), 'Verbose Author')

View File

@ -114,7 +114,11 @@ class TestInline(TestDataMixin, TestCase):
} }
response = self.client.post(reverse('admin:admin_inlines_titlecollection_add'), data) response = self.client.post(reverse('admin:admin_inlines_titlecollection_add'), data)
# Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbox. # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbox.
self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist nonfield"><li>The two titles must be the same</li></ul></td></tr>') self.assertContains(
response,
'<tr><td colspan="4"><ul class="errorlist nonfield">'
'<li>The two titles must be the same</li></ul></td></tr>'
)
def test_no_parent_callable_lookup(self): def test_no_parent_callable_lookup(self):
"""Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable""" """Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable"""
@ -143,10 +147,24 @@ class TestInline(TestDataMixin, TestCase):
""" """
response = self.client.get(reverse('admin:admin_inlines_holder4_add')) response = self.client.get(reverse('admin:admin_inlines_holder4_add'))
self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4) self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4)
self.assertContains(response, '<img src="/static/admin/img/icon-unknown.svg" class="help help-tooltip" width="10" height="10" alt="(Awesome tabular help text is awesome.)" title="Awesome tabular help text is awesome." />', 1) self.assertContains(
response,
'<img src="/static/admin/img/icon-unknown.svg" '
'class="help help-tooltip" width="10" height="10" '
'alt="(Awesome tabular help text is awesome.)" '
'title="Awesome tabular help text is awesome." />',
1
)
# ReadOnly fields # ReadOnly fields
response = self.client.get(reverse('admin:admin_inlines_capofamiglia_add')) response = self.client.get(reverse('admin:admin_inlines_capofamiglia_add'))
self.assertContains(response, '<img src="/static/admin/img/icon-unknown.svg" class="help help-tooltip" width="10" height="10" alt="(Help text for ReadOnlyInline)" title="Help text for ReadOnlyInline" />', 1) self.assertContains(
response,
'<img src="/static/admin/img/icon-unknown.svg" '
'class="help help-tooltip" width="10" height="10" '
'alt="(Help text for ReadOnlyInline)" '
'title="Help text for ReadOnlyInline" />',
1
)
def test_inline_hidden_field_no_column(self): def test_inline_hidden_field_no_column(self):
"""#18263 -- Make sure hidden fields don't get a column in tabular inlines""" """#18263 -- Make sure hidden fields don't get a column in tabular inlines"""
@ -228,13 +246,17 @@ class TestInline(TestDataMixin, TestCase):
def test_custom_get_extra_form(self): def test_custom_get_extra_form(self):
bt_head = BinaryTree.objects.create(name="Tree Head") bt_head = BinaryTree.objects.create(name="Tree Head")
BinaryTree.objects.create(name="First Child", parent=bt_head) BinaryTree.objects.create(name="First Child", parent=bt_head)
# The maximum number of forms should respect 'get_max_num' on the # The maximum number of forms should respect 'get_max_num' on the
# ModelAdmin # ModelAdmin
max_forms_input = '<input id="id_binarytree_set-MAX_NUM_FORMS" name="binarytree_set-MAX_NUM_FORMS" type="hidden" value="%d" />' max_forms_input = (
'<input id="id_binarytree_set-MAX_NUM_FORMS" '
'name="binarytree_set-MAX_NUM_FORMS" type="hidden" value="%d" />'
)
# The total number of forms will remain the same in either case # The total number of forms will remain the same in either case
total_forms_hidden = '<input id="id_binarytree_set-TOTAL_FORMS" name="binarytree_set-TOTAL_FORMS" type="hidden" value="2" />' total_forms_hidden = (
'<input id="id_binarytree_set-TOTAL_FORMS" '
'name="binarytree_set-TOTAL_FORMS" type="hidden" value="2" />'
)
response = self.client.get(reverse('admin:admin_inlines_binarytree_add')) response = self.client.get(reverse('admin:admin_inlines_binarytree_add'))
self.assertContains(response, max_forms_input % 3) self.assertContains(response, max_forms_input % 3)
self.assertContains(response, total_forms_hidden) self.assertContains(response, total_forms_hidden)
@ -254,10 +276,14 @@ class TestInline(TestDataMixin, TestCase):
modeladmin = ModelAdmin(BinaryTree, admin_site) modeladmin = ModelAdmin(BinaryTree, admin_site)
modeladmin.inlines = [MinNumInline] modeladmin.inlines = [MinNumInline]
min_forms = (
min_forms = '<input id="id_binarytree_set-MIN_NUM_FORMS" name="binarytree_set-MIN_NUM_FORMS" type="hidden" value="2" />' '<input id="id_binarytree_set-MIN_NUM_FORMS" '
total_forms = '<input id="id_binarytree_set-TOTAL_FORMS" name="binarytree_set-TOTAL_FORMS" type="hidden" value="5" />' 'name="binarytree_set-MIN_NUM_FORMS" type="hidden" value="2" />'
)
total_forms = (
'<input id="id_binarytree_set-TOTAL_FORMS" '
'name="binarytree_set-TOTAL_FORMS" type="hidden" value="5" />'
)
request = self.factory.get(reverse('admin:admin_inlines_binarytree_add')) request = self.factory.get(reverse('admin:admin_inlines_binarytree_add'))
request.user = User(username='super', is_superuser=True) request.user = User(username='super', is_superuser=True)
response = modeladmin.changeform_view(request) response = modeladmin.changeform_view(request)
@ -282,10 +308,14 @@ class TestInline(TestDataMixin, TestCase):
modeladmin = ModelAdmin(BinaryTree, admin_site) modeladmin = ModelAdmin(BinaryTree, admin_site)
modeladmin.inlines = [MinNumInline] modeladmin.inlines = [MinNumInline]
min_forms = (
min_forms = '<input id="id_binarytree_set-MIN_NUM_FORMS" name="binarytree_set-MIN_NUM_FORMS" type="hidden" value="%d" />' '<input id="id_binarytree_set-MIN_NUM_FORMS" '
total_forms = '<input id="id_binarytree_set-TOTAL_FORMS" name="binarytree_set-TOTAL_FORMS" type="hidden" value="%d" />' 'name="binarytree_set-MIN_NUM_FORMS" type="hidden" value="%d" />'
)
total_forms = (
'<input id="id_binarytree_set-TOTAL_FORMS" '
'name="binarytree_set-TOTAL_FORMS" type="hidden" value="%d" />'
)
request = self.factory.get(reverse('admin:admin_inlines_binarytree_add')) request = self.factory.get(reverse('admin:admin_inlines_binarytree_add'))
request.user = User(username='super', is_superuser=True) request.user = User(username='super', is_superuser=True)
response = modeladmin.changeform_view(request) response = modeladmin.changeform_view(request)
@ -300,21 +330,33 @@ class TestInline(TestDataMixin, TestCase):
def test_inline_nonauto_noneditable_pk(self): def test_inline_nonauto_noneditable_pk(self):
response = self.client.get(reverse('admin:admin_inlines_author_add')) response = self.client.get(reverse('admin:admin_inlines_author_add'))
self.assertContains(response, self.assertContains(
'<input id="id_nonautopkbook_set-0-rand_pk" name="nonautopkbook_set-0-rand_pk" type="hidden" />', response,
html=True) '<input id="id_nonautopkbook_set-0-rand_pk" '
self.assertContains(response, 'name="nonautopkbook_set-0-rand_pk" type="hidden" />',
'<input id="id_nonautopkbook_set-2-0-rand_pk" name="nonautopkbook_set-2-0-rand_pk" type="hidden" />', html=True
html=True) )
self.assertContains(
response,
'<input id="id_nonautopkbook_set-2-0-rand_pk" '
'name="nonautopkbook_set-2-0-rand_pk" type="hidden" />',
html=True
)
def test_inline_editable_pk(self): def test_inline_editable_pk(self):
response = self.client.get(reverse('admin:admin_inlines_author_add')) response = self.client.get(reverse('admin:admin_inlines_author_add'))
self.assertContains(response, self.assertContains(
'<input class="vIntegerField" id="id_editablepkbook_set-0-manual_pk" name="editablepkbook_set-0-manual_pk" type="text" />', response,
html=True, count=1) '<input class="vIntegerField" id="id_editablepkbook_set-0-manual_pk" '
self.assertContains(response, 'name="editablepkbook_set-0-manual_pk" type="text" />',
'<input class="vIntegerField" id="id_editablepkbook_set-2-0-manual_pk" name="editablepkbook_set-2-0-manual_pk" type="text" />', html=True, count=1
html=True, count=1) )
self.assertContains(
response,
'<input class="vIntegerField" id="id_editablepkbook_set-2-0-manual_pk" '
'name="editablepkbook_set-2-0-manual_pk" type="text" />',
html=True, count=1
)
def test_stacked_inline_edit_form_contains_has_original_class(self): def test_stacked_inline_edit_form_contains_has_original_class(self):
holder = Holder.objects.create(dummy=1) holder = Holder.objects.create(dummy=1)
@ -585,8 +627,12 @@ class TestInlinePermissions(TestCase):
self.assertContains(response, 'Add another Author\\u002Dbook relationship') self.assertContains(response, 'Add another Author\\u002Dbook relationship')
self.assertContains(response, '<input type="hidden" id="id_Author_books-TOTAL_FORMS" ' self.assertContains(response, '<input type="hidden" id="id_Author_books-TOTAL_FORMS" '
'value="4" name="Author_books-TOTAL_FORMS" />', html=True) 'value="4" name="Author_books-TOTAL_FORMS" />', html=True)
self.assertContains(response, '<input type="hidden" id="id_Author_books-0-id" ' self.assertContains(
'value="%i" name="Author_books-0-id" />' % self.author_book_auto_m2m_intermediate_id, html=True) response,
'<input type="hidden" id="id_Author_books-0-id" value="%i" '
'name="Author_books-0-id" />' % self.author_book_auto_m2m_intermediate_id,
html=True
)
self.assertContains(response, 'id="id_Author_books-0-DELETE"') self.assertContains(response, 'id="id_Author_books-0-DELETE"')
def test_inline_change_fk_add_perm(self): def test_inline_change_fk_add_perm(self):
@ -597,8 +643,12 @@ class TestInlinePermissions(TestCase):
self.assertContains(response, '<h2>Inner2s</h2>') self.assertContains(response, '<h2>Inner2s</h2>')
self.assertContains(response, 'Add another Inner2') self.assertContains(response, 'Add another Inner2')
# 3 extra forms only, not the existing instance form # 3 extra forms only, not the existing instance form
self.assertContains(response, '<input type="hidden" id="id_inner2_set-TOTAL_FORMS" ' self.assertContains(
'value="3" name="inner2_set-TOTAL_FORMS" />', html=True) response,
'<input type="hidden" id="id_inner2_set-TOTAL_FORMS" value="3" '
'name="inner2_set-TOTAL_FORMS" />',
html=True
)
self.assertNotContains(response, '<input type="hidden" id="id_inner2_set-0-id" ' self.assertNotContains(response, '<input type="hidden" id="id_inner2_set-0-id" '
'value="%i" name="inner2_set-0-id" />' % self.inner2_id, html=True) 'value="%i" name="inner2_set-0-id" />' % self.inner2_id, html=True)

View File

@ -964,21 +964,36 @@ class ManageAlternateSettings(AdminScriptTestCase):
"alternate: manage.py can execute user commands if settings are provided as argument" "alternate: manage.py can execute user commands if settings are provided as argument"
args = ['noargs_command', '--settings=alternate_settings'] args = ['noargs_command', '--settings=alternate_settings']
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertOutput(out, "EXECUTE: noargs_command options=[('no_color', False), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
"EXECUTE: noargs_command options=[('no_color', False), "
"('pythonpath', None), ('settings', 'alternate_settings'), "
"('traceback', False), ('verbosity', 1)]"
)
self.assertNoOutput(err) self.assertNoOutput(err)
def test_custom_command_with_environment(self): def test_custom_command_with_environment(self):
"alternate: manage.py can execute user commands if settings are provided in environment" "alternate: manage.py can execute user commands if settings are provided in environment"
args = ['noargs_command'] args = ['noargs_command']
out, err = self.run_manage(args, 'alternate_settings') out, err = self.run_manage(args, 'alternate_settings')
self.assertOutput(out, "EXECUTE: noargs_command options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
"EXECUTE: noargs_command options=[('no_color', False), "
"('pythonpath', None), ('settings', None), ('traceback', False), "
"('verbosity', 1)]"
)
self.assertNoOutput(err) self.assertNoOutput(err)
def test_custom_command_output_color(self): def test_custom_command_output_color(self):
"alternate: manage.py output syntax color can be deactivated with the `--no-color` option" "alternate: manage.py output syntax color can be deactivated with the `--no-color` option"
args = ['noargs_command', '--no-color', '--settings=alternate_settings'] args = ['noargs_command', '--no-color', '--settings=alternate_settings']
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertOutput(out, "EXECUTE: noargs_command options=[('no_color', True), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
"EXECUTE: noargs_command options=[('no_color', True), "
"('pythonpath', None), ('settings', 'alternate_settings'), "
"('traceback', False), ('verbosity', 1)]"
)
self.assertNoOutput(err) self.assertNoOutput(err)
@ -1660,7 +1675,12 @@ class CommandTypes(AdminScriptTestCase):
args = ['noargs_command'] args = ['noargs_command']
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE: noargs_command options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
"EXECUTE: noargs_command options=[('no_color', False), "
"('pythonpath', None), ('settings', None), ('traceback', False), "
"('verbosity', 1)]"
)
def test_noargs_with_args(self): def test_noargs_with_args(self):
"NoArg Commands raise an error if an argument is provided" "NoArg Commands raise an error if an argument is provided"
@ -1674,7 +1694,11 @@ class CommandTypes(AdminScriptTestCase):
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.auth, options=") self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.auth, options=")
self.assertOutput(out, ", options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
", options=[('no_color', False), ('pythonpath', None), "
"('settings', None), ('traceback', False), ('verbosity', 1)]"
)
def test_app_command_no_apps(self): def test_app_command_no_apps(self):
"User AppCommands raise an error when no app name is provided" "User AppCommands raise an error when no app name is provided"
@ -1688,9 +1712,17 @@ class CommandTypes(AdminScriptTestCase):
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.auth, options=") self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.auth, options=")
self.assertOutput(out, ", options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
", options=[('no_color', False), ('pythonpath', None), "
"('settings', None), ('traceback', False), ('verbosity', 1)]"
)
self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.contenttypes, options=") self.assertOutput(out, "EXECUTE:AppCommand name=django.contrib.contenttypes, options=")
self.assertOutput(out, ", options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
", options=[('no_color', False), ('pythonpath', None), "
"('settings', None), ('traceback', False), ('verbosity', 1)]"
)
def test_app_command_invalid_app_label(self): def test_app_command_invalid_app_label(self):
"User AppCommands can execute when a single app name is provided" "User AppCommands can execute when a single app name is provided"
@ -1709,7 +1741,11 @@ class CommandTypes(AdminScriptTestCase):
args = ['label_command', 'testlabel'] args = ['label_command', 'testlabel']
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
out,
"EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), "
"('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]"
)
def test_label_command_no_label(self): def test_label_command_no_label(self):
"User LabelCommands raise an error if no label is provided" "User LabelCommands raise an error if no label is provided"
@ -1722,8 +1758,16 @@ class CommandTypes(AdminScriptTestCase):
args = ['label_command', 'testlabel', 'anotherlabel'] args = ['label_command', 'testlabel', 'anotherlabel']
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(
self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") out,
"EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), "
"('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]"
)
self.assertOutput(
out,
"EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), "
"('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]"
)
class Discovery(SimpleTestCase): class Discovery(SimpleTestCase):
@ -1794,7 +1838,13 @@ class ArgumentOrder(AdminScriptTestCase):
def _test(self, args, option_b="'2'"): def _test(self, args, option_b="'2'"):
out, err = self.run_manage(args) out, err = self.run_manage(args)
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', %s), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', False), ('verbosity', 1)]" % option_b) self.assertOutput(
out,
"EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), "
"('option_a', 'x'), ('option_b', %s), ('option_c', '3'), "
"('pythonpath', None), ('settings', 'alternate_settings'), "
"('traceback', False), ('verbosity', 1)]" % option_b
)
@override_settings(ROOT_URLCONF='admin_scripts.urls') @override_settings(ROOT_URLCONF='admin_scripts.urls')
@ -1907,7 +1957,10 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
self.assertTrue(os.path.exists(os.path.join(testproject_dir, 'run.py'))) self.assertTrue(os.path.exists(os.path.join(testproject_dir, 'run.py')))
def test_custom_project_template_from_tarball_by_url(self): def test_custom_project_template_from_tarball_by_url(self):
"Make sure the startproject management command is able to use a different project template from a tarball via a url" """
The startproject management command is able to use a different project
template from a tarball via a URL.
"""
template_url = '%s/custom_templates/project_template.tgz' % self.live_server_url template_url = '%s/custom_templates/project_template.tgz' % self.live_server_url
args = ['startproject', '--template', template_url, 'urltestproject'] args = ['startproject', '--template', template_url, 'urltestproject']
@ -1971,7 +2024,11 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
self.write_settings('alternate_settings.py') self.write_settings('alternate_settings.py')
self.addCleanup(self.remove_settings, 'alternate_settings.py') self.addCleanup(self.remove_settings, 'alternate_settings.py')
template_path = os.path.join(custom_templates_dir, 'project_template') template_path = os.path.join(custom_templates_dir, 'project_template')
args = ['custom_startproject', '--template', template_path, 'another_project', 'project_dir', '--extra', '<&>', '--settings=alternate_settings'] args = [
'custom_startproject', '--template', template_path,
'another_project', 'project_dir', '--extra', '<&>',
'--settings=alternate_settings',
]
testproject_dir = os.path.join(self.test_dir, 'project_dir') testproject_dir = os.path.join(self.test_dir, 'project_dir')
os.mkdir(testproject_dir) os.mkdir(testproject_dir)
self.addCleanup(shutil.rmtree, testproject_dir) self.addCleanup(shutil.rmtree, testproject_dir)
@ -1996,7 +2053,10 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
self.assertFalse(os.path.exists(testproject_dir)) self.assertFalse(os.path.exists(testproject_dir))
def test_custom_project_template_with_non_ascii_templates(self): def test_custom_project_template_with_non_ascii_templates(self):
"Ticket 18091: Make sure the startproject management command is able to render templates with non-ASCII content" """
The startproject management command is able to render templates with
non-ASCII content.
"""
template_path = os.path.join(custom_templates_dir, 'project_template') template_path = os.path.join(custom_templates_dir, 'project_template')
args = ['startproject', '--template', template_path, '--extension=txt', 'customtestproject'] args = ['startproject', '--template', template_path, '--extension=txt', 'customtestproject']
testproject_dir = os.path.join(self.test_dir, 'customtestproject') testproject_dir = os.path.join(self.test_dir, 'customtestproject')

View File

@ -587,7 +587,9 @@ class PluggableSearchPersonAdmin(admin.ModelAdmin):
search_fields = ('name',) search_fields = ('name',)
def get_search_results(self, request, queryset, search_term): def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super(PluggableSearchPersonAdmin, self).get_search_results(request, queryset, search_term) queryset, use_distinct = super(PluggableSearchPersonAdmin, self).get_search_results(
request, queryset, search_term
)
try: try:
search_term_as_int = int(search_term) search_term_as_int = int(search_term)
queryset |= self.model.objects.filter(age=search_term_as_int) queryset |= self.model.objects.filter(age=search_term_as_int)

View File

@ -300,7 +300,8 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
""" """
A smoke test to ensure POST on edit_view works. A smoke test to ensure POST on edit_view works.
""" """
response = self.client.post(reverse('admin:admin_views_section_change', args=(self.s1.pk,)), self.inline_post_data) url = reverse('admin:admin_views_section_change', args=(self.s1.pk,))
response = self.client.post(url, self.inline_post_data)
self.assertEqual(response.status_code, 302) # redirect somewhere self.assertEqual(response.status_code, 302) # redirect somewhere
def test_edit_save_as(self): def test_edit_save_as(self):
@ -600,7 +601,10 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
link1 = reverse('admin:admin_views_fabric_change', args=(self.fab1.pk,)) link1 = reverse('admin:admin_views_fabric_change', args=(self.fab1.pk,))
link2 = reverse('admin:admin_views_fabric_change', args=(self.fab2.pk,)) link2 = reverse('admin:admin_views_fabric_change', args=(self.fab2.pk,))
response = self.client.get(reverse('admin:admin_views_fabric_changelist')) response = self.client.get(reverse('admin:admin_views_fabric_changelist'))
fail_msg = "Changelist table isn't showing the right human-readable values set by a model field 'choices' option named group." fail_msg = (
"Changelist table isn't showing the right human-readable values "
"set by a model field 'choices' option named group."
)
self.assertContains(response, '<a href="%s">Horizontal</a>' % link1, msg_prefix=fail_msg, html=True) self.assertContains(response, '<a href="%s">Horizontal</a>' % link1, msg_prefix=fail_msg, html=True)
self.assertContains(response, '<a href="%s">Vertical</a>' % link2, msg_prefix=fail_msg, html=True) self.assertContains(response, '<a href="%s">Vertical</a>' % link2, msg_prefix=fail_msg, html=True)
@ -610,7 +614,10 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
been used in the choices option of a model field. been used in the choices option of a model field.
""" """
response = self.client.get(reverse('admin:admin_views_fabric_changelist')) response = self.client.get(reverse('admin:admin_views_fabric_changelist'))
fail_msg = "Changelist filter isn't showing options contained inside a model field 'choices' option named group." fail_msg = (
"Changelist filter isn't showing options contained inside a model "
"field 'choices' option named group."
)
self.assertContains(response, '<div id="changelist-filter">') self.assertContains(response, '<div id="changelist-filter">')
self.assertContains(response, self.assertContains(response,
'<a href="?surface__exact=x">Horizontal</a>', msg_prefix=fail_msg, html=True) '<a href="?surface__exact=x">Horizontal</a>', msg_prefix=fail_msg, html=True)
@ -684,7 +691,8 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
def test_disallowed_to_field(self): def test_disallowed_to_field(self):
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls: with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
response = self.client.get(reverse('admin:admin_views_section_changelist'), {TO_FIELD_VAR: 'missing_field'}) url = reverse('admin:admin_views_section_changelist')
response = self.client.get(url, {TO_FIELD_VAR: 'missing_field'})
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
@ -726,12 +734,14 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
section = Section.objects.create() section = Section.objects.create()
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls: with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
response = self.client.post(reverse('admin:admin_views_section_change', args=(section.pk,)), {TO_FIELD_VAR: 'name'}) url = reverse('admin:admin_views_section_change', args=(section.pk,))
response = self.client.post(url, {TO_FIELD_VAR: 'name'})
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls: with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
response = self.client.post(reverse('admin:admin_views_section_delete', args=(section.pk,)), {TO_FIELD_VAR: 'name'}) url = reverse('admin:admin_views_section_delete', args=(section.pk,))
response = self.client.post(url, {TO_FIELD_VAR: 'name'})
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
@ -742,7 +752,8 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
can break. can break.
""" """
# Filters should be allowed if they are defined on a ForeignKey pointing to this model # Filters should be allowed if they are defined on a ForeignKey pointing to this model
response = self.client.get("%s?leader__name=Palin&leader__age=27" % reverse('admin:admin_views_inquisition_changelist')) url = "%s?leader__name=Palin&leader__age=27" % reverse('admin:admin_views_inquisition_changelist')
response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_popup_dismiss_related(self): def test_popup_dismiss_related(self):
@ -1787,24 +1798,24 @@ class AdminViewPermissionsTest(TestCase):
rl2 = RowLevelChangePermissionModel.objects.create(name="even id") rl2 = RowLevelChangePermissionModel.objects.create(name="even id")
for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]: for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
self.client.post(login_url, login_dict) self.client.post(login_url, login_dict)
response = self.client.get(reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,))) url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,))
response = self.client.get(url)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
response = self.client.get(reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,))) url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,))
response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.client.get(reverse('admin:logout')) self.client.get(reverse('admin:logout'))
for login_dict in [self.joepublic_login, self.no_username_login]: for login_dict in [self.joepublic_login, self.no_username_login]:
self.client.post(login_url, login_dict) self.client.post(login_url, login_dict)
response = self.client.get( url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,))
reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,)), follow=True response = self.client.get(url, follow=True)
)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'login-form') self.assertContains(response, 'login-form')
response = self.client.get( url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,))
reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,)), follow=True response = self.client.get(url, follow=True)
)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'login-form') self.assertContains(response, 'login-form')
@ -2118,11 +2129,15 @@ class AdminViewDeletedObjectsTest(TestCase):
Objects should be nested to display the relationships that Objects should be nested to display the relationships that
cause them to be scheduled for deletion. cause them to be scheduled for deletion.
""" """
pattern = re.compile(force_bytes( pattern = re.compile(
r'<li>Plot: <a href="%s">World Domination</a>\s*<ul>\s*<li>Plot details: <a href="%s">almost finished</a>' % ( force_bytes(
reverse('admin:admin_views_plot_change', args=(self.pl1.pk,)), r'<li>Plot: <a href="%s">World Domination</a>\s*<ul>\s*'
reverse('admin:admin_views_plotdetails_change', args=(self.pd1.pk,))) r'<li>Plot details: <a href="%s">almost finished</a>' % (
)) reverse('admin:admin_views_plot_change', args=(self.pl1.pk,)),
reverse('admin:admin_views_plotdetails_change', args=(self.pd1.pk,)),
)
)
)
response = self.client.get(reverse('admin:admin_views_villain_delete', args=(self.v1.pk,))) response = self.client.get(reverse('admin:admin_views_villain_delete', args=(self.v1.pk,)))
six.assertRegex(self, response.content, pattern) six.assertRegex(self, response.content, pattern)
@ -2210,7 +2225,9 @@ class AdminViewDeletedObjectsTest(TestCase):
""" """
should_contain = [ should_contain = [
'<li>Villain: <a href="%s">Bob</a>' % reverse('admin:admin_views_villain_change', args=(self.sv1.pk,)), '<li>Villain: <a href="%s">Bob</a>' % reverse('admin:admin_views_villain_change', args=(self.sv1.pk,)),
'<li>Super villain: <a href="%s">Bob</a>' % reverse('admin:admin_views_supervillain_change', args=(self.sv1.pk,)), '<li>Super villain: <a href="%s">Bob</a>' % reverse(
'admin:admin_views_supervillain_change', args=(self.sv1.pk,)
),
'<li>Secret hideout: floating castle', '<li>Secret hideout: floating castle',
'<li>Super secret hideout: super floating castle!', '<li>Super secret hideout: super floating castle!',
] ]
@ -2324,7 +2341,10 @@ class AdminViewStringPrimaryKeyTest(TestCase):
content='<p>Newest content</p>', date=datetime.datetime(2009, 3, 18, 11, 54, 58), section=cls.s1 content='<p>Newest content</p>', date=datetime.datetime(2009, 3, 18, 11, 54, 58), section=cls.s1
) )
cls.p1 = PrePopulatedPost.objects.create(title='A Long Title', published=True, slug='a-long-title') cls.p1 = PrePopulatedPost.objects.create(title='A Long Title', published=True, slug='a-long-title')
cls.pk = """abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 -_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`""" cls.pk = (
"abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 "
"""-_.!~*'() ;/?:@&=+$, <>#%" {}|\^[]`"""
)
cls.m1 = ModelWithStringPrimaryKey.objects.create(string_pk=cls.pk) cls.m1 = ModelWithStringPrimaryKey.objects.create(string_pk=cls.pk)
content_type_pk = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).pk content_type_pk = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).pk
LogEntry.objects.log_action(100, content_type_pk, cls.pk, cls.pk, 2, change_message='Changed something') LogEntry.objects.log_action(100, content_type_pk, cls.pk, cls.pk, 2, change_message='Changed something')
@ -2389,7 +2409,10 @@ class AdminViewStringPrimaryKeyTest(TestCase):
counted_presence_after) counted_presence_after)
def test_logentry_get_admin_url(self): def test_logentry_get_admin_url(self):
"LogEntry.get_admin_url returns a URL to edit the entry's object or None for non-existent (possibly deleted) models" """
LogEntry.get_admin_url returns a URL to edit the entry's object or
None for non-existent (possibly deleted) models.
"""
log_entry_model = "modelwithstringprimarykey" # capitalized in Recent Actions log_entry_model = "modelwithstringprimarykey" # capitalized in Recent Actions
logentry = LogEntry.objects.get(content_type__model__iexact=log_entry_model) logentry = LogEntry.objects.get(content_type__model__iexact=log_entry_model)
desired_admin_url = reverse('admin:admin_views_modelwithstringprimarykey_change', args=(quote(self.pk),)) desired_admin_url = reverse('admin:admin_views_modelwithstringprimarykey_change', args=(quote(self.pk),))
@ -2418,7 +2441,8 @@ class AdminViewStringPrimaryKeyTest(TestCase):
def test_deleteconfirmation_link(self): def test_deleteconfirmation_link(self):
"The link from the delete confirmation page referring back to the changeform of the object should be quoted" "The link from the delete confirmation page referring back to the changeform of the object should be quoted"
response = self.client.get(reverse('admin:admin_views_modelwithstringprimarykey_delete', args=(quote(self.pk),))) url = reverse('admin:admin_views_modelwithstringprimarykey_delete', args=(quote(self.pk),))
response = self.client.get(url)
# this URL now comes through reverse(), thus url quoting and iri_to_uri encoding # this URL now comes through reverse(), thus url quoting and iri_to_uri encoding
change_url = reverse( change_url = reverse(
'admin:admin_views_modelwithstringprimarykey_change', args=('__fk__',) 'admin:admin_views_modelwithstringprimarykey_change', args=('__fk__',)
@ -3028,11 +3052,22 @@ class AdminViewListEditable(TestCase):
Refs #12475. Refs #12475.
""" """
story1 = Story.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...') story1 = Story.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...')
story2 = Story.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...') story2 = Story.objects.create(
title='Crouching Tiger, Hidden Python',
content='The Python was sneaking into...',
)
response = self.client.get(reverse('admin:admin_views_story_changelist')) response = self.client.get(reverse('admin:admin_views_story_changelist'))
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table. # Only one hidden field, in a separate place than the table.
self.assertContains(response, 'id="id_form-0-id"', 1)
self.assertContains(response, 'id="id_form-1-id"', 1) self.assertContains(response, 'id="id_form-1-id"', 1)
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True) self.assertContains(
response,
'<div class="hiddenfields">\n'
'<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" />'
'<input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>'
% (story2.id, story1.id),
html=True
)
self.assertContains(response, '<td class="field-id">%d</td>' % story1.id, 1) self.assertContains(response, '<td class="field-id">%d</td>' % story1.id, 1)
self.assertContains(response, '<td class="field-id">%d</td>' % story2.id, 1) self.assertContains(response, '<td class="field-id">%d</td>' % story2.id, 1)
@ -3041,14 +3076,28 @@ class AdminViewListEditable(TestCase):
referenced in list_display_links. referenced in list_display_links.
Refs #12475. Refs #12475.
""" """
story1 = OtherStory.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...') story1 = OtherStory.objects.create(
story2 = OtherStory.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...') title='The adventures of Guido',
content='Once upon a time in Djangoland...',
)
story2 = OtherStory.objects.create(
title='Crouching Tiger, Hidden Python',
content='The Python was sneaking into...',
)
link1 = reverse('admin:admin_views_otherstory_change', args=(story1.pk,)) link1 = reverse('admin:admin_views_otherstory_change', args=(story1.pk,))
link2 = reverse('admin:admin_views_otherstory_change', args=(story2.pk,)) link2 = reverse('admin:admin_views_otherstory_change', args=(story2.pk,))
response = self.client.get(reverse('admin:admin_views_otherstory_changelist')) response = self.client.get(reverse('admin:admin_views_otherstory_changelist'))
self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table. # Only one hidden field, in a separate place than the table.
self.assertContains(response, 'id="id_form-0-id"', 1)
self.assertContains(response, 'id="id_form-1-id"', 1) self.assertContains(response, 'id="id_form-1-id"', 1)
self.assertContains(response, '<div class="hiddenfields">\n<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>' % (story2.id, story1.id), html=True) self.assertContains(
response,
'<div class="hiddenfields">\n'
'<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" />'
'<input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" />\n</div>'
% (story2.id, story1.id),
html=True
)
self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link1, story1.id), 1) self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link1, story1.id), 1)
self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link2, story2.id), 1) self.assertContains(response, '<th class="field-id"><a href="%s">%d</a></th>' % (link2, story2.id), 1)
@ -3850,9 +3899,11 @@ class AdminCustomQuerysetTest(TestCase):
# Message should contain non-ugly model verbose name. The ugly(!) # Message should contain non-ugly model verbose name. The ugly(!)
# instance representation is set by six.text_type() # instance representation is set by six.text_type()
self.assertContains( self.assertContains(
response, response, (
'<li class="success">The short message &quot;ShortMessage_Deferred_timestamp object&quot; was changed successfully.</li>', '<li class="success">The short message '
html=True '&quot;ShortMessage_Deferred_timestamp object&quot; was '
'changed successfully.</li>'
), html=True
) )
def test_edit_model_modeladmin_only_qs(self): def test_edit_model_modeladmin_only_qs(self):
@ -4462,9 +4513,15 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
# Initial inline # Initial inline
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-pubdate').send_keys('2011-12-17') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-pubdate').send_keys('2011-12-17')
self.get_select_option('#id_relatedprepopulated_set-0-status', 'option one').click() self.get_select_option('#id_relatedprepopulated_set-0-status', 'option one').click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-name').send_keys(' here is a sŤāÇkeð inline ! ') self.selenium.find_element_by_css_selector(
slug1 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-slug1').get_attribute('value') '#id_relatedprepopulated_set-0-name'
slug2 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-slug2').get_attribute('value') ).send_keys(' here is a sŤāÇkeð inline ! ')
slug1 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-0-slug1'
).get_attribute('value')
slug2 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-0-slug2'
).get_attribute('value')
self.assertEqual(slug1, 'here-stacked-inline-2011-12-17') self.assertEqual(slug1, 'here-stacked-inline-2011-12-17')
self.assertEqual(slug2, 'option-one-here-stacked-inline') self.assertEqual(slug2, 'option-one-here-stacked-inline')
@ -4472,19 +4529,34 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
self.selenium.find_elements_by_link_text('Add another Related prepopulated')[0].click() self.selenium.find_elements_by_link_text('Add another Related prepopulated')[0].click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-pubdate').send_keys('1999-01-25') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-pubdate').send_keys('1999-01-25')
self.get_select_option('#id_relatedprepopulated_set-1-status', 'option two').click() self.get_select_option('#id_relatedprepopulated_set-1-status', 'option two').click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-name').send_keys(' now you haVe anöther sŤāÇkeð inline with a very ... loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog text... ') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-name').send_keys(
slug1 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-slug1').get_attribute('value') ' now you haVe anöther sŤāÇkeð inline with a very ... '
slug2 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-1-slug2').get_attribute('value') 'loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog text... '
self.assertEqual(slug1, 'now-you-have-another-stacked-inline-very-loooooooo') # 50 characters maximum for slug1 field )
self.assertEqual(slug2, 'option-two-now-you-have-another-stacked-inline-very-looooooo') # 60 characters maximum for slug2 field slug1 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-1-slug1'
).get_attribute('value')
slug2 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-1-slug2'
).get_attribute('value')
# 50 characters maximum for slug1 field
self.assertEqual(slug1, 'now-you-have-another-stacked-inline-very-loooooooo')
# 60 characters maximum for slug2 field
self.assertEqual(slug2, 'option-two-now-you-have-another-stacked-inline-very-looooooo')
# Tabular inlines ---------------------------------------------------- # Tabular inlines ----------------------------------------------------
# Initial inline # Initial inline
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-pubdate').send_keys('1234-12-07') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-pubdate').send_keys('1234-12-07')
self.get_select_option('#id_relatedprepopulated_set-2-0-status', 'option two').click() self.get_select_option('#id_relatedprepopulated_set-2-0-status', 'option two').click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-name').send_keys('And now, with a tÃbűlaŘ inline !!!') self.selenium.find_element_by_css_selector(
slug1 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-slug1').get_attribute('value') '#id_relatedprepopulated_set-2-0-name'
slug2 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-slug2').get_attribute('value') ).send_keys('And now, with a tÃbűlaŘ inline !!!')
slug1 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-2-0-slug1'
).get_attribute('value')
slug2 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-2-0-slug2'
).get_attribute('value')
self.assertEqual(slug1, 'and-now-tabular-inline-1234-12-07') self.assertEqual(slug1, 'and-now-tabular-inline-1234-12-07')
self.assertEqual(slug2, 'option-two-and-now-tabular-inline') self.assertEqual(slug2, 'option-two-and-now-tabular-inline')
@ -4492,9 +4564,15 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
self.selenium.find_elements_by_link_text('Add another Related prepopulated')[1].click() self.selenium.find_elements_by_link_text('Add another Related prepopulated')[1].click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-pubdate').send_keys('1981-08-22') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-pubdate').send_keys('1981-08-22')
self.get_select_option('#id_relatedprepopulated_set-2-1-status', 'option one').click() self.get_select_option('#id_relatedprepopulated_set-2-1-status', 'option one').click()
self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-name').send_keys('a tÃbűlaŘ inline with ignored ;"&*^\%$#@-/`~ characters') self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-name').send_keys(
slug1 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-slug1').get_attribute('value') 'a tÃbűlaŘ inline with ignored ;"&*^\%$#@-/`~ characters'
slug2 = self.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-slug2').get_attribute('value') )
slug1 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-2-1-slug1'
).get_attribute('value')
slug2 = self.selenium.find_element_by_css_selector(
'#id_relatedprepopulated_set-2-1-slug2'
).get_attribute('value')
self.assertEqual(slug1, 'tabular-inline-ignored-characters-1981-08-22') self.assertEqual(slug1, 'tabular-inline-ignored-characters-1981-08-22')
self.assertEqual(slug2, 'option-one-tabular-inline-ignored-characters') self.assertEqual(slug2, 'option-one-tabular-inline-ignored-characters')
@ -4518,7 +4596,8 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
slug2='option-one-here-stacked-inline', slug2='option-one-here-stacked-inline',
) )
RelatedPrepopulated.objects.get( RelatedPrepopulated.objects.get(
name=' now you haVe anöther sŤāÇkeð inline with a very ... loooooooooooooooooo', # 75 characters in name field # 75 characters in name field
name=' now you haVe anöther sŤāÇkeð inline with a very ... loooooooooooooooooo',
pubdate='1999-01-25', pubdate='1999-01-25',
status='option two', status='option two',
slug1='now-you-have-another-stacked-inline-very-loooooooo', slug1='now-you-have-another-stacked-inline-very-loooooooo',
@ -4713,9 +4792,21 @@ class ReadonlyTest(TestCase):
self.assertContains(response, '<div class="form-row field-value">') self.assertContains(response, '<div class="form-row field-value">')
self.assertContains(response, '<div class="form-row">') self.assertContains(response, '<div class="form-row">')
self.assertContains(response, '<p class="help">', 3) self.assertContains(response, '<p class="help">', 3)
self.assertContains(response, '<p class="help">Some help text for the title (with unicode ŠĐĆŽćžšđ)</p>', html=True) self.assertContains(
self.assertContains(response, '<p class="help">Some help text for the content (with unicode ŠĐĆŽćžšđ)</p>', html=True) response,
self.assertContains(response, '<p class="help">Some help text for the date (with unicode ŠĐĆŽćžšđ)</p>', html=True) '<p class="help">Some help text for the title (with unicode ŠĐĆŽćžšđ)</p>',
html=True
)
self.assertContains(
response,
'<p class="help">Some help text for the content (with unicode ŠĐĆŽćžšđ)</p>',
html=True
)
self.assertContains(
response,
'<p class="help">Some help text for the date (with unicode ŠĐĆŽćžšđ)</p>',
html=True
)
p = Post.objects.create(title="I worked on readonly_fields", content="Its good stuff") p = Post.objects.create(title="I worked on readonly_fields", content="Its good stuff")
response = self.client.get(reverse('admin:admin_views_post_change', args=(p.pk,))) response = self.client.get(reverse('admin:admin_views_post_change', args=(p.pk,)))
@ -5741,20 +5832,30 @@ class AdminKeepChangeListFiltersTests(TestCase):
# Test equality. # Test equality.
change_user_url = reverse('admin:auth_user_change', args=(self.u5.pk,)) change_user_url = reverse('admin:auth_user_change', args=(self.u5.pk,))
self.assertURLEqual( self.assertURLEqual(
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url), 'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url) change_user_url
),
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(
change_user_url
)
) )
# Test inequality. # Test inequality.
with self.assertRaises(AssertionError): with self.assertRaises(AssertionError):
self.assertURLEqual( self.assertURLEqual(
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url), 'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(
'http://testserver{}?_changelist_filters=is_staff__exact%3D1%26is_superuser__exact%3D1'.format(change_user_url) change_user_url
),
'http://testserver{}?_changelist_filters=is_staff__exact%3D1%26is_superuser__exact%3D1'.format(
change_user_url
)
) )
# Ignore scheme and host. # Ignore scheme and host.
self.assertURLEqual( self.assertURLEqual(
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url), 'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(
change_user_url
),
'{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url) '{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(change_user_url)
) )

View File

@ -189,7 +189,10 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase):
filter_vertical=['companies']) filter_vertical=['companies'])
ma = AdvisorAdmin(models.Advisor, admin.site) ma = AdvisorAdmin(models.Advisor, admin.site)
f = ma.formfield_for_dbfield(models.Advisor._meta.get_field('companies'), request=None) f = ma.formfield_for_dbfield(models.Advisor._meta.get_field('companies'), request=None)
self.assertEqual(six.text_type(f.help_text), 'Hold down "Control", or "Command" on a Mac, to select more than one.') self.assertEqual(
six.text_type(f.help_text),
'Hold down "Control", or "Command" on a Mac, to select more than one.'
)
@override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'], @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'],
@ -327,7 +330,11 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase):
w = widgets.AdminSplitDateTime() w = widgets.AdminSplitDateTime()
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', datetime(2007, 12, 1, 9, 30)), w.render('test', datetime(2007, 12, 1, 9, 30)),
'<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>', '<p class="datetime">'
'Date: <input value="2007-12-01" type="text" class="vDateField" '
'name="test_0" size="10" /><br />'
'Time: <input value="09:30:00" type="text" class="vTimeField" '
'name="test_1" size="8" /></p>'
) )
def test_localization(self): def test_localization(self):
@ -337,7 +344,11 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase):
w.is_localized = True w.is_localized = True
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', datetime(2007, 12, 1, 9, 30)), w.render('test', datetime(2007, 12, 1, 9, 30)),
'<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>', '<p class="datetime">'
'Datum: <input value="01.12.2007" type="text" '
'class="vDateField" name="test_0"size="10" /><br />'
'Zeit: <input value="09:30:00" type="text" class="vTimeField" '
'name="test_1" size="8" /></p>'
) )
@ -350,14 +361,20 @@ class AdminURLWidgetTest(SimpleTestCase):
) )
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', 'http://example.com'), w.render('test', 'http://example.com'),
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example.com" /></p>' '<p class="url">Currently:<a href="http://example.com">'
'http://example.com</a><br />'
'Change:<input class="vURLField" name="test" type="url" '
'value="http://example.com" /></p>'
) )
def test_render_idn(self): def test_render_idn(self):
w = widgets.AdminURLFieldWidget() w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', 'http://example-äüö.com'), w.render('test', 'http://example-äüö.com'),
'<p class="url">Currently: <a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="url" value="http://example-äüö.com" /></p>' '<p class="url">Currently: <a href="http://xn--example--7za4pnc.com">'
'http://example-äüö.com</a><br />'
'Change:<input class="vURLField" name="test" type="url" '
'value="http://example-äüö.com" /></p>'
) )
def test_render_quoting(self): def test_render_quoting(self):
@ -366,15 +383,29 @@ class AdminURLWidgetTest(SimpleTestCase):
w = widgets.AdminURLFieldWidget() w = widgets.AdminURLFieldWidget()
self.assertEqual( self.assertEqual(
w.render('test', 'http://example.com/<sometag>some text</sometag>'), w.render('test', 'http://example.com/<sometag>some text</sometag>'),
'<p class="url">Currently: <a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change: <input class="vURLField" name="test" type="url" value="http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></p>' '<p class="url">Currently: '
'<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">'
'http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />'
'Change: <input class="vURLField" name="test" type="url" '
'value="http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></p>'
) )
self.assertEqual( self.assertEqual(
w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>'), w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>'),
'<p class="url">Currently: <a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change: <input class="vURLField" name="test" type="url" value="http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></p>' '<p class="url">Currently: '
'<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">'
'http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />'
'Change: <input class="vURLField" name="test" type="url" '
'value="http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;" /></p>'
) )
self.assertEqual( self.assertEqual(
w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"'), w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"'),
'<p class="url">Currently: <a href="http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22">http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;</a><br />Change: <input class="vURLField" name="test" type="url" value="http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;" /></p>' '<p class="url">Currently: '
'<a href="http://www.example.com/%C3%A4%22%3E%3Cscript%3Ealert(%22XSS!%22)%3C/script%3E%22">'
'http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;'
'alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;</a><br />'
'Change: <input class="vURLField" name="test" type="url" '
'value="http://www.example.com/%C3%A4&quot;&gt;&lt;script&gt;'
'alert(&quot;XSS!&quot;)&lt;/script&gt;&quot;" /></p>'
) )
@ -447,11 +478,12 @@ class ForeignKeyRawIdWidgetTest(TestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', band.pk, attrs={}), ( w.render('test', band.pk, attrs={}),
'<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" />' '<input type="text" name="test" value="%(bandpk)s" '
'<a href="/admin_widgets/band/?_to_field=id" class="related-lookup" id="lookup_id_test" title="Lookup"></a>' 'class="vForeignKeyRawIdAdminField" />'
'&nbsp;<strong>Linkin Park</strong>' '<a href="/admin_widgets/band/?_to_field=id" class="related-lookup" '
) % {'bandpk': band.pk} 'id="lookup_id_test" title="Lookup"></a>&nbsp;<strong>Linkin Park</strong>'
% {'bandpk': band.pk}
) )
def test_relations_to_non_primary_key(self): def test_relations_to_non_primary_key(self):
@ -465,11 +497,12 @@ class ForeignKeyRawIdWidgetTest(TestCase):
rel = models.Inventory._meta.get_field('parent').remote_field rel = models.Inventory._meta.get_field('parent').remote_field
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', core.parent_id, attrs={}), ( w.render('test', core.parent_id, attrs={}),
'<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" />' '<input type="text" name="test" value="86" '
'<a href="/admin_widgets/inventory/?_to_field=barcode" class="related-lookup" id="lookup_id_test" title="Lookup">' 'class="vForeignKeyRawIdAdminField" />'
'</a>&nbsp;<strong>Apple</strong>' '<a href="/admin_widgets/inventory/?_to_field=barcode" '
) 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
'&nbsp;<strong>Apple</strong>'
) )
def test_fk_related_model_not_in_admin(self): def test_fk_related_model_not_in_admin(self):
@ -482,7 +515,9 @@ class ForeignKeyRawIdWidgetTest(TestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('honeycomb_widget', big_honeycomb.pk, attrs={}), w.render('honeycomb_widget', big_honeycomb.pk, attrs={}),
'<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />&nbsp;<strong>Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk} '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />'
'&nbsp;<strong>Honeycomb object</strong>'
% {'hcombpk': big_honeycomb.pk}
) )
def test_fk_to_self_model_not_in_admin(self): def test_fk_to_self_model_not_in_admin(self):
@ -495,7 +530,9 @@ class ForeignKeyRawIdWidgetTest(TestCase):
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('individual_widget', subject1.pk, attrs={}), w.render('individual_widget', subject1.pk, attrs={}),
'<input type="text" name="individual_widget" value="%(subj1pk)s" />&nbsp;<strong>Individual object</strong>' % {'subj1pk': subject1.pk} '<input type="text" name="individual_widget" value="%(subj1pk)s" />'
'&nbsp;<strong>Individual object</strong>'
% {'subj1pk': subject1.pk}
) )
def test_proper_manager_for_label_lookup(self): def test_proper_manager_for_label_lookup(self):
@ -510,11 +547,11 @@ class ForeignKeyRawIdWidgetTest(TestCase):
barcode=94, name='Child of hidden', parent=hidden barcode=94, name='Child of hidden', parent=hidden
) )
self.assertHTMLEqual( self.assertHTMLEqual(
w.render('test', child_of_hidden.parent_id, attrs={}), ( w.render('test', child_of_hidden.parent_id, attrs={}),
'<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" />' '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" />'
'<a href="/admin_widgets/inventory/?_to_field=barcode" class="related-lookup" id="lookup_id_test" title="Lookup">' '<a href="/admin_widgets/inventory/?_to_field=barcode" '
'</a>&nbsp;<strong>Hidden</strong>' 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
) '&nbsp;<strong>Hidden</strong>'
) )

View File

@ -307,7 +307,12 @@ class AggregateTestCase(TestCase):
] ]
) )
books = Book.objects.filter(pk=self.b1.pk).annotate(mean_age=Avg('authors__age')).values('pk', 'isbn', 'mean_age') books = (
Book.objects
.filter(pk=self.b1.pk)
.annotate(mean_age=Avg('authors__age'))
.values('pk', 'isbn', 'mean_age')
)
self.assertEqual( self.assertEqual(
list(books), [ list(books), [
{ {
@ -345,7 +350,12 @@ class AggregateTestCase(TestCase):
] ]
) )
books = Book.objects.values("rating").annotate(n_authors=Count("authors__id"), mean_age=Avg("authors__age")).order_by("rating") books = (
Book.objects
.values("rating")
.annotate(n_authors=Count("authors__id"), mean_age=Avg("authors__age"))
.order_by("rating")
)
self.assertEqual( self.assertEqual(
list(books), [ list(books), [
{ {
@ -561,7 +571,12 @@ class AggregateTestCase(TestCase):
lambda p: p.name lambda p: p.name
) )
publishers = Publisher.objects.annotate(num_books=Count("book__id")).filter(num_books__gt=1, book__price__lt=Decimal("40.0")).order_by("pk") publishers = (
Publisher.objects
.annotate(num_books=Count("book__id"))
.filter(num_books__gt=1, book__price__lt=Decimal("40.0"))
.order_by("pk")
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
publishers, [ publishers, [
"Apress", "Apress",
@ -571,7 +586,13 @@ class AggregateTestCase(TestCase):
lambda p: p.name, lambda p: p.name,
) )
publishers = Publisher.objects.filter(book__price__lt=Decimal("40.0")).annotate(num_books=Count("book__id")).filter(num_books__gt=1).order_by("pk") publishers = (
Publisher.objects
.filter(book__price__lt=Decimal("40.0"))
.annotate(num_books=Count("book__id"))
.filter(num_books__gt=1)
.order_by("pk")
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
publishers, [ publishers, [
"Apress", "Apress",
@ -628,7 +649,12 @@ class AggregateTestCase(TestCase):
lambda b: b.name lambda b: b.name
) )
authors = Author.objects.annotate(num_friends=Count("friends__id", distinct=True)).filter(num_friends=0).order_by("pk") authors = (
Author.objects
.annotate(num_friends=Count("friends__id", distinct=True))
.filter(num_friends=0)
.order_by("pk")
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
authors, [ authors, [
"Brad Dayley", "Brad Dayley",
@ -645,7 +671,12 @@ class AggregateTestCase(TestCase):
lambda p: p.name lambda p: p.name
) )
publishers = Publisher.objects.filter(book__price__lt=Decimal("40.0")).annotate(num_books=Count("book__id")).filter(num_books__gt=1) publishers = (
Publisher.objects
.filter(book__price__lt=Decimal("40.0"))
.annotate(num_books=Count("book__id"))
.filter(num_books__gt=1)
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
publishers, [ publishers, [
"Apress", "Apress",
@ -653,7 +684,11 @@ class AggregateTestCase(TestCase):
lambda p: p.name lambda p: p.name
) )
books = Book.objects.annotate(num_authors=Count("authors__id")).filter(authors__name__contains="Norvig", num_authors__gt=1) books = (
Book.objects
.annotate(num_authors=Count("authors__id"))
.filter(authors__name__contains="Norvig", num_authors__gt=1)
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
books, [ books, [
"Artificial Intelligence: A Modern Approach", "Artificial Intelligence: A Modern Approach",
@ -667,7 +702,12 @@ class AggregateTestCase(TestCase):
b.authors.add(a) b.authors.add(a)
b.save() b.save()
vals = Book.objects.annotate(num_authors=Count("authors__id")).filter(authors__name__contains="Norvig", num_authors__gt=1).aggregate(Avg("rating")) vals = (
Book.objects
.annotate(num_authors=Count("authors__id"))
.filter(authors__name__contains="Norvig", num_authors__gt=1)
.aggregate(Avg("rating"))
)
self.assertEqual(vals, {"rating__avg": 4.25}) self.assertEqual(vals, {"rating__avg": 4.25})
def test_even_more_aggregate(self): def test_even_more_aggregate(self):
@ -718,7 +758,12 @@ class AggregateTestCase(TestCase):
) )
def test_annotate_values_list(self): def test_annotate_values_list(self):
books = Book.objects.filter(pk=self.b1.pk).annotate(mean_age=Avg("authors__age")).values_list("pk", "isbn", "mean_age") books = (
Book.objects
.filter(pk=self.b1.pk)
.annotate(mean_age=Avg("authors__age"))
.values_list("pk", "isbn", "mean_age")
)
self.assertEqual( self.assertEqual(
list(books), [ list(books), [
(1, "159059725", 34.5), (1, "159059725", 34.5),
@ -739,7 +784,12 @@ class AggregateTestCase(TestCase):
] ]
) )
books = Book.objects.filter(pk=self.b1.pk).annotate(mean_age=Avg("authors__age")).values_list("mean_age", flat=True) books = (
Book.objects
.filter(pk=self.b1.pk)
.annotate(mean_age=Avg("authors__age"))
.values_list("mean_age", flat=True)
)
self.assertEqual(list(books), [34.5]) self.assertEqual(list(books), [34.5])
books = Book.objects.values_list("price").annotate(count=Count("price")).order_by("-count", "price") books = Book.objects.values_list("price").annotate(count=Count("price")).order_by("-count", "price")

View File

@ -319,7 +319,13 @@ class AggregationTests(TestCase):
) )
# Check that consecutive calls to annotate accumulate in the query # Check that consecutive calls to annotate accumulate in the query
qs = Book.objects.values('price').annotate(oldest=Max('authors__age')).order_by('oldest', 'price').annotate(Max('publisher__num_awards')) qs = (
Book.objects
.values('price')
.annotate(oldest=Max('authors__age'))
.order_by('oldest', 'price')
.annotate(Max('publisher__num_awards'))
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'price': Decimal("30"), 'oldest': 35, 'publisher__num_awards__max': 3}, {'price': Decimal("30"), 'oldest': 35, 'publisher__num_awards__max': 3},
@ -334,7 +340,12 @@ class AggregationTests(TestCase):
def test_aggrate_annotation(self): def test_aggrate_annotation(self):
# Aggregates can be composed over annotations. # Aggregates can be composed over annotations.
# The return type is derived from the composed aggregate # The return type is derived from the composed aggregate
vals = Book.objects.all().annotate(num_authors=Count('authors__id')).aggregate(Max('pages'), Max('price'), Sum('num_authors'), Avg('num_authors')) vals = (
Book.objects
.all()
.annotate(num_authors=Count('authors__id'))
.aggregate(Max('pages'), Max('price'), Sum('num_authors'), Avg('num_authors'))
)
self.assertEqual(vals, { self.assertEqual(vals, {
'num_authors__sum': 10, 'num_authors__sum': 10,
'num_authors__avg': Approximate(1.666, places=2), 'num_authors__avg': Approximate(1.666, places=2),
@ -441,18 +452,34 @@ class AggregationTests(TestCase):
) )
self.assertEqual( self.assertEqual(
len(Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__lt=3).exclude(num_authors__lt=2)), len(
Book.objects
.annotate(num_authors=Count('authors'))
.filter(num_authors__lt=3)
.exclude(num_authors__lt=2)
),
2 2
) )
self.assertEqual( self.assertEqual(
len(Book.objects.annotate(num_authors=Count('authors')).exclude(num_authors__lt=2).filter(num_authors__lt=3)), len(
Book.objects
.annotate(num_authors=Count('authors'))
.exclude(num_authors__lt=2)
.filter(num_authors__lt=3)
),
2 2
) )
def test_aggregate_fexpr(self): def test_aggregate_fexpr(self):
# Aggregates can be used with F() expressions # Aggregates can be used with F() expressions
# ... where the F() is pushed into the HAVING clause # ... where the F() is pushed into the HAVING clause
qs = Publisher.objects.annotate(num_books=Count('book')).filter(num_books__lt=F('num_awards') / 2).order_by('name').values('name', 'num_books', 'num_awards') qs = (
Publisher.objects
.annotate(num_books=Count('book'))
.filter(num_books__lt=F('num_awards') / 2)
.order_by('name')
.values('name', 'num_books', 'num_awards')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9}, {'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9},
@ -461,7 +488,13 @@ class AggregationTests(TestCase):
lambda p: p, lambda p: p,
) )
qs = Publisher.objects.annotate(num_books=Count('book')).exclude(num_books__lt=F('num_awards') / 2).order_by('name').values('name', 'num_books', 'num_awards') qs = (
Publisher.objects
.annotate(num_books=Count('book'))
.exclude(num_books__lt=F('num_awards') / 2)
.order_by('name')
.values('name', 'num_books', 'num_awards')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'num_books': 2, 'name': 'Apress', 'num_awards': 3}, {'num_books': 2, 'name': 'Apress', 'num_awards': 3},
@ -472,7 +505,13 @@ class AggregationTests(TestCase):
) )
# ... and where the F() references an aggregate # ... and where the F() references an aggregate
qs = Publisher.objects.annotate(num_books=Count('book')).filter(num_awards__gt=2 * F('num_books')).order_by('name').values('name', 'num_books', 'num_awards') qs = (
Publisher.objects
.annotate(num_books=Count('book'))
.filter(num_awards__gt=2 * F('num_books'))
.order_by('name')
.values('name', 'num_books', 'num_awards')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9}, {'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9},
@ -481,7 +520,13 @@ class AggregationTests(TestCase):
lambda p: p, lambda p: p,
) )
qs = Publisher.objects.annotate(num_books=Count('book')).exclude(num_books__lt=F('num_awards') / 2).order_by('name').values('name', 'num_books', 'num_awards') qs = (
Publisher.objects
.annotate(num_books=Count('book'))
.exclude(num_books__lt=F('num_awards') / 2)
.order_by('name')
.values('name', 'num_books', 'num_awards')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'num_books': 2, 'name': 'Apress', 'num_awards': 3}, {'num_books': 2, 'name': 'Apress', 'num_awards': 3},
@ -493,7 +538,11 @@ class AggregationTests(TestCase):
def test_db_col_table(self): def test_db_col_table(self):
# Tests on fields with non-default table and column names. # Tests on fields with non-default table and column names.
qs = Clues.objects.values('EntryID__Entry').annotate(Appearances=Count('EntryID'), Distinct_Clues=Count('Clue', distinct=True)) qs = (
Clues.objects
.values('EntryID__Entry')
.annotate(Appearances=Count('EntryID'), Distinct_Clues=Count('Clue', distinct=True))
)
self.assertQuerysetEqual(qs, []) self.assertQuerysetEqual(qs, [])
qs = Entries.objects.annotate(clue_count=Count('clues__ID')) qs = Entries.objects.annotate(clue_count=Count('clues__ID'))
@ -518,17 +567,45 @@ class AggregationTests(TestCase):
0 0
) )
vals = Book.objects.filter(id__in=[]).aggregate(num_authors=Count('authors'), avg_authors=Avg('authors'), max_authors=Max('authors'), max_price=Max('price'), max_rating=Max('rating')) vals = (
Book.objects
.filter(id__in=[])
.aggregate(
num_authors=Count('authors'),
avg_authors=Avg('authors'),
max_authors=Max('authors'),
max_price=Max('price'),
max_rating=Max('rating'),
)
)
self.assertEqual( self.assertEqual(
vals, vals,
{'max_authors': None, 'max_rating': None, 'num_authors': 0, 'avg_authors': None, 'max_price': None} {'max_authors': None, 'max_rating': None, 'num_authors': 0, 'avg_authors': None, 'max_price': None}
) )
qs = Publisher.objects.filter(name="Jonno's House of Books").annotate(num_authors=Count('book__authors'), avg_authors=Avg('book__authors'), max_authors=Max('book__authors'), max_price=Max('book__price'), max_rating=Max('book__rating')).values() qs = (
Publisher.objects
.filter(name="Jonno's House of Books")
.annotate(
num_authors=Count('book__authors'),
avg_authors=Avg('book__authors'),
max_authors=Max('book__authors'),
max_price=Max('book__price'),
max_rating=Max('book__rating'),
).values()
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs,
{'max_authors': None, 'name': "Jonno's House of Books", 'num_awards': 0, 'max_price': None, 'num_authors': 0, 'max_rating': None, 'id': self.p5.id, 'avg_authors': None} [{
], 'max_authors': None,
'name': "Jonno's House of Books",
'num_awards': 0,
'max_price': None,
'num_authors': 0,
'max_rating': None,
'id': self.p5.id,
'avg_authors': None,
}],
lambda p: p lambda p: p
) )
@ -551,10 +628,16 @@ class AggregationTests(TestCase):
# Regression for #10127 - Empty select_related() works with annotate # Regression for #10127 - Empty select_related() works with annotate
qs = Book.objects.filter(rating__lt=4.5).select_related().annotate(Avg('authors__age')) qs = Book.objects.filter(rating__lt=4.5).select_related().annotate(Avg('authors__age'))
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs,
[
('Artificial Intelligence: A Modern Approach', 51.5, 'Prentice Hall', 'Peter Norvig'), ('Artificial Intelligence: A Modern Approach', 51.5, 'Prentice Hall', 'Peter Norvig'),
('Practical Django Projects', 29.0, 'Apress', 'James Bennett'), ('Practical Django Projects', 29.0, 'Apress', 'James Bennett'),
('Python Web Development with Django', Approximate(30.333, places=2), 'Prentice Hall', 'Jeffrey Forcier'), (
'Python Web Development with Django',
Approximate(30.333, places=2),
'Prentice Hall',
'Jeffrey Forcier',
),
('Sams Teach Yourself Django in 24 Hours', 45.0, 'Sams', 'Brad Dayley') ('Sams Teach Yourself Django in 24 Hours', 45.0, 'Sams', 'Brad Dayley')
], ],
lambda b: (b.name, b.authors__age__avg, b.publisher.name, b.contact.name) lambda b: (b.name, b.authors__age__avg, b.publisher.name, b.contact.name)
@ -573,7 +656,13 @@ class AggregationTests(TestCase):
lambda b: b lambda b: b
) )
qs = Book.objects.extra(select={'pub': 'publisher_id', 'foo': 'pages'}).values('pub').annotate(Count('id')).order_by('pub') qs = (
Book.objects
.extra(select={'pub': 'publisher_id', 'foo': 'pages'})
.values('pub')
.annotate(Count('id'))
.order_by('pub')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
{'pub': self.p1.id, 'id__count': 2}, {'pub': self.p1.id, 'id__count': 2},
@ -586,7 +675,13 @@ class AggregationTests(TestCase):
# Regression for #10182 - Queries with aggregate calls are correctly # Regression for #10182 - Queries with aggregate calls are correctly
# realiased when used in a subquery # realiased when used in a subquery
ids = Book.objects.filter(pages__gt=100).annotate(n_authors=Count('authors')).filter(n_authors__gt=2).order_by('n_authors') ids = (
Book.objects
.filter(pages__gt=100)
.annotate(n_authors=Count('authors'))
.filter(n_authors__gt=2)
.order_by('n_authors')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
Book.objects.filter(id__in=ids), [ Book.objects.filter(id__in=ids), [
"Python Web Development with Django", "Python Web Development with Django",
@ -603,14 +698,20 @@ class AggregationTests(TestCase):
def test_duplicate_alias(self): def test_duplicate_alias(self):
# Regression for #11256 - duplicating a default alias raises ValueError. # Regression for #11256 - duplicating a default alias raises ValueError.
self.assertRaises(ValueError, Book.objects.all().annotate, Avg('authors__age'), authors__age__avg=Avg('authors__age')) self.assertRaises(
ValueError,
Book.objects.all().annotate,
Avg('authors__age'), authors__age__avg=Avg('authors__age')
)
def test_field_name_conflict(self): def test_field_name_conflict(self):
# Regression for #11256 - providing an aggregate name that conflicts with a field name on the model raises ValueError # Regression for #11256 - providing an aggregate name
# that conflicts with a field name on the model raises ValueError
self.assertRaises(ValueError, Author.objects.annotate, age=Avg('friends__age')) self.assertRaises(ValueError, Author.objects.annotate, age=Avg('friends__age'))
def test_m2m_name_conflict(self): def test_m2m_name_conflict(self):
# Regression for #11256 - providing an aggregate name that conflicts with an m2m name on the model raises ValueError # Regression for #11256 - providing an aggregate name
# that conflicts with an m2m name on the model raises ValueError
self.assertRaises(ValueError, Author.objects.annotate, friends=Count('friends')) self.assertRaises(ValueError, Author.objects.annotate, friends=Count('friends'))
def test_values_queryset_non_conflict(self): def test_values_queryset_non_conflict(self):
@ -636,7 +737,8 @@ class AggregationTests(TestCase):
self.assertEqual(results[0]['friends'], 2) self.assertEqual(results[0]['friends'], 2)
def test_reverse_relation_name_conflict(self): def test_reverse_relation_name_conflict(self):
# Regression for #11256 - providing an aggregate name that conflicts with a reverse-related name on the model raises ValueError # Regression for #11256 - providing an aggregate name
# that conflicts with a reverse-related name on the model raises ValueError
self.assertRaises(ValueError, Author.objects.annotate, book_contact_set=Avg('friends__age')) self.assertRaises(ValueError, Author.objects.annotate, book_contact_set=Avg('friends__age'))
def test_pickle(self): def test_pickle(self):
@ -682,7 +784,13 @@ class AggregationTests(TestCase):
# Regression for #10290 - extra selects with parameters can be used for # Regression for #10290 - extra selects with parameters can be used for
# grouping. # grouping.
qs = Book.objects.annotate(mean_auth_age=Avg('authors__age')).extra(select={'sheets': '(pages + %s) / %s'}, select_params=[1, 2]).order_by('sheets').values('sheets') qs = (
Book.objects
.annotate(mean_auth_age=Avg('authors__age'))
.extra(select={'sheets': '(pages + %s) / %s'}, select_params=[1, 2])
.order_by('sheets')
.values('sheets')
)
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs, [
150, 150,
@ -766,18 +874,26 @@ class AggregationTests(TestCase):
qs = HardbackBook.objects.annotate(n_authors=Count('book_ptr__authors')).values('name', 'n_authors') qs = HardbackBook.objects.annotate(n_authors=Count('book_ptr__authors')).values('name', 'n_authors')
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs,
[
{'n_authors': 2, 'name': 'Artificial Intelligence: A Modern Approach'}, {'n_authors': 2, 'name': 'Artificial Intelligence: A Modern Approach'},
{'n_authors': 1, 'name': 'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'} {
'n_authors': 1,
'name': 'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'
}
], ],
lambda h: h lambda h: h
) )
qs = HardbackBook.objects.annotate(n_authors=Count('authors')).values('name', 'n_authors') qs = HardbackBook.objects.annotate(n_authors=Count('authors')).values('name', 'n_authors')
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs,
[
{'n_authors': 2, 'name': 'Artificial Intelligence: A Modern Approach'}, {'n_authors': 2, 'name': 'Artificial Intelligence: A Modern Approach'},
{'n_authors': 1, 'name': 'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'} {
'n_authors': 1,
'name': 'Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp'
}
], ],
lambda h: h, lambda h: h,
) )
@ -871,11 +987,17 @@ class AggregationTests(TestCase):
attrgetter("name") attrgetter("name")
) )
qs = Book.objects.annotate(n_authors=Count("authors")).filter( qs = (
Q(name="The Definitive Guide to Django: Web Development Done Right") | (Q(name="Artificial Intelligence: A Modern Approach") & Q(n_authors=3)) Book.objects
.annotate(n_authors=Count("authors"))
.filter(
Q(name="The Definitive Guide to Django: Web Development Done Right")
| (Q(name="Artificial Intelligence: A Modern Approach") & Q(n_authors=3))
)
) )
self.assertQuerysetEqual( self.assertQuerysetEqual(
qs, [ qs,
[
"The Definitive Guide to Django: Web Development Done Right", "The Definitive Guide to Django: Web Development Done Right",
], ],
attrgetter("name") attrgetter("name")

View File

@ -38,7 +38,8 @@ class TestSessionAuthenticationMiddleware(TestCase):
self.assertEqual(session_key, self.request.session.session_key) self.assertEqual(session_key, self.request.session.session_key)
def test_changed_password_invalidates_session_with_middleware(self): def test_changed_password_invalidates_session_with_middleware(self):
with self.modify_settings(MIDDLEWARE_CLASSES={'append': ['django.contrib.auth.middleware.SessionAuthenticationMiddleware']}): with self.modify_settings(
MIDDLEWARE_CLASSES={'append': ['django.contrib.auth.middleware.SessionAuthenticationMiddleware']}):
# After password change, user should be anonymous # After password change, user should be anonymous
self.user.set_password('new_password') self.user.set_password('new_password')
self.user.save() self.user.save()

View File

@ -157,7 +157,11 @@ class PostgreSQLTests(TestCase):
self.assert_parses("EnterpriseDB 9.3", 90300) self.assert_parses("EnterpriseDB 9.3", 90300)
self.assert_parses("PostgreSQL 9.3.6", 90306) self.assert_parses("PostgreSQL 9.3.6", 90306)
self.assert_parses("PostgreSQL 9.4beta1", 90400) self.assert_parses("PostgreSQL 9.4beta1", 90400)
self.assert_parses("PostgreSQL 9.3.1 on i386-apple-darwin9.2.2, compiled by GCC i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)", 90301) self.assert_parses(
"PostgreSQL 9.3.1 on i386-apple-darwin9.2.2, compiled by GCC "
"i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)",
90301
)
def test_nodb_connection(self): def test_nodb_connection(self):
""" """
@ -419,13 +423,19 @@ class LongNameTest(TransactionTestCase):
models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
def test_sequence_name_length_limits_m2m(self): def test_sequence_name_length_limits_m2m(self):
"""Test an m2m save of a model with a long name and a long m2m field name doesn't error as on Django >=1.2 this now uses object saves. Ref #8901""" """
An m2m save of a model with a long name and a long m2m field name
doesn't error (#8901).
"""
obj = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() obj = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt') rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt')
obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj) obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj)
def test_sequence_name_length_limits_flush(self): def test_sequence_name_length_limits_flush(self):
"""Test that sequence resetting as part of a flush with model with long name and long pk name doesn't error. Ref #8901""" """
Sequence resetting as part of a flush with model with long name and
long pk name doesn't error (#8901).
"""
# A full flush is expensive to the full test, so we dig into the # A full flush is expensive to the full test, so we dig into the
# internals to generate the likely offending SQL and run it manually # internals to generate the likely offending SQL and run it manually
@ -834,11 +844,16 @@ class FkConstraintsTests(TransactionTestCase):
def test_disable_constraint_checks_manually(self): def test_disable_constraint_checks_manually(self):
""" """
When constraint checks are disabled, should be able to write bad data without IntegrityErrors. When constraint checks are disabled, should be able to write bad data
without IntegrityErrors.
""" """
with transaction.atomic(): with transaction.atomic():
# Create an Article. # Create an Article.
models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) models.Article.objects.create(
headline="Test article",
pub_date=datetime.datetime(2010, 9, 4),
reporter=self.r,
)
# Retrieve it from the DB # Retrieve it from the DB
a = models.Article.objects.get(headline="Test article") a = models.Article.objects.get(headline="Test article")
a.reporter_id = 30 a.reporter_id = 30
@ -852,11 +867,16 @@ class FkConstraintsTests(TransactionTestCase):
def test_disable_constraint_checks_context_manager(self): def test_disable_constraint_checks_context_manager(self):
""" """
When constraint checks are disabled (using context manager), should be able to write bad data without IntegrityErrors. When constraint checks are disabled (using context manager), should be
able to write bad data without IntegrityErrors.
""" """
with transaction.atomic(): with transaction.atomic():
# Create an Article. # Create an Article.
models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) models.Article.objects.create(
headline="Test article",
pub_date=datetime.datetime(2010, 9, 4),
reporter=self.r,
)
# Retrieve it from the DB # Retrieve it from the DB
a = models.Article.objects.get(headline="Test article") a = models.Article.objects.get(headline="Test article")
a.reporter_id = 30 a.reporter_id = 30
@ -873,7 +893,11 @@ class FkConstraintsTests(TransactionTestCase):
""" """
with transaction.atomic(): with transaction.atomic():
# Create an Article. # Create an Article.
models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) models.Article.objects.create(
headline="Test article",
pub_date=datetime.datetime(2010, 9, 4),
reporter=self.r,
)
# Retrieve it from the DB # Retrieve it from the DB
a = models.Article.objects.get(headline="Test article") a = models.Article.objects.get(headline="Test article")
a.reporter_id = 30 a.reporter_id = 30

View File

@ -1844,7 +1844,8 @@ class CacheMiddlewareTest(SimpleTestCase):
self.assertEqual(as_view_decorator.cache_timeout, 30) # Timeout value for 'default' cache, i.e. 30 self.assertEqual(as_view_decorator.cache_timeout, 30) # Timeout value for 'default' cache, i.e. 30
self.assertEqual(as_view_decorator.key_prefix, '') self.assertEqual(as_view_decorator.key_prefix, '')
self.assertEqual(as_view_decorator.cache_alias, 'default') # Value of DEFAULT_CACHE_ALIAS from django.core.cache # Value of DEFAULT_CACHE_ALIAS from django.core.cache
self.assertEqual(as_view_decorator.cache_alias, 'default')
# Next, test with custom values: # Next, test with custom values:
as_view_decorator_with_custom = CacheMiddleware(cache_timeout=60, cache_alias='other', key_prefix='foo') as_view_decorator_with_custom = CacheMiddleware(cache_timeout=60, cache_alias='other', key_prefix='foo')

View File

@ -164,7 +164,10 @@ class GenericForeignKeyTests(IsolatedModelsTestCase):
expected = [ expected = [
checks.Error( checks.Error(
"'Model.content_type' is not a ForeignKey.", "'Model.content_type' is not a ForeignKey.",
hint="GenericForeignKeys must use a ForeignKey to 'contenttypes.ContentType' as the 'content_type' field.", hint=(
"GenericForeignKeys must use a ForeignKey to "
"'contenttypes.ContentType' as the 'content_type' field."
),
obj=Model.content_object, obj=Model.content_object,
id='contenttypes.E003', id='contenttypes.E003',
) )
@ -182,7 +185,10 @@ class GenericForeignKeyTests(IsolatedModelsTestCase):
expected = [ expected = [
checks.Error( checks.Error(
"'Model.content_type' is not a ForeignKey to 'contenttypes.ContentType'.", "'Model.content_type' is not a ForeignKey to 'contenttypes.ContentType'.",
hint="GenericForeignKeys must use a ForeignKey to 'contenttypes.ContentType' as the 'content_type' field.", hint=(
"GenericForeignKeys must use a ForeignKey to "
"'contenttypes.ContentType' as the 'content_type' field."
),
obj=Model.content_object, obj=Model.content_object,
id='contenttypes.E004', id='contenttypes.E004',
) )

View File

@ -24,7 +24,10 @@ class MultiDBChangepasswordManagementCommandTestCase(TestCase):
command.execute(username="joe", database='other', stdout=out) command.execute(username="joe", database='other', stdout=out)
command_output = out.getvalue().strip() command_output = out.getvalue().strip()
self.assertEqual(command_output, "Changing password for user 'joe'\nPassword changed successfully for user 'joe'") self.assertEqual(
command_output,
"Changing password for user 'joe'\nPassword changed successfully for user 'joe'"
)
self.assertTrue(models.User.objects.using('other').get(username="joe").check_password("not qwerty")) self.assertTrue(models.User.objects.using('other').get(username="joe").check_password("not qwerty"))

View File

@ -95,7 +95,8 @@ class CustomColumnsTests(TestCase):
def test_filter_on_nonexistent_field(self): def test_filter_on_nonexistent_field(self):
self.assertRaisesMessage( self.assertRaisesMessage(
FieldError, FieldError,
"Cannot resolve keyword 'firstname' into field. Choices are: Author_ID, article, first_name, last_name, primary_set", "Cannot resolve keyword 'firstname' into field. Choices are: "
"Author_ID, article, first_name, last_name, primary_set",
Author.objects.filter, Author.objects.filter,
firstname__exact='John' firstname__exact='John'
) )

View File

@ -53,4 +53,8 @@ class DBTypeCasts(unittest.TestCase):
for k, v in six.iteritems(TEST_CASES): for k, v in six.iteritems(TEST_CASES):
for inpt, expected in v: for inpt, expected in v:
got = getattr(typecasts, k)(inpt) got = getattr(typecasts, k)(inpt)
self.assertEqual(got, expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got)) self.assertEqual(
got,
expected,
"In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got)
)

View File

@ -689,7 +689,15 @@ class CaseExpressionTests(TestCase):
) )
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.all().order_by('pk'), CaseTestModel.objects.all().order_by('pk'),
[(1, Decimal('1.1')), (2, Decimal('2.2')), (3, None), (2, Decimal('2.2')), (3, None), (3, None), (4, None)], [
(1, Decimal('1.1')),
(2, Decimal('2.2')),
(3, None),
(2, Decimal('2.2')),
(3, None),
(3, None),
(4, None)
],
transform=attrgetter('integer', 'decimal') transform=attrgetter('integer', 'decimal')
) )
@ -934,8 +942,13 @@ class CaseExpressionTests(TestCase):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.all().order_by('pk'), CaseTestModel.objects.all().order_by('pk'),
[ [
(1, UUID('11111111111111111111111111111111')), (2, UUID('22222222222222222222222222222222')), (3, None), (1, UUID('11111111111111111111111111111111')),
(2, UUID('22222222222222222222222222222222')), (3, None), (3, None), (4, None) (2, UUID('22222222222222222222222222222222')),
(3, None),
(2, UUID('22222222222222222222222222222222')),
(3, None),
(3, None),
(4, None),
], ],
transform=attrgetter('integer', 'uuid') transform=attrgetter('integer', 'uuid')
) )

View File

@ -185,100 +185,174 @@ class ExtraRegressTests(TestCase):
obj.save() obj.save()
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values()), list(
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}] TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values()
),
[{
'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first',
'id': obj.pk, 'first': 'first'
}]
) )
# Extra clauses after an empty values clause are still included # Extra clauses after an empty values clause are still included
self.assertEqual( self.assertEqual(
list(TestObject.objects.values().extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))), list(
[{'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first', 'id': obj.pk, 'first': 'first'}] TestObject.objects
.values()
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
),
[{
'bar': 'second', 'third': 'third', 'second': 'second', 'whiz': 'third', 'foo': 'first',
'id': obj.pk, 'first': 'first'
}]
) )
# Extra columns are ignored if not mentioned in the values() clause # Extra columns are ignored if not mentioned in the values() clause
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values('first', 'second')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values('first', 'second')
),
[{'second': 'second', 'first': 'first'}] [{'second': 'second', 'first': 'first'}]
) )
# Extra columns after a non-empty values() clause are ignored # Extra columns after a non-empty values() clause are ignored
self.assertEqual( self.assertEqual(
list(TestObject.objects.values('first', 'second').extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))), list(
TestObject.objects
.values('first', 'second')
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
),
[{'second': 'second', 'first': 'first'}] [{'second': 'second', 'first': 'first'}]
) )
# Extra columns can be partially returned # Extra columns can be partially returned
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values('first', 'second', 'foo')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values('first', 'second', 'foo')
),
[{'second': 'second', 'foo': 'first', 'first': 'first'}] [{'second': 'second', 'foo': 'first', 'first': 'first'}]
) )
# Also works if only extra columns are included # Also works if only extra columns are included
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values('foo', 'whiz')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values('foo', 'whiz')
),
[{'foo': 'first', 'whiz': 'third'}] [{'foo': 'first', 'whiz': 'third'}]
) )
# Values list works the same way # Values list works the same way
# All columns are returned for an empty values_list() # All columns are returned for an empty values_list()
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list()), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list()
),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')] [('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
) )
# Extra columns after an empty values_list() are still included # Extra columns after an empty values_list() are still included
self.assertEqual( self.assertEqual(
list(TestObject.objects.values_list().extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))), list(
TestObject.objects
.values_list()
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
),
[('first', 'second', 'third', obj.pk, 'first', 'second', 'third')] [('first', 'second', 'third', obj.pk, 'first', 'second', 'third')]
) )
# Extra columns ignored completely if not mentioned in values_list() # Extra columns ignored completely if not mentioned in values_list()
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('first', 'second')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('first', 'second')
),
[('first', 'second')] [('first', 'second')]
) )
# Extra columns after a non-empty values_list() clause are ignored completely # Extra columns after a non-empty values_list() clause are ignored completely
self.assertEqual( self.assertEqual(
list(TestObject.objects.values_list('first', 'second').extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))), list(
TestObject.objects
.values_list('first', 'second')
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
),
[('first', 'second')] [('first', 'second')]
) )
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('second', flat=True)), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('second', flat=True)
),
['second'] ['second']
) )
# Only the extra columns specified in the values_list() are returned # Only the extra columns specified in the values_list() are returned
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('first', 'second', 'whiz')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('first', 'second', 'whiz')
),
[('first', 'second', 'third')] [('first', 'second', 'third')]
) )
# ...also works if only extra columns are included # ...also works if only extra columns are included
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('foo', 'whiz')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('foo', 'whiz')
),
[('first', 'third')] [('first', 'third')]
) )
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('whiz', flat=True)), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('whiz', flat=True)
),
['third'] ['third']
) )
# ... and values are returned in the order they are specified # ... and values are returned in the order they are specified
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('whiz', 'foo')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('whiz', 'foo')
),
[('third', 'first')] [('third', 'first')]
) )
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('first', 'id')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('first', 'id')
),
[('first', obj.pk)] [('first', obj.pk)]
) )
self.assertEqual( self.assertEqual(
list(TestObject.objects.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third')))).values_list('whiz', 'first', 'bar', 'id')), list(
TestObject.objects
.extra(select=OrderedDict((('foo', 'first'), ('bar', 'second'), ('whiz', 'third'))))
.values_list('whiz', 'first', 'bar', 'id')
),
[('third', 'first', 'second', obj.pk)] [('third', 'first', 'second', obj.pk)]
) )

View File

@ -156,14 +156,18 @@ class FileUploadTests(TestCase):
(#22971). (#22971).
""" """
payload = client.FakePayload() payload = client.FakePayload()
payload.write('\r\n'.join([ payload.write(
'--' + client.BOUNDARY, '\r\n'.join([
'Content-Disposition: form-data; name*=UTF-8\'\'file_unicode; filename*=UTF-8\'\'%s' % urlquote(UNICODE_FILENAME), '--' + client.BOUNDARY,
'Content-Type: application/octet-stream', 'Content-Disposition: form-data; name*=UTF-8\'\'file_unicode; filename*=UTF-8\'\'%s' % urlquote(
'', UNICODE_FILENAME
'You got pwnd.\r\n', ),
'\r\n--' + client.BOUNDARY + '--\r\n' 'Content-Type: application/octet-stream',
])) '',
'You got pwnd.\r\n',
'\r\n--' + client.BOUNDARY + '--\r\n'
])
)
r = { r = {
'CONTENT_LENGTH': len(payload), 'CONTENT_LENGTH': len(payload),

View File

@ -89,32 +89,83 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
]) ])
# Dump the current contents of the database as a JSON fixture # Dump the current contents of the database as a JSON fixture
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Try just dumping the contents of fixtures.Category # Try just dumping the contents of fixtures.Category
self._dumpdata_assert(['fixtures.Category'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]') self._dumpdata_assert(
['fixtures.Category'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", '
'"title": "News Stories"}}]'
)
# ...and just fixtures.Article # ...and just fixtures.Article
self._dumpdata_assert(['fixtures.Article'], '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures.Article'],
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": '
'"Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# ...and both # ...and both
self._dumpdata_assert(['fixtures.Category', 'fixtures.Article'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures.Category', 'fixtures.Article'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", '
'"title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has '
'no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", '
'"fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Specify a specific model twice # Specify a specific model twice
self._dumpdata_assert(['fixtures.Article', 'fixtures.Article'], '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures.Article', 'fixtures.Article'],
(
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": '
'"Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
)
# Specify a dump that specifies Article both explicitly and implicitly # Specify a dump that specifies Article both explicitly and implicitly
self._dumpdata_assert(['fixtures.Article', 'fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures.Article', 'fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Specify a dump that specifies Article both explicitly and implicitly, # Specify a dump that specifies Article both explicitly and implicitly,
# but lists the app first (#22025). # but lists the app first (#22025).
self._dumpdata_assert(['fixtures', 'fixtures.Article'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures', 'fixtures.Article'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Same again, but specify in the reverse order # Same again, but specify in the reverse order
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no '
'place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields":'
' {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Specify one model from one application, and an entire other application. # Specify one model from one application, and an entire other application.
self._dumpdata_assert(['fixtures.Category', 'sites'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}]') self._dumpdata_assert(
['fixtures.Category', 'sites'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": '
'"example.com"}}]'
)
# Load fixture 2. JSON file imported by default. Overwrites some existing objects # Load fixture 2. JSON file imported by default. Overwrites some existing objects
management.call_command('loaddata', 'fixture2.json', verbosity=0) management.call_command('loaddata', 'fixture2.json', verbosity=0)
@ -174,20 +225,106 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
]) ])
# By default, you get raw keys on dumpdata # By default, you get raw keys on dumpdata
self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}]') self._dumpdata_assert(
['fixtures.book'],
'[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}]'
)
# But you can get natural keys if you ask for them and they are available # But you can get natural keys if you ask for them and they are available
self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) self._dumpdata_assert(
['fixtures.book'],
'[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist '
'formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]',
natural_foreign_keys=True
)
# You can also omit the primary keys for models that we can get later with natural keys. # You can also omit the primary keys for models that we can get later with natural keys.
self._dumpdata_assert(['fixtures.person'], '[{"fields": {"name": "Django Reinhardt"}, "model": "fixtures.person"}, {"fields": {"name": "Stephane Grappelli"}, "model": "fixtures.person"}, {"fields": {"name": "Artist formerly known as \\"Prince\\""}, "model": "fixtures.person"}]', natural_primary_keys=True) self._dumpdata_assert(
['fixtures.person'],
'[{"fields": {"name": "Django Reinhardt"}, "model": "fixtures.person"}, {"fields": {"name": "Stephane '
'Grappelli"}, "model": "fixtures.person"}, {"fields": {"name": "Artist formerly known as '
'\\"Prince\\""}, "model": "fixtures.person"}]',
natural_primary_keys=True
)
# Dump the current contents of the database as a JSON fixture # Dump the current contents of the database as a JSON fixture
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16T11:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16T15:00:00"}}, {"pk": 5, "model": "fixtures.article", "fields": {"headline": "XML identified as leading cause of cancer", "pub_date": "2006-06-16T16:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "world domination", "tagged_id": 4}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.visa", "fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person": ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) self._dumpdata_assert(
['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is '
'great!", "pub_date": "2006-06-16T11:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}, {"pk": 4, '
'"model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": '
'"2006-06-16T15:00:00"}}, {"pk": 5, "model": "fixtures.article", "fields": {"headline": "XML '
'identified as leading cause of cancer", "pub_date": "2006-06-16T16:00:00"}}, {"pk": 1, "model": '
'"fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": '
'3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": '
'"legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", '
'"article"], "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": '
'{"tagged_type": ["fixtures", "article"], "name": "world domination", "tagged_id": 4}}, {"pk": 1, '
'"model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": '
'"fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 3, "model": "fixtures.person", '
'"fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.visa", '
'"fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], '
'["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": '
'"fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", '
'"user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person":'
' ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, '
'{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist '
'formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]',
natural_foreign_keys=True
)
# Dump the current contents of the database as an XML fixture # Dump the current contents of the database as an XML fixture
self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> self._dumpdata_assert(
<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker on TV is great!</field><field type="DateTimeField" name="pub_date">2006-06-16T11:00:00</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Copyright is fine the way it is</field><field type="DateTimeField" name="pub_date">2006-06-16T14:00:00</field></object><object pk="4" model="fixtures.article"><field type="CharField" name="headline">Django conquers world!</field><field type="DateTimeField" name="pub_date">2006-06-16T15:00:00</field></object><object pk="5" model="fixtures.article"><field type="CharField" name="headline">XML identified as leading cause of cancer</field><field type="DateTimeField" name="pub_date">2006-06-16T16:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">legal</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="3" model="fixtures.tag"><field type="CharField" name="name">django</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="4" model="fixtures.tag"><field type="CharField" name="name">world domination</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="1" model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as "Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object></django-objects>""", format='xml', natural_foreign_keys=True) ['fixtures'],
'<?xml version="1.0" encoding="utf-8"?><django-objects version="1.0"><object pk="1" '
'model="fixtures.category"><field type="CharField" name="title">News Stories</field><field '
'type="TextField" name="description">Latest news stories</field></object><object pk="2" '
'model="fixtures.article"><field type="CharField" name="headline">Poker on TV is great!</field><field '
'type="DateTimeField" name="pub_date">2006-06-16T11:00:00</field></object><object pk="3" '
'model="fixtures.article"><field type="CharField" name="headline">Copyright is fine the way it '
'is</field><field type="DateTimeField" name="pub_date">2006-06-16T14:00:00</field></object><object '
'pk="4" model="fixtures.article"><field type="CharField" name="headline">Django conquers world!'
'</field><field type="DateTimeField" name="pub_date">2006-06-16T15:00:00</field></object><object '
'pk="5" model="fixtures.article"><field type="CharField" name="headline">XML identified as leading '
'cause of cancer</field><field type="DateTimeField" name="pub_date">2006-06-16T16:00:00</field>'
'</object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field>'
'<field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures'
'</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3'
'</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">legal'
'</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>'
'fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" '
'name="tagged_id">3</field></object><object pk="3" model="fixtures.tag"><field type="CharField" '
'name="name">django</field><field to="contenttypes.contenttype" name="tagged_type" '
'rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field '
'type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="4" model="fixtures.tag">'
'<field type="CharField" name="name">world domination</field><field to="contenttypes.contenttype" '
'name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field>'
'<field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="1" '
'model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object>'
'<object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli'
'</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">'
'Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.visa"><field '
'to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field>'
'<field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user'
'</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user'
'</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user'
'</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" '
'model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane'
' Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel">'
'<object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object>'
'<natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field>'
'</object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" '
'rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field '
'to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural>'
'<natural>auth</natural><natural>user</natural></object></field></object><object pk="1" '
'model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field '
'to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as '
'"Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object>'
'</django-objects>',
format='xml', natural_foreign_keys=True
)
def test_dumpdata_with_excludes(self): def test_dumpdata_with_excludes(self):
# Load fixture1 which has a site, two articles, and a category # Load fixture1 which has a site, two articles, and a category
@ -203,20 +340,28 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
# Excluding fixtures.Article/Book should leave fixtures.Category # Excluding fixtures.Article/Book should leave fixtures.Category
self._dumpdata_assert( self._dumpdata_assert(
['sites', 'fixtures'], ['sites', 'fixtures'],
'[{"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]', '[{"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, '
exclude_list=['fixtures.Article', 'fixtures.Book']) '{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}]',
exclude_list=['fixtures.Article', 'fixtures.Book']
)
# Excluding fixtures and fixtures.Article/Book should be a no-op # Excluding fixtures and fixtures.Article/Book should be a no-op
self._dumpdata_assert( self._dumpdata_assert(
['sites', 'fixtures'], ['sites', 'fixtures'],
'[{"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]', '[{"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, '
exclude_list=['fixtures.Article', 'fixtures.Book']) '{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}]',
exclude_list=['fixtures.Article', 'fixtures.Book']
)
# Excluding sites and fixtures.Article/Book should only leave fixtures.Category # Excluding sites and fixtures.Article/Book should only leave fixtures.Category
self._dumpdata_assert( self._dumpdata_assert(
['sites', 'fixtures'], ['sites', 'fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]', '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
exclude_list=['fixtures.Article', 'fixtures.Book', 'sites']) '"News Stories"}}]',
exclude_list=['fixtures.Article', 'fixtures.Book', 'sites']
)
# Excluding a bogus app should throw an error # Excluding a bogus app should throw an error
with six.assertRaisesRegex(self, management.CommandError, with six.assertRaisesRegex(self, management.CommandError,
@ -239,23 +384,34 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
self.assertQuerysetEqual(Spy.objects.all(), self.assertQuerysetEqual(Spy.objects.all(),
['<Spy: Paul>']) ['<Spy: Paul>'])
# Use the default manager # Use the default manager
self._dumpdata_assert(['fixtures.Spy'], '[{"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": false}}]' % spy1.pk) self._dumpdata_assert(
['fixtures.Spy'],
'[{"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": false}}]' % spy1.pk
)
# Dump using Django's base manager. Should return all objects, # Dump using Django's base manager. Should return all objects,
# even those normally filtered by the manager # even those normally filtered by the manager
self._dumpdata_assert(['fixtures.Spy'], '[{"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": true}}, {"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": false}}]' % (spy2.pk, spy1.pk), use_base_manager=True) self._dumpdata_assert(
['fixtures.Spy'],
'[{"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": true}}, {"pk": %d, "model": '
'"fixtures.spy", "fields": {"cover_blown": false}}]' % (spy2.pk, spy1.pk),
use_base_manager=True
)
def test_dumpdata_with_pks(self): def test_dumpdata_with_pks(self):
management.call_command('loaddata', 'fixture1.json', verbosity=0) management.call_command('loaddata', 'fixture1.json', verbosity=0)
management.call_command('loaddata', 'fixture2.json', verbosity=0) management.call_command('loaddata', 'fixture2.json', verbosity=0)
self._dumpdata_assert( self._dumpdata_assert(
['fixtures.Article'], ['fixtures.Article'],
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]', '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": '
'"Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]',
primary_keys='2,3' primary_keys='2,3'
) )
self._dumpdata_assert( self._dumpdata_assert(
['fixtures.Article'], ['fixtures.Article'],
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}]', '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}]',
primary_keys='2' primary_keys='2'
) )
@ -263,7 +419,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
"You can only use --pks option with one model"): "You can only use --pks option with one model"):
self._dumpdata_assert( self._dumpdata_assert(
['fixtures'], ['fixtures'],
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]', '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]',
primary_keys='2,3' primary_keys='2,3'
) )
@ -271,7 +429,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
"You can only use --pks option with one model"): "You can only use --pks option with one model"):
self._dumpdata_assert( self._dumpdata_assert(
'', '',
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]', '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]',
primary_keys='2,3' primary_keys='2,3'
) )
@ -279,14 +439,22 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
"You can only use --pks option with one model"): "You can only use --pks option with one model"):
self._dumpdata_assert( self._dumpdata_assert(
['fixtures.Article', 'fixtures.category'], ['fixtures.Article', 'fixtures.category'],
'[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]', '[{"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
'"pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}]',
primary_keys='2,3' primary_keys='2,3'
) )
def test_dumpdata_with_file_output(self): def test_dumpdata_with_file_output(self):
management.call_command('loaddata', 'fixture1.json', verbosity=0) management.call_command('loaddata', 'fixture1.json', verbosity=0)
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]', self._dumpdata_assert(
filename='dumpdata.json') ['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]',
filename='dumpdata.json'
)
def test_dumpdata_progressbar(self): def test_dumpdata_progressbar(self):
""" """
@ -414,11 +582,42 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
], ordered=False) ], ordered=False)
# Dump the current contents of the database as a JSON fixture # Dump the current contents of the database as a JSON fixture
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "law", "tagged_id": 3}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}]', natural_foreign_keys=True) self._dumpdata_assert(
['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}, {"pk": 1, "model": '
'"fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": "copyright", "tagged_id": '
'3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": ["fixtures", "article"], "name": '
'"law", "tagged_id": 3}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django '
'Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, '
'{"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}]',
natural_foreign_keys=True
)
# Dump the current contents of the database as an XML fixture # Dump the current contents of the database as an XML fixture
self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> self._dumpdata_assert(
<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker has no place on ESPN</field><field type="DateTimeField" name="pub_date">2006-06-16T12:00:00</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Time to reform copyright</field><field type="DateTimeField" name="pub_date">2006-06-16T13:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">law</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Prince</field></object></django-objects>""", format='xml', natural_foreign_keys=True) ['fixtures'],
'<?xml version="1.0" encoding="utf-8"?><django-objects version="1.0"><object pk="1" '
'model="fixtures.category"><field type="CharField" name="title">News Stories</field><field '
'type="TextField" name="description">Latest news stories</field></object><object pk="2" '
'model="fixtures.article"><field type="CharField" name="headline">Poker has no place on ESPN</field>'
'<field type="DateTimeField" name="pub_date">2006-06-16T12:00:00</field></object><object pk="3" '
'model="fixtures.article"><field type="CharField" name="headline">Time to reform copyright</field>'
'<field type="DateTimeField" name="pub_date">2006-06-16T13:00:00</field></object><object pk="1" '
'model="fixtures.tag"><field type="CharField" name="name">copyright</field><field '
'to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural>'
'<natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field>'
'</object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">law</field><field '
'to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><natural>fixtures</natural>'
'<natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field>'
'</object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt'
'</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane '
'Grappelli</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">'
'Prince</field></object></django-objects>',
format='xml', natural_foreign_keys=True
)
class NonExistentFixtureTests(TestCase): class NonExistentFixtureTests(TestCase):
@ -476,7 +675,13 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
]) ])
# Dump the current contents of the database as a JSON fixture # Dump the current contents of the database as a JSON fixture
self._dumpdata_assert(['fixtures'], '[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]') self._dumpdata_assert(
['fixtures'],
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
'"News Stories"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place '
'on ESPN", "pub_date": "2006-06-16T12:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": '
'{"headline": "Time to reform copyright", "pub_date": "2006-06-16T13:00:00"}}]'
)
# Load fixture 4 (compressed), using format discovery # Load fixture 4 (compressed), using format discovery
management.call_command('loaddata', 'fixture4', verbosity=0) management.call_command('loaddata', 'fixture4', verbosity=0)

View File

@ -239,7 +239,10 @@ class TestFixtures(TestCase):
) )
warning = warning_list.pop() warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning) self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)") self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_invalid_data_no_ext(self): def test_invalid_data_no_ext(self):
""" """
@ -256,7 +259,10 @@ class TestFixtures(TestCase):
) )
warning = warning_list.pop() warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning) self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)") self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_empty(self): def test_empty(self):
""" """
@ -272,7 +278,8 @@ class TestFixtures(TestCase):
) )
warning = warning_list.pop() warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning) self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)") self.assertEqual(str(warning.message),
"No fixture data found for 'empty'. (File format may be invalid.)")
def test_error_message(self): def test_error_message(self):
""" """
@ -289,7 +296,10 @@ class TestFixtures(TestCase):
) )
warning = warning_list.pop() warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning) self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(str(warning.message), "No fixture data found for 'bad_fixture2'. (File format may be invalid.)") self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_pg_sequence_resetting_checks(self): def test_pg_sequence_resetting_checks(self):
""" """
@ -394,9 +404,18 @@ class TestFixtures(TestCase):
data = re.sub('0{6,}[0-9]', '', data) data = re.sub('0{6,}[0-9]', '', data)
animals_data = sorted([ animals_data = sorted([
{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {
{"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}, "pk": 1, "model": "fixtures_regress.animal",
{"pk": animal.pk, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}
},
{
"pk": 10, "model": "fixtures_regress.animal",
"fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}
},
{
"pk": animal.pk, "model": "fixtures_regress.animal",
"fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}
},
], key=lambda x: x["pk"]) ], key=lambda x: x["pk"])
data = sorted(json.loads(data), key=lambda x: x["pk"]) data = sorted(json.loads(data), key=lambda x: x["pk"])
@ -636,7 +655,13 @@ class NaturalKeyFixtureTests(TestCase):
) )
self.assertJSONEqual( self.assertJSONEqual(
out.getvalue(), out.getvalue(),
"""[{"fields": {"main": null, "name": "Amazon"}, "model": "fixtures_regress.store"}, {"fields": {"main": null, "name": "Borders"}, "model": "fixtures_regress.store"}, {"fields": {"name": "Neal Stephenson"}, "model": "fixtures_regress.person"}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]""" """
[{"fields": {"main": null, "name": "Amazon"}, "model": "fixtures_regress.store"},
{"fields": {"main": null, "name": "Borders"}, "model": "fixtures_regress.store"},
{"fields": {"name": "Neal Stephenson"}, "model": "fixtures_regress.person"},
{"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]],
"name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]
"""
) )
def test_dependency_sorting(self): def test_dependency_sorting(self):
@ -711,7 +736,8 @@ class NaturalKeyFixtureTests(TestCase):
def test_dependency_sorting_tight_circular(self): def test_dependency_sorting_tight_circular(self):
self.assertRaisesMessage( self.assertRaisesMessage(
RuntimeError, RuntimeError,
"""Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2 in serialized app list.""", "Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2 in serialized app list.",
serializers.sort_dependencies, serializers.sort_dependencies,
[('fixtures_regress', [Person, Circle2, Circle1, Store, Book])], [('fixtures_regress', [Person, Circle2, Circle1, Store, Book])],
) )
@ -719,7 +745,8 @@ class NaturalKeyFixtureTests(TestCase):
def test_dependency_sorting_tight_circular_2(self): def test_dependency_sorting_tight_circular_2(self):
self.assertRaisesMessage( self.assertRaisesMessage(
RuntimeError, RuntimeError,
"""Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2 in serialized app list.""", "Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2 in serialized app list.",
serializers.sort_dependencies, serializers.sort_dependencies,
[('fixtures_regress', [Circle1, Book, Circle2])], [('fixtures_regress', [Circle1, Book, Circle2])],
) )
@ -727,7 +754,8 @@ class NaturalKeyFixtureTests(TestCase):
def test_dependency_self_referential(self): def test_dependency_self_referential(self):
self.assertRaisesMessage( self.assertRaisesMessage(
RuntimeError, RuntimeError,
"""Can't resolve dependencies for fixtures_regress.Circle3 in serialized app list.""", "Can't resolve dependencies for fixtures_regress.Circle3 in "
"serialized app list.",
serializers.sort_dependencies, serializers.sort_dependencies,
[('fixtures_regress', [Book, Circle3])], [('fixtures_regress', [Book, Circle3])],
) )
@ -735,7 +763,9 @@ class NaturalKeyFixtureTests(TestCase):
def test_dependency_sorting_long(self): def test_dependency_sorting_long(self):
self.assertRaisesMessage( self.assertRaisesMessage(
RuntimeError, RuntimeError,
"""Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2, fixtures_regress.Circle3 in serialized app list.""", "Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2, fixtures_regress.Circle3 in serialized "
"app list.",
serializers.sort_dependencies, serializers.sort_dependencies,
[('fixtures_regress', [Person, Circle2, Circle1, Circle3, Store, Book])], [('fixtures_regress', [Person, Circle2, Circle1, Circle3, Store, Book])],
) )
@ -772,7 +802,9 @@ class NaturalKeyFixtureTests(TestCase):
books = Book.objects.all() books = Book.objects.all()
self.assertEqual( self.assertEqual(
books.__repr__(), books.__repr__(),
"""[<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>, <Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>, <Book: Permutation City by Greg Egan (available at Angus and Robertson)>]""" "[<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>, "
"<Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>, "
"<Book: Permutation City by Greg Egan (available at Angus and Robertson)>]"
) )

View File

@ -157,7 +157,11 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin):
f = URLField(error_messages=e, max_length=17) f = URLField(error_messages=e, max_length=17)
self.assertFormErrors(['REQUIRED'], f.clean, '') self.assertFormErrors(['REQUIRED'], f.clean, '')
self.assertFormErrors(['INVALID'], f.clean, 'abc.c') self.assertFormErrors(['INVALID'], f.clean, 'abc.c')
self.assertFormErrors(['"http://djangoproject.com" has more than 17 characters.'], f.clean, 'djangoproject.com') self.assertFormErrors(
['"http://djangoproject.com" has more than 17 characters.'],
f.clean,
'djangoproject.com'
)
def test_booleanfield(self): def test_booleanfield(self):
e = { e = {
@ -226,8 +230,14 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin):
# This form should print errors the default way. # This form should print errors the default way.
form1 = TestForm({'first_name': 'John'}) form1 = TestForm({'first_name': 'John'})
self.assertHTMLEqual(str(form1['last_name'].errors), '<ul class="errorlist"><li>This field is required.</li></ul>') self.assertHTMLEqual(
self.assertHTMLEqual(str(form1.errors['__all__']), '<ul class="errorlist nonfield"><li>I like to be awkward.</li></ul>') str(form1['last_name'].errors),
'<ul class="errorlist"><li>This field is required.</li></ul>'
)
self.assertHTMLEqual(
str(form1.errors['__all__']),
'<ul class="errorlist nonfield"><li>I like to be awkward.</li></ul>'
)
# This one should wrap error groups in the customized way. # This one should wrap error groups in the customized way.
form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList) form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList)

View File

@ -117,14 +117,18 @@ class FieldsTests(SimpleTestCase):
f = CharField(max_length=10, required=False) f = CharField(max_length=10, required=False)
self.assertEqual('12345', f.clean('12345')) self.assertEqual('12345', f.clean('12345'))
self.assertEqual('1234567890', f.clean('1234567890')) self.assertEqual('1234567890', f.clean('1234567890'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 10 characters (it has 11).'", f.clean, '1234567890a') msg = "'Ensure this value has at most 10 characters (it has 11).'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean('1234567890a')
self.assertEqual(f.max_length, 10) self.assertEqual(f.max_length, 10)
self.assertEqual(f.min_length, None) self.assertEqual(f.min_length, None)
def test_charfield_4(self): def test_charfield_4(self):
f = CharField(min_length=10, required=False) f = CharField(min_length=10, required=False)
self.assertEqual('', f.clean('')) self.assertEqual('', f.clean(''))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 5).'", f.clean, '12345') msg = "'Ensure this value has at least 10 characters (it has 5).'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean('12345')
self.assertEqual('1234567890', f.clean('1234567890')) self.assertEqual('1234567890', f.clean('1234567890'))
self.assertEqual('1234567890a', f.clean('1234567890a')) self.assertEqual('1234567890a', f.clean('1234567890a'))
self.assertEqual(f.max_length, None) self.assertEqual(f.max_length, None)
@ -133,7 +137,9 @@ class FieldsTests(SimpleTestCase):
def test_charfield_5(self): def test_charfield_5(self):
f = CharField(min_length=10, required=True) f = CharField(min_length=10, required=True)
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 5).'", f.clean, '12345') msg = "'Ensure this value has at least 10 characters (it has 5).'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean('12345')
self.assertEqual('1234567890', f.clean('1234567890')) self.assertEqual('1234567890', f.clean('1234567890'))
self.assertEqual('1234567890a', f.clean('1234567890a')) self.assertEqual('1234567890a', f.clean('1234567890a'))
self.assertEqual(f.max_length, None) self.assertEqual(f.max_length, None)
@ -327,7 +333,10 @@ class FieldsTests(SimpleTestCase):
f = FloatField(max_value=1.5, min_value=0.5) f = FloatField(max_value=1.5, min_value=0.5)
self.assertWidgetRendersTo(f, '<input step="any" name="f" min="0.5" max="1.5" type="number" id="id_f" />') self.assertWidgetRendersTo(f, '<input step="any" name="f" min="0.5" max="1.5" type="number" id="id_f" />')
self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6') self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6')
self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4') self.assertRaisesMessage(
ValidationError, "'Ensure this value is greater than or equal to 0.5.'",
f.clean, '0.4'
)
self.assertEqual(1.5, f.clean('1.5')) self.assertEqual(1.5, f.clean('1.5'))
self.assertEqual(0.5, f.clean('0.5')) self.assertEqual(0.5, f.clean('0.5'))
self.assertEqual(f.max_value, 1.5) self.assertEqual(f.max_value, 1.5)
@ -377,16 +386,34 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.clean(' 1.0'), Decimal("1.0")) self.assertEqual(f.clean(' 1.0'), Decimal("1.0"))
self.assertEqual(f.clean(' 1.0 '), Decimal("1.0")) self.assertEqual(f.clean(' 1.0 '), Decimal("1.0"))
self.assertRaisesMessage(ValidationError, "'Enter a number.'", f.clean, '1.0a') self.assertRaisesMessage(ValidationError, "'Enter a number.'", f.clean, '1.0a')
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'", f.clean, '123.45') self.assertRaisesMessage(
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'", f.clean, '1.234') ValidationError, "'Ensure that there are no more than 4 digits in total.'",
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 digits before the decimal point.'", f.clean, '123.4') f.clean, '123.45'
)
self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 2 decimal places.'",
f.clean, '1.234'
)
self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 2 digits before the decimal point.'",
f.clean, '123.4'
)
self.assertEqual(f.clean('-12.34'), Decimal("-12.34")) self.assertEqual(f.clean('-12.34'), Decimal("-12.34"))
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'", f.clean, '-123.45') self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 4 digits in total.'",
f.clean, '-123.45'
)
self.assertEqual(f.clean('-.12'), Decimal("-0.12")) self.assertEqual(f.clean('-.12'), Decimal("-0.12"))
self.assertEqual(f.clean('-00.12'), Decimal("-0.12")) self.assertEqual(f.clean('-00.12'), Decimal("-0.12"))
self.assertEqual(f.clean('-000.12'), Decimal("-0.12")) self.assertEqual(f.clean('-000.12'), Decimal("-0.12"))
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'", f.clean, '-000.123') self.assertRaisesMessage(
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'", f.clean, '-000.12345') ValidationError, "'Ensure that there are no more than 2 decimal places.'",
f.clean, '-000.123'
)
self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 4 digits in total.'",
f.clean, '-000.12345'
)
self.assertRaisesMessage(ValidationError, "'Enter a number.'", f.clean, '--0.12') self.assertRaisesMessage(ValidationError, "'Enter a number.'", f.clean, '--0.12')
self.assertEqual(f.max_digits, 4) self.assertEqual(f.max_digits, 4)
self.assertEqual(f.decimal_places, 2) self.assertEqual(f.decimal_places, 2)
@ -407,7 +434,10 @@ class FieldsTests(SimpleTestCase):
f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5')) f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5'))
self.assertWidgetRendersTo(f, '<input step="0.01" name="f" min="0.5" max="1.5" type="number" id="id_f" />') self.assertWidgetRendersTo(f, '<input step="0.01" name="f" min="0.5" max="1.5" type="number" id="id_f" />')
self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6') self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6')
self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4') self.assertRaisesMessage(
ValidationError, "'Ensure this value is greater than or equal to 0.5.'",
f.clean, '0.4'
)
self.assertEqual(f.clean('1.5'), Decimal("1.5")) self.assertEqual(f.clean('1.5'), Decimal("1.5"))
self.assertEqual(f.clean('0.5'), Decimal("0.5")) self.assertEqual(f.clean('0.5'), Decimal("0.5"))
self.assertEqual(f.clean('.5'), Decimal("0.5")) self.assertEqual(f.clean('.5'), Decimal("0.5"))
@ -419,7 +449,10 @@ class FieldsTests(SimpleTestCase):
def test_decimalfield_4(self): def test_decimalfield_4(self):
f = DecimalField(decimal_places=2) f = DecimalField(decimal_places=2)
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'", f.clean, '0.00000001') self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 2 decimal places.'",
f.clean, '0.00000001'
)
def test_decimalfield_5(self): def test_decimalfield_5(self):
f = DecimalField(max_digits=3) f = DecimalField(max_digits=3)
@ -429,13 +462,19 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.clean('0000000.100'), Decimal("0.100")) self.assertEqual(f.clean('0000000.100'), Decimal("0.100"))
# Only leading whole zeros "collapse" to one digit. # Only leading whole zeros "collapse" to one digit.
self.assertEqual(f.clean('000000.02'), Decimal('0.02')) self.assertEqual(f.clean('000000.02'), Decimal('0.02'))
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 3 digits in total.'", f.clean, '000000.0002') self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 3 digits in total.'",
f.clean, '000000.0002'
)
self.assertEqual(f.clean('.002'), Decimal("0.002")) self.assertEqual(f.clean('.002'), Decimal("0.002"))
def test_decimalfield_6(self): def test_decimalfield_6(self):
f = DecimalField(max_digits=2, decimal_places=2) f = DecimalField(max_digits=2, decimal_places=2)
self.assertEqual(f.clean('.01'), Decimal(".01")) self.assertEqual(f.clean('.01'), Decimal(".01"))
self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 0 digits before the decimal point.'", f.clean, '1.1') self.assertRaisesMessage(
ValidationError, "'Ensure that there are no more than 0 digits before the decimal point.'",
f.clean, '1.1'
)
def test_decimalfield_scientific(self): def test_decimalfield_scientific(self):
f = DecimalField(max_digits=2, decimal_places=2) f = DecimalField(max_digits=2, decimal_places=2)
@ -588,8 +627,14 @@ class FieldsTests(SimpleTestCase):
f = DateTimeField() f = DateTimeField()
self.assertEqual(datetime.datetime(2006, 10, 25, 0, 0), f.clean(datetime.date(2006, 10, 25))) self.assertEqual(datetime.datetime(2006, 10, 25, 0, 0), f.clean(datetime.date(2006, 10, 25)))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean(datetime.datetime(2006, 10, 25, 14, 30))) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean(datetime.datetime(2006, 10, 25, 14, 30)))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 59), f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))) self.assertEqual(
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 59, 200), f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))) datetime.datetime(2006, 10, 25, 14, 30, 59),
f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
)
self.assertEqual(
datetime.datetime(2006, 10, 25, 14, 30, 59, 200),
f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
)
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45, 200), f.clean('2006-10-25 14:30:45.000200')) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45, 200), f.clean('2006-10-25 14:30:45.000200'))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45, 200), f.clean('2006-10-25 14:30:45.0002')) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45, 200), f.clean('2006-10-25 14:30:45.0002'))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45), f.clean('2006-10-25 14:30:45')) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 45), f.clean('2006-10-25 14:30:45'))
@ -613,8 +658,14 @@ class FieldsTests(SimpleTestCase):
f = DateTimeField(input_formats=['%Y %m %d %I:%M %p']) f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
self.assertEqual(datetime.datetime(2006, 10, 25, 0, 0), f.clean(datetime.date(2006, 10, 25))) self.assertEqual(datetime.datetime(2006, 10, 25, 0, 0), f.clean(datetime.date(2006, 10, 25)))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean(datetime.datetime(2006, 10, 25, 14, 30))) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean(datetime.datetime(2006, 10, 25, 14, 30)))
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 59), f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))) self.assertEqual(
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30, 59, 200), f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))) datetime.datetime(2006, 10, 25, 14, 30, 59),
f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
)
self.assertEqual(
datetime.datetime(2006, 10, 25, 14, 30, 59, 200),
f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
)
self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean('2006 10 25 2:30 PM')) self.assertEqual(datetime.datetime(2006, 10, 25, 14, 30), f.clean('2006 10 25 2:30 PM'))
self.assertRaisesMessage(ValidationError, "'Enter a valid date/time.'", f.clean, '2006-10-25 14:30:45') self.assertRaisesMessage(ValidationError, "'Enter a valid date/time.'", f.clean, '2006-10-25 14:30:45')
@ -717,11 +768,22 @@ class FieldsTests(SimpleTestCase):
def test_regexfield_5(self): def test_regexfield_5(self):
f = RegexField('^[0-9]+$', min_length=5, max_length=10) f = RegexField('^[0-9]+$', min_length=5, max_length=10)
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 5 characters (it has 3).'", f.clean, '123') self.assertRaisesMessage(
six.assertRaisesRegex(self, ValidationError, "'Ensure this value has at least 5 characters \(it has 3\)\.', u?'Enter a valid value\.'", f.clean, 'abc') ValidationError, "'Ensure this value has at least 5 characters (it has 3).'",
f.clean, '123'
)
six.assertRaisesRegex(
self, ValidationError,
"'Ensure this value has at least 5 characters \(it has 3\)\.',"
" u?'Enter a valid value\.'",
f.clean, 'abc'
)
self.assertEqual('12345', f.clean('12345')) self.assertEqual('12345', f.clean('12345'))
self.assertEqual('1234567890', f.clean('1234567890')) self.assertEqual('1234567890', f.clean('1234567890'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 10 characters (it has 11).'", f.clean, '12345678901') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at most 10 characters (it has 11).'",
f.clean, '12345678901'
)
self.assertRaisesMessage(ValidationError, "'Enter a valid value.'", f.clean, '12345a') self.assertRaisesMessage(ValidationError, "'Enter a valid value.'", f.clean, '12345a')
def test_regexfield_6(self): def test_regexfield_6(self):
@ -769,9 +831,15 @@ class FieldsTests(SimpleTestCase):
def test_emailfield_min_max_length(self): def test_emailfield_min_max_length(self):
f = EmailField(min_length=10, max_length=15) f = EmailField(min_length=10, max_length=15)
self.assertWidgetRendersTo(f, '<input id="id_f" type="email" name="f" maxlength="15" />') self.assertWidgetRendersTo(f, '<input id="id_f" type="email" name="f" maxlength="15" />')
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 9).'", f.clean, 'a@foo.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at least 10 characters (it has 9).'",
f.clean, 'a@foo.com'
)
self.assertEqual('alf@foo.com', f.clean('alf@foo.com')) self.assertEqual('alf@foo.com', f.clean('alf@foo.com'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 15 characters (it has 20).'", f.clean, 'alf123456788@foo.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at most 15 characters (it has 20).'",
f.clean, 'alf123456788@foo.com'
)
# FileField ################################################################## # FileField ##################################################################
@ -783,19 +851,43 @@ class FieldsTests(SimpleTestCase):
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None, '') self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None, '')
self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf')) self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf'))
self.assertRaisesMessage(ValidationError, "'No file was submitted. Check the encoding type on the form.'", f.clean, SimpleUploadedFile('', b'')) self.assertRaisesMessage(
self.assertRaisesMessage(ValidationError, "'No file was submitted. Check the encoding type on the form.'", f.clean, SimpleUploadedFile('', b''), '') ValidationError, "'No file was submitted. Check the encoding type on the form.'",
f.clean, SimpleUploadedFile('', b'')
)
self.assertRaisesMessage(
ValidationError, "'No file was submitted. Check the encoding type on the form.'",
f.clean, SimpleUploadedFile('', b''), ''
)
self.assertEqual('files/test3.pdf', f.clean(None, 'files/test3.pdf')) self.assertEqual('files/test3.pdf', f.clean(None, 'files/test3.pdf'))
self.assertRaisesMessage(ValidationError, "'No file was submitted. Check the encoding type on the form.'", f.clean, 'some content that is not a file') self.assertRaisesMessage(
self.assertRaisesMessage(ValidationError, "'The submitted file is empty.'", f.clean, SimpleUploadedFile('name', None)) ValidationError, "'No file was submitted. Check the encoding type on the form.'",
self.assertRaisesMessage(ValidationError, "'The submitted file is empty.'", f.clean, SimpleUploadedFile('name', b'')) f.clean, 'some content that is not a file'
)
self.assertRaisesMessage(
ValidationError, "'The submitted file is empty.'",
f.clean, SimpleUploadedFile('name', None)
)
self.assertRaisesMessage(
ValidationError, "'The submitted file is empty.'",
f.clean, SimpleUploadedFile('name', b'')
)
self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content')))) self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content'))))
self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode('utf-8'))))) self.assertIsInstance(
self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content'), 'files/test4.pdf'))) f.clean(SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode('utf-8'))),
SimpleUploadedFile
)
self.assertIsInstance(
f.clean(SimpleUploadedFile('name', b'Some File Content'), 'files/test4.pdf'),
SimpleUploadedFile
)
def test_filefield_2(self): def test_filefield_2(self):
f = FileField(max_length=5) f = FileField(max_length=5)
self.assertRaisesMessage(ValidationError, "'Ensure this filename has at most 5 characters (it has 18).'", f.clean, SimpleUploadedFile('test_maxlength.txt', b'hello world')) self.assertRaisesMessage(
ValidationError, "'Ensure this filename has at most 5 characters (it has 18).'",
f.clean, SimpleUploadedFile('test_maxlength.txt', b'hello world')
)
self.assertEqual('files/test1.pdf', f.clean('', 'files/test1.pdf')) self.assertEqual('files/test1.pdf', f.clean('', 'files/test1.pdf'))
self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf')) self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf'))
self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content')))) self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content'))))
@ -897,8 +989,14 @@ class FieldsTests(SimpleTestCase):
self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://inv-.alid-.com') self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://inv-.alid-.com')
self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://inv-.-alid.com') self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://inv-.-alid.com')
self.assertEqual('http://valid-----hyphens.com', f.clean('http://valid-----hyphens.com')) self.assertEqual('http://valid-----hyphens.com', f.clean('http://valid-----hyphens.com'))
self.assertEqual('http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah', f.clean('http://some.idn.xyzäöüßabc.domain.com:123/blah')) self.assertEqual(
self.assertEqual('http://www.example.com/s/http://code.djangoproject.com/ticket/13804', f.clean('www.example.com/s/http://code.djangoproject.com/ticket/13804')) 'http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah',
f.clean('http://some.idn.xyzäöüßabc.domain.com:123/blah')
)
self.assertEqual(
'http://www.example.com/s/http://code.djangoproject.com/ticket/13804',
f.clean('www.example.com/s/http://code.djangoproject.com/ticket/13804')
)
self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, '[a') self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, '[a')
self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://[a') self.assertRaisesMessage(ValidationError, "'Enter a valid URL.'", f.clean, 'http://[a')
@ -926,9 +1024,15 @@ class FieldsTests(SimpleTestCase):
def test_urlfield_5(self): def test_urlfield_5(self):
f = URLField(min_length=15, max_length=20) f = URLField(min_length=15, max_length=20)
self.assertWidgetRendersTo(f, '<input id="id_f" type="url" name="f" maxlength="20" />') self.assertWidgetRendersTo(f, '<input id="id_f" type="url" name="f" maxlength="20" />')
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 15 characters (it has 12).'", f.clean, 'http://f.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at least 15 characters (it has 12).'",
f.clean, 'http://f.com'
)
self.assertEqual('http://example.com', f.clean('http://example.com')) self.assertEqual('http://example.com', f.clean('http://example.com'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 37).'", f.clean, 'http://abcdefghijklmnopqrstuvwxyz.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at most 20 characters (it has 37).'",
f.clean, 'http://abcdefghijklmnopqrstuvwxyz.com'
)
def test_urlfield_6(self): def test_urlfield_6(self):
f = URLField(required=False) f = URLField(required=False)
@ -1033,7 +1137,10 @@ class FieldsTests(SimpleTestCase):
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
self.assertEqual('1', f.clean(1)) self.assertEqual('1', f.clean(1))
self.assertEqual('1', f.clean('1')) self.assertEqual('1', f.clean('1'))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 3 is not one of the available choices.'", f.clean, '3') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
f.clean, '3'
)
def test_choicefield_2(self): def test_choicefield_2(self):
f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False) f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False)
@ -1041,22 +1148,36 @@ class FieldsTests(SimpleTestCase):
self.assertEqual('', f.clean(None)) self.assertEqual('', f.clean(None))
self.assertEqual('1', f.clean(1)) self.assertEqual('1', f.clean(1))
self.assertEqual('1', f.clean('1')) self.assertEqual('1', f.clean('1'))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 3 is not one of the available choices.'", f.clean, '3') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
f.clean, '3'
)
def test_choicefield_3(self): def test_choicefield_3(self):
f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')]) f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')])
self.assertEqual('J', f.clean('J')) self.assertEqual('J', f.clean('J'))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. John is not one of the available choices.'", f.clean, 'John') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. John is not one of the available choices.'",
f.clean, 'John'
)
def test_choicefield_4(self): def test_choicefield_4(self):
f = ChoiceField(choices=[('Numbers', (('1', 'One'), ('2', 'Two'))), ('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other')]) f = ChoiceField(
choices=[
('Numbers', (('1', 'One'), ('2', 'Two'))),
('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other'),
]
)
self.assertEqual('1', f.clean(1)) self.assertEqual('1', f.clean(1))
self.assertEqual('1', f.clean('1')) self.assertEqual('1', f.clean('1'))
self.assertEqual('3', f.clean(3)) self.assertEqual('3', f.clean(3))
self.assertEqual('3', f.clean('3')) self.assertEqual('3', f.clean('3'))
self.assertEqual('5', f.clean(5)) self.assertEqual('5', f.clean(5))
self.assertEqual('5', f.clean('5')) self.assertEqual('5', f.clean('5'))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 6 is not one of the available choices.'", f.clean, '6') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 6 is not one of the available choices.'",
f.clean, '6'
)
def test_choicefield_callable(self): def test_choicefield_callable(self):
choices = lambda: [('J', 'John'), ('P', 'Paul')] choices = lambda: [('J', 'John'), ('P', 'Paul')]
@ -1093,7 +1214,10 @@ class FieldsTests(SimpleTestCase):
def test_typedchoicefield_1(self): def test_typedchoicefield_1(self):
f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
self.assertEqual(1, f.clean('1')) self.assertEqual(1, f.clean('1'))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 2 is not one of the available choices.'", f.clean, '2') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 2 is not one of the available choices.'",
f.clean, '2'
)
def test_typedchoicefield_2(self): def test_typedchoicefield_2(self):
# Different coercion, same validation. # Different coercion, same validation.
@ -1109,7 +1233,10 @@ class FieldsTests(SimpleTestCase):
# Even more weirdness: if you have a valid choice but your coercion function # Even more weirdness: if you have a valid choice but your coercion function
# can't coerce, you'll still get a validation error. Don't do this! # can't coerce, you'll still get a validation error. Don't do this!
f = TypedChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int) f = TypedChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int)
self.assertRaisesMessage(ValidationError, "'Select a valid choice. B is not one of the available choices.'", f.clean, 'B') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. B is not one of the available choices.'",
f.clean, 'B'
)
# Required fields require values # Required fields require values
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
@ -1140,11 +1267,14 @@ class FieldsTests(SimpleTestCase):
f = TypedChoiceField(choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True) f = TypedChoiceField(choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True)
self.assertEqual(Decimal('1.2'), f.clean('2')) self.assertEqual(Decimal('1.2'), f.clean('2'))
self.assertRaisesMessage(ValidationError, self.assertRaisesMessage(
"'This field is required.'", f.clean, '') ValidationError, "'This field is required.'",
self.assertRaisesMessage(ValidationError, f.clean, ''
"'Select a valid choice. 3 is not one of the available choices.'", )
f.clean, '3') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
f.clean, '3'
)
# NullBooleanField ############################################################ # NullBooleanField ############################################################
@ -1168,7 +1298,11 @@ class FieldsTests(SimpleTestCase):
hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True) hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True)
hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False) hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False)
f = HiddenNullBooleanForm() f = HiddenNullBooleanForm()
self.assertHTMLEqual('<input type="hidden" name="hidden_nullbool1" value="True" id="id_hidden_nullbool1" /><input type="hidden" name="hidden_nullbool2" value="False" id="id_hidden_nullbool2" />', str(f)) self.assertHTMLEqual(
'<input type="hidden" name="hidden_nullbool1" value="True" id="id_hidden_nullbool1" />'
'<input type="hidden" name="hidden_nullbool2" value="False" id="id_hidden_nullbool2" />',
str(f)
)
def test_nullbooleanfield_3(self): def test_nullbooleanfield_3(self):
class HiddenNullBooleanForm(Form): class HiddenNullBooleanForm(Form):
@ -1218,7 +1352,10 @@ class FieldsTests(SimpleTestCase):
self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello') self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello')
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, []) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ()) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, ())
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 3 is not one of the available choices.'", f.clean, ['3']) self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
f.clean, ['3']
)
def test_multiplechoicefield_2(self): def test_multiplechoicefield_2(self):
f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False) f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False)
@ -1232,18 +1369,29 @@ class FieldsTests(SimpleTestCase):
self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello') self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello')
self.assertEqual([], f.clean([])) self.assertEqual([], f.clean([]))
self.assertEqual([], f.clean(())) self.assertEqual([], f.clean(()))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 3 is not one of the available choices.'", f.clean, ['3']) self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
f.clean, ['3']
)
def test_multiplechoicefield_3(self): def test_multiplechoicefield_3(self):
f = MultipleChoiceField(choices=[('Numbers', (('1', 'One'), ('2', 'Two'))), ('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other')]) f = MultipleChoiceField(
choices=[('Numbers', (('1', 'One'), ('2', 'Two'))), ('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other')]
)
self.assertEqual(['1'], f.clean([1])) self.assertEqual(['1'], f.clean([1]))
self.assertEqual(['1'], f.clean(['1'])) self.assertEqual(['1'], f.clean(['1']))
self.assertEqual(['1', '5'], f.clean([1, 5])) self.assertEqual(['1', '5'], f.clean([1, 5]))
self.assertEqual(['1', '5'], f.clean([1, '5'])) self.assertEqual(['1', '5'], f.clean([1, '5']))
self.assertEqual(['1', '5'], f.clean(['1', 5])) self.assertEqual(['1', '5'], f.clean(['1', 5]))
self.assertEqual(['1', '5'], f.clean(['1', '5'])) self.assertEqual(['1', '5'], f.clean(['1', '5']))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 6 is not one of the available choices.'", f.clean, ['6']) self.assertRaisesMessage(
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 6 is not one of the available choices.'", f.clean, ['1', '6']) ValidationError, "'Select a valid choice. 6 is not one of the available choices.'",
f.clean, ['6']
)
self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 6 is not one of the available choices.'",
f.clean, ['1', '6']
)
def test_multiplechoicefield_changed(self): def test_multiplechoicefield_changed(self):
f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two'), ('3', 'Three')]) f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two'), ('3', 'Three')])
@ -1262,7 +1410,10 @@ class FieldsTests(SimpleTestCase):
def test_typedmultiplechoicefield_1(self): def test_typedmultiplechoicefield_1(self):
f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
self.assertEqual([1], f.clean(['1'])) self.assertEqual([1], f.clean(['1']))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 2 is not one of the available choices.'", f.clean, ['2']) self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 2 is not one of the available choices.'",
f.clean, ['2']
)
def test_typedmultiplechoicefield_2(self): def test_typedmultiplechoicefield_2(self):
# Different coercion, same validation. # Different coercion, same validation.
@ -1277,13 +1428,19 @@ class FieldsTests(SimpleTestCase):
def test_typedmultiplechoicefield_4(self): def test_typedmultiplechoicefield_4(self):
f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
self.assertEqual([1, -1], f.clean(['1', '-1'])) self.assertEqual([1, -1], f.clean(['1', '-1']))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. 2 is not one of the available choices.'", f.clean, ['1', '2']) self.assertRaisesMessage(
ValidationError, "'Select a valid choice. 2 is not one of the available choices.'",
f.clean, ['1', '2']
)
def test_typedmultiplechoicefield_5(self): def test_typedmultiplechoicefield_5(self):
# Even more weirdness: if you have a valid choice but your coercion function # Even more weirdness: if you have a valid choice but your coercion function
# can't coerce, you'll still get a validation error. Don't do this! # can't coerce, you'll still get a validation error. Don't do this!
f = TypedMultipleChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int) f = TypedMultipleChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int)
self.assertRaisesMessage(ValidationError, "'Select a valid choice. B is not one of the available choices.'", f.clean, ['B']) self.assertRaisesMessage(
ValidationError, "'Select a valid choice. B is not one of the available choices.'",
f.clean, ['B']
)
# Required fields require values # Required fields require values
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, []) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
@ -1324,7 +1481,10 @@ class FieldsTests(SimpleTestCase):
def test_combofield_1(self): def test_combofield_1(self):
f = ComboField(fields=[CharField(max_length=20), EmailField()]) f = ComboField(fields=[CharField(max_length=20), EmailField()])
self.assertEqual('test@example.com', f.clean('test@example.com')) self.assertEqual('test@example.com', f.clean('test@example.com'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 28).'", f.clean, 'longemailaddress@example.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at most 20 characters (it has 28).'",
f.clean, 'longemailaddress@example.com'
)
self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'", f.clean, 'not an email') self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'", f.clean, 'not an email')
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
@ -1332,7 +1492,10 @@ class FieldsTests(SimpleTestCase):
def test_combofield_2(self): def test_combofield_2(self):
f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False) f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False)
self.assertEqual('test@example.com', f.clean('test@example.com')) self.assertEqual('test@example.com', f.clean('test@example.com'))
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 28).'", f.clean, 'longemailaddress@example.com') self.assertRaisesMessage(
ValidationError, "'Ensure this value has at most 20 characters (it has 28).'",
f.clean, 'longemailaddress@example.com'
)
self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'", f.clean, 'not an email') self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'", f.clean, 'not an email')
self.assertEqual('', f.clean('')) self.assertEqual('', f.clean(''))
self.assertEqual('', f.clean(None)) self.assertEqual('', f.clean(None))
@ -1362,7 +1525,10 @@ class FieldsTests(SimpleTestCase):
for exp, got in zip(expected, fix_os_paths(f.choices)): for exp, got in zip(expected, fix_os_paths(f.choices)):
self.assertEqual(exp[1], got[1]) self.assertEqual(exp[1], got[1])
self.assertTrue(got[0].endswith(exp[0])) self.assertTrue(got[0].endswith(exp[0]))
self.assertRaisesMessage(ValidationError, "'Select a valid choice. fields.py is not one of the available choices.'", f.clean, 'fields.py') self.assertRaisesMessage(
ValidationError, "'Select a valid choice. fields.py is not one of the available choices.'",
f.clean, 'fields.py'
)
assert fix_os_paths(f.clean(path + 'fields.py')).endswith('/django/forms/fields.py') assert fix_os_paths(f.clean(path + 'fields.py')).endswith('/django/forms/fields.py')
def test_filepathfield_3(self): def test_filepathfield_3(self):
@ -1437,24 +1603,36 @@ class FieldsTests(SimpleTestCase):
from django.forms.widgets import SplitDateTimeWidget from django.forms.widgets import SplitDateTimeWidget
f = SplitDateTimeField() f = SplitDateTimeField()
self.assertIsInstance(f.widget, SplitDateTimeWidget) self.assertIsInstance(f.widget, SplitDateTimeWidget)
self.assertEqual(datetime.datetime(2006, 1, 10, 7, 30), f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])) self.assertEqual(
datetime.datetime(2006, 1, 10, 7, 30),
f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
)
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello') self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello')
six.assertRaisesRegex(self, ValidationError, "'Enter a valid date\.', u?'Enter a valid time\.'", f.clean, ['hello', 'there']) six.assertRaisesRegex(
self, ValidationError, "'Enter a valid date\.', u?'Enter a valid time\.'",
f.clean, ['hello', 'there']
)
self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', 'there']) self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', 'there'])
self.assertRaisesMessage(ValidationError, "'Enter a valid date.'", f.clean, ['hello', '07:30']) self.assertRaisesMessage(ValidationError, "'Enter a valid date.'", f.clean, ['hello', '07:30'])
def test_splitdatetimefield_2(self): def test_splitdatetimefield_2(self):
f = SplitDateTimeField(required=False) f = SplitDateTimeField(required=False)
self.assertEqual(datetime.datetime(2006, 1, 10, 7, 30), f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])) self.assertEqual(
datetime.datetime(2006, 1, 10, 7, 30),
f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
)
self.assertEqual(datetime.datetime(2006, 1, 10, 7, 30), f.clean(['2006-01-10', '07:30'])) self.assertEqual(datetime.datetime(2006, 1, 10, 7, 30), f.clean(['2006-01-10', '07:30']))
self.assertIsNone(f.clean(None)) self.assertIsNone(f.clean(None))
self.assertIsNone(f.clean('')) self.assertIsNone(f.clean(''))
self.assertIsNone(f.clean([''])) self.assertIsNone(f.clean(['']))
self.assertIsNone(f.clean(['', ''])) self.assertIsNone(f.clean(['', '']))
self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello') self.assertRaisesMessage(ValidationError, "'Enter a list of values.'", f.clean, 'hello')
six.assertRaisesRegex(self, ValidationError, "'Enter a valid date\.', u?'Enter a valid time\.'", f.clean, ['hello', 'there']) six.assertRaisesRegex(
self, ValidationError, "'Enter a valid date\.', u?'Enter a valid time\.'",
f.clean, ['hello', 'there']
)
self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', 'there']) self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', 'there'])
self.assertRaisesMessage(ValidationError, "'Enter a valid date.'", f.clean, ['hello', '07:30']) self.assertRaisesMessage(ValidationError, "'Enter a valid date.'", f.clean, ['hello', '07:30'])
self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', '']) self.assertRaisesMessage(ValidationError, "'Enter a valid time.'", f.clean, ['2006-01-10', ''])
@ -1489,7 +1667,10 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, 'foo::223:6cff:fe8a:2e8a') self.assertRaisesMessage(
ValidationError, "'This is not a valid IPv6 address.'",
f.clean, 'foo::223:6cff:fe8a:2e8a'
)
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2')
@ -1518,7 +1699,10 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, 'foo::223:6cff:fe8a:2e8a') self.assertRaisesMessage(
ValidationError, "'This is not a valid IPv6 address.'",
f.clean, 'foo::223:6cff:fe8a:2e8a'
)
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2')
@ -1535,7 +1719,10 @@ class FieldsTests(SimpleTestCase):
self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '12345:2:3:4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3::4')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, 'foo::223:6cff:fe8a:2e8a') self.assertRaisesMessage(
ValidationError, "'This is not a valid IPv6 address.'",
f.clean, 'foo::223:6cff:fe8a:2e8a'
)
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1::2:3:4:5:6:7:8')
self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2') self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'", f.clean, '1:2')

File diff suppressed because it is too large Load Diff

View File

@ -101,9 +101,15 @@ class FormsFormsetTestCase(SimpleTestCase):
# for adding data. By default, it displays 1 blank form. It can display more, # for adding data. By default, it displays 1 blank form. It can display more,
# but we'll look at how to do so later. # but we'll look at how to do so later.
formset = self.make_choiceformset() formset = self.make_choiceformset()
self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="1000" /> self.assertHTMLEqual(
str(formset),
"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" />
<input type="hidden" name="choices-INITIAL_FORMS" value="0" />
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0" />
<input type="hidden" name="choices-MAX_NUM_FORMS" value="1000" />
<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr> <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr>
<tr><th>Votes:</th><td><input type="number" name="choices-0-votes" /></td></tr>""") <tr><th>Votes:</th><td><input type="number" name="choices-0-votes" /></td></tr>"""
)
# We treat FormSet pretty much like we would treat a normal Form. FormSet has an # We treat FormSet pretty much like we would treat a normal Form. FormSet has an
# is_valid method, and a cleaned_data or errors attribute depending on whether all # is_valid method, and a cleaned_data or errors attribute depending on whether all
@ -186,10 +192,13 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>
<li>Choice: <input type="text" name="choices-1-choice" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li>
<li>Votes: <input type="number" name="choices-1-votes" /></li>""") <li>Votes: <input type="number" name="choices-1-votes" /></li>"""
)
# Let's simulate what would happen if we submitted this form. # Let's simulate what would happen if we submitted this form.
formset = self.make_choiceformset([('Calexico', '100'), ('', '')], initial_forms=1) formset = self.make_choiceformset([('Calexico', '100'), ('', '')], initial_forms=1)
@ -212,7 +221,10 @@ class FormsFormsetTestCase(SimpleTestCase):
# handle that case later. # handle that case later.
formset = self.make_choiceformset([('', ''), ('', '')], initial_forms=1) formset = self.make_choiceformset([('', ''), ('', '')], initial_forms=1)
self.assertFalse(formset.is_valid()) self.assertFalse(formset.is_valid())
self.assertEqual(formset.errors, [{'votes': ['This field is required.'], 'choice': ['This field is required.']}, {}]) self.assertEqual(
formset.errors,
[{'votes': ['This field is required.'], 'choice': ['This field is required.']}, {}]
)
def test_displaying_more_than_one_blank_form(self): def test_displaying_more_than_one_blank_form(self):
# Displaying more than 1 blank form ########################################### # Displaying more than 1 blank form ###########################################
@ -226,12 +238,15 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" /></li>
<li>Votes: <input type="number" name="choices-0-votes" /></li> <li>Votes: <input type="number" name="choices-0-votes" /></li>
<li>Choice: <input type="text" name="choices-1-choice" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li>
<li>Votes: <input type="number" name="choices-1-votes" /></li> <li>Votes: <input type="number" name="choices-1-votes" /></li>
<li>Choice: <input type="text" name="choices-2-choice" /></li> <li>Choice: <input type="text" name="choices-2-choice" /></li>
<li>Votes: <input type="number" name="choices-2-votes" /></li>""") <li>Votes: <input type="number" name="choices-2-votes" /></li>"""
)
# Since we displayed every form as blank, we will also accept them back as blank. # Since we displayed every form as blank, we will also accept them back as blank.
# This may seem a little strange, but later we will show how to require a minimum # This may seem a little strange, but later we will show how to require a minimum
@ -269,10 +284,13 @@ class FormsFormsetTestCase(SimpleTestCase):
self.assertFalse(formset.forms[0].empty_permitted) self.assertFalse(formset.forms[0].empty_permitted)
self.assertTrue(formset.forms[1].empty_permitted) self.assertTrue(formset.forms[1].empty_permitted)
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" /></li>
<li>Votes: <input type="number" name="choices-0-votes" /></li> <li>Votes: <input type="number" name="choices-0-votes" /></li>
<li>Choice: <input type="text" name="choices-1-choice" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li>
<li>Votes: <input type="number" name="choices-1-votes" /></li>""") <li>Votes: <input type="number" name="choices-1-votes" /></li>"""
)
def test_min_num_displaying_more_than_one_blank_form_with_zero_extra(self): def test_min_num_displaying_more_than_one_blank_form_with_zero_extra(self):
# We can also display more than 1 empty form passing min_num argument # We can also display more than 1 empty form passing min_num argument
@ -284,12 +302,15 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" /></li>
<li>Votes: <input type="number" name="choices-0-votes" /></li> <li>Votes: <input type="number" name="choices-0-votes" /></li>
<li>Choice: <input type="text" name="choices-1-choice" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li>
<li>Votes: <input type="number" name="choices-1-votes" /></li> <li>Votes: <input type="number" name="choices-1-votes" /></li>
<li>Choice: <input type="text" name="choices-2-choice" /></li> <li>Choice: <input type="text" name="choices-2-choice" /></li>
<li>Votes: <input type="number" name="choices-2-votes" /></li>""") <li>Votes: <input type="number" name="choices-2-votes" /></li>"""
)
def test_single_form_completed(self): def test_single_form_completed(self):
# We can just fill out one of the forms. # We can just fill out one of the forms.
@ -388,20 +409,26 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>
<li>Choice: <input type="text" name="choices-1-choice" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li>
<li>Votes: <input type="number" name="choices-1-votes" /></li> <li>Votes: <input type="number" name="choices-1-votes" /></li>
<li>Choice: <input type="text" name="choices-2-choice" /></li> <li>Choice: <input type="text" name="choices-2-choice" /></li>
<li>Votes: <input type="number" name="choices-2-votes" /></li> <li>Votes: <input type="number" name="choices-2-votes" /></li>
<li>Choice: <input type="text" name="choices-3-choice" /></li> <li>Choice: <input type="text" name="choices-3-choice" /></li>
<li>Votes: <input type="number" name="choices-3-votes" /></li>""") <li>Votes: <input type="number" name="choices-3-votes" /></li>"""
)
# Make sure retrieving an empty form works, and it shows up in the form list # Make sure retrieving an empty form works, and it shows up in the form list
self.assertTrue(formset.empty_form.empty_permitted) self.assertTrue(formset.empty_form.empty_permitted)
self.assertHTMLEqual(formset.empty_form.as_ul(), """<li>Choice: <input type="text" name="choices-__prefix__-choice" /></li> self.assertHTMLEqual(
<li>Votes: <input type="number" name="choices-__prefix__-votes" /></li>""") formset.empty_form.as_ul(),
"""<li>Choice: <input type="text" name="choices-__prefix__-choice" /></li>
<li>Votes: <input type="number" name="choices-__prefix__-votes" /></li>"""
)
def test_formset_with_deletion(self): def test_formset_with_deletion(self):
# FormSets with deletion ###################################################### # FormSets with deletion ######################################################
@ -418,7 +445,9 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>
<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> <li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> <li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li>
@ -426,7 +455,8 @@ class FormsFormsetTestCase(SimpleTestCase):
<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li> <li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li>
<li>Choice: <input type="text" name="choices-2-choice" /></li> <li>Choice: <input type="text" name="choices-2-choice" /></li>
<li>Votes: <input type="number" name="choices-2-votes" /></li> <li>Votes: <input type="number" name="choices-2-votes" /></li>
<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>""") <li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>"""
)
# To delete something, we just need to set that form's special delete field to # To delete something, we just need to set that form's special delete field to
# 'on'. Let's go ahead and delete Fergie. # 'on'. Let's go ahead and delete Fergie.
@ -449,8 +479,18 @@ class FormsFormsetTestCase(SimpleTestCase):
formset = ChoiceFormSet(data, auto_id=False, prefix='choices') formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
self.assertTrue(formset.is_valid()) self.assertTrue(formset.is_valid())
self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'DELETE': False, 'choice': 'Calexico'}, {'votes': 900, 'DELETE': True, 'choice': 'Fergie'}, {}]) self.assertEqual(
self.assertEqual([form.cleaned_data for form in formset.deleted_forms], [{'votes': 900, 'DELETE': True, 'choice': 'Fergie'}]) [form.cleaned_data for form in formset.forms],
[
{'votes': 100, 'DELETE': False, 'choice': 'Calexico'},
{'votes': 900, 'DELETE': True, 'choice': 'Fergie'},
{},
]
)
self.assertEqual(
[form.cleaned_data for form in formset.deleted_forms],
[{'votes': 900, 'DELETE': True, 'choice': 'Fergie'}]
)
# If we fill a form with something and then we check the can_delete checkbox for # If we fill a form with something and then we check the can_delete checkbox for
# that form, that form's errors should not make the entire formset invalid since # that form, that form's errors should not make the entire formset invalid since
@ -517,7 +557,9 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>
<li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li> <li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li>
<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> <li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li>
@ -525,7 +567,8 @@ class FormsFormsetTestCase(SimpleTestCase):
<li>Order: <input type="number" name="choices-1-ORDER" value="2" /></li> <li>Order: <input type="number" name="choices-1-ORDER" value="2" /></li>
<li>Choice: <input type="text" name="choices-2-choice" /></li> <li>Choice: <input type="text" name="choices-2-choice" /></li>
<li>Votes: <input type="number" name="choices-2-votes" /></li> <li>Votes: <input type="number" name="choices-2-votes" /></li>
<li>Order: <input type="number" name="choices-2-ORDER" /></li>""") <li>Order: <input type="number" name="choices-2-ORDER" /></li>"""
)
data = { data = {
'choices-TOTAL_FORMS': '3', # the number of forms rendered 'choices-TOTAL_FORMS': '3', # the number of forms rendered
@ -631,7 +674,9 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(form.as_ul()) form_output.append(form.as_ul())
self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> self.assertHTMLEqual(
'\n'.join(form_output),
"""<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>
<li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li> <li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li>
<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> <li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
@ -646,7 +691,8 @@ class FormsFormsetTestCase(SimpleTestCase):
<li>Choice: <input type="text" name="choices-3-choice" /></li> <li>Choice: <input type="text" name="choices-3-choice" /></li>
<li>Votes: <input type="number" name="choices-3-votes" /></li> <li>Votes: <input type="number" name="choices-3-votes" /></li>
<li>Order: <input type="number" name="choices-3-ORDER" /></li> <li>Order: <input type="number" name="choices-3-ORDER" /></li>
<li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li>""") <li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li>"""
)
# Let's delete Fergie, and put The Decemberists ahead of Calexico. # Let's delete Fergie, and put The Decemberists ahead of Calexico.
@ -684,7 +730,10 @@ class FormsFormsetTestCase(SimpleTestCase):
{'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': 'The Decemberists'}, {'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': 'The Decemberists'},
{'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': 'Calexico'}, {'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': 'Calexico'},
]) ])
self.assertEqual([form.cleaned_data for form in formset.deleted_forms], [{'votes': 900, 'DELETE': True, 'ORDER': 2, 'choice': 'Fergie'}]) self.assertEqual(
[form.cleaned_data for form in formset.deleted_forms],
[{'votes': 900, 'DELETE': True, 'ORDER': 2, 'choice': 'Fergie'}]
)
def test_invalid_deleted_form_with_ordering(self): def test_invalid_deleted_form_with_ordering(self):
# Should be able to get ordered forms from a valid formset even if a # Should be able to get ordered forms from a valid formset even if a
@ -761,9 +810,15 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr> '\n'.join(form_output),
<tr><th><label for="id_form-2-name">Name:</label></th><td><input type="text" name="form-2-name" id="id_form-2-name" /></td></tr>""") """<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th>
<td><input type="text" name="form-2-name" id="id_form-2-name" /></td></tr>"""
)
# If max_num is 0 then no form is rendered at all. # If max_num is 0 then no form is rendered at all.
LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0) LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0)
@ -782,8 +837,13 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>""") '\n'.join(form_output),
"""<tr><th><label for="id_form-0-name">Name:</label></th><td>
<input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>"""
)
# Ensure that max_num has no effect when extra is less than max_num. # Ensure that max_num has no effect when extra is less than max_num.
@ -794,7 +854,11 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>""") self.assertHTMLEqual(
'\n'.join(form_output),
"""<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>"""
)
def test_max_num_with_initial_data(self): def test_max_num_with_initial_data(self):
# max_num with initial data # max_num with initial data
@ -813,8 +877,13 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Fernet and Coke" id="id_form-0-name" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>""") '\n'.join(form_output),
"""<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input type="text" name="form-0-name" value="Fernet and Coke" id="id_form-0-name" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>"""
)
def test_max_num_zero(self): def test_max_num_zero(self):
# If max_num is 0 then no form is rendered at all, regardless of extra, # If max_num is 0 then no form is rendered at all, regardless of extra,
@ -842,8 +911,13 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" name="form-0-name" type="text" value="Fernet and Coke" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary" /></td></tr>""") '\n'.join(form_output),
"""<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input id="id_form-0-name" name="form-0-name" type="text" value="Fernet and Coke" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary" /></td></tr>"""
)
def test_more_initial_than_max_num(self): def test_more_initial_than_max_num(self):
# More initial forms than max_num now results in all initial forms # More initial forms than max_num now results in all initial forms
@ -861,9 +935,15 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" name="form-0-name" type="text" value="Gin Tonic" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary" /></td></tr> '\n'.join(form_output),
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" name="form-2-name" type="text" value="Jack and Coke" /></td></tr>""") """<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input id="id_form-0-name" name="form-0-name" type="text" value="Gin Tonic" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th>
<td><input id="id_form-2-name" name="form-2-name" type="text" value="Jack and Coke" /></td></tr>"""
)
# One form from initial and extra=3 with max_num=2 should result in the one # One form from initial and extra=3 with max_num=2 should result in the one
# initial form and one extra. # initial form and one extra.
@ -877,8 +957,13 @@ class FormsFormsetTestCase(SimpleTestCase):
for form in formset.forms: for form in formset.forms:
form_output.append(str(form)) form_output.append(str(form))
self.assertHTMLEqual('\n'.join(form_output), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>""") '\n'.join(form_output),
"""<tr><th><label for="id_form-0-name">Name:</label></th>
<td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th>
<td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>"""
)
def test_regression_6926(self): def test_regression_6926(self):
# Regression test for #6926 ################################################## # Regression test for #6926 ##################################################
@ -1157,21 +1242,39 @@ ChoiceFormSet = formset_factory(Choice)
class FormsetAsFooTests(SimpleTestCase): class FormsetAsFooTests(SimpleTestCase):
def test_as_table(self): def test_as_table(self):
formset = ChoiceFormSet(data, auto_id=False, prefix='choices') formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
self.assertHTMLEqual(formset.as_table(), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> self.assertHTMLEqual(
formset.as_table(),
"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" />
<input type="hidden" name="choices-INITIAL_FORMS" value="0" />
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0" />
<input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" value="Calexico" /></td></tr> <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" value="Calexico" /></td></tr>
<tr><th>Votes:</th><td><input type="number" name="choices-0-votes" value="100" /></td></tr>""") <tr><th>Votes:</th><td><input type="number" name="choices-0-votes" value="100" /></td></tr>"""
)
def test_as_p(self): def test_as_p(self):
formset = ChoiceFormSet(data, auto_id=False, prefix='choices') formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
self.assertHTMLEqual(formset.as_p(), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> self.assertHTMLEqual(
formset.as_p(),
"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" />
<input type="hidden" name="choices-INITIAL_FORMS" value="0" />
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0" />
<input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
<p>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></p> <p>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></p>
<p>Votes: <input type="number" name="choices-0-votes" value="100" /></p>""") <p>Votes: <input type="number" name="choices-0-votes" value="100" /></p>"""
)
def test_as_ul(self): def test_as_ul(self):
formset = ChoiceFormSet(data, auto_id=False, prefix='choices') formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
self.assertHTMLEqual(formset.as_ul(), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> self.assertHTMLEqual(
formset.as_ul(),
"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" />
<input type="hidden" name="choices-INITIAL_FORMS" value="0" />
<input type="hidden" name="choices-MIN_NUM_FORMS" value="0" />
<input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> <li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
<li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>""") <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>"""
)
# Regression test for #11418 ################################################# # Regression test for #11418 #################################################
@ -1241,8 +1344,14 @@ class TestEmptyFormSet(SimpleTestCase):
def test_empty_formset_is_valid(self): def test_empty_formset_is_valid(self):
"""Test that an empty formset still calls clean()""" """Test that an empty formset still calls clean()"""
EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate) EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate)
formset = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '0'}, prefix="form") formset = EmptyFsetWontValidateFormset(
formset2 = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '1', 'form-0-name': 'bah'}, prefix="form") data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '0'},
prefix="form",
)
formset2 = EmptyFsetWontValidateFormset(
data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '1', 'form-0-name': 'bah'},
prefix="form",
)
self.assertFalse(formset.is_valid()) self.assertFalse(formset.is_valid())
self.assertFalse(formset2.is_valid()) self.assertFalse(formset2.is_valid())

View File

@ -14,12 +14,18 @@ class FormsMediaTestCase(SimpleTestCase):
def test_construction(self): def test_construction(self):
# Check construction of media objects # Check construction of media objects
m = Media(css={'all': ('path/to/css1', '/path/to/css2')}, js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')) m = Media(
self.assertEqual(str(m), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> css={'all': ('path/to/css1', '/path/to/css2')},
js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'),
)
self.assertEqual(
str(m),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
class Foo: class Foo:
css = { css = {
@ -28,11 +34,14 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')
m3 = Media(Foo) m3 = Media(Foo)
self.assertEqual(str(m3), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(m3),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# A widget can exist without a media definition # A widget can exist without a media definition
class MyWidget(TextInput): class MyWidget(TextInput):
@ -57,19 +66,27 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')
w1 = MyWidget1() w1 = MyWidget1()
self.assertEqual(str(w1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# Media objects can be interrogated by media type # Media objects can be interrogated by media type
self.assertEqual(str(w1.media['css']), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media['css']),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""") <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""")
self.assertEqual(str(w1.media['js']), """<script type="text/javascript" src="/path/to/js1"></script> self.assertEqual(
str(w1.media['js']),
"""<script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
def test_combine_media(self): def test_combine_media(self):
# Media objects can be combined. Any given media resource will appear only # Media objects can be combined. Any given media resource will appear only
@ -98,20 +115,26 @@ class FormsMediaTestCase(SimpleTestCase):
w1 = MyWidget1() w1 = MyWidget1()
w2 = MyWidget2() w2 = MyWidget2()
w3 = MyWidget3() w3 = MyWidget3()
self.assertEqual(str(w1.media + w2.media + w3.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media + w2.media + w3.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Check that media addition hasn't affected the original objects # Check that media addition hasn't affected the original objects
self.assertEqual(str(w1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# Regression check for #12879: specifying the same CSS or JS file # Regression check for #12879: specifying the same CSS or JS file
# multiple times in a single Media instance should result in that file # multiple times in a single Media instance should result in that file
@ -122,8 +145,11 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js1') js = ('/path/to/js1', '/path/to/js1')
w4 = MyWidget4() w4 = MyWidget4()
self.assertEqual(str(w4.media), """<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
<script type="text/javascript" src="/path/to/js1"></script>""") str(w4.media),
"""<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script>"""
)
def test_media_property(self): def test_media_property(self):
############################################################### ###############################################################
@ -147,10 +173,13 @@ class FormsMediaTestCase(SimpleTestCase):
media = property(_media) media = property(_media)
w5 = MyWidget5() w5 = MyWidget5()
self.assertEqual(str(w5.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w5.media),
"""<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
<link href="/other/path" type="text/css" media="all" rel="stylesheet" /> <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/some/js"></script> <script type="text/javascript" src="/some/js"></script>
<script type="text/javascript" src="/other/js"></script>""") <script type="text/javascript" src="/other/js"></script>"""
)
def test_media_property_parent_references(self): def test_media_property_parent_references(self):
# Media properties can reference the media of their parents, # Media properties can reference the media of their parents,
@ -168,13 +197,16 @@ class FormsMediaTestCase(SimpleTestCase):
media = property(_media) media = property(_media)
w6 = MyWidget6() w6 = MyWidget6()
self.assertEqual(str(w6.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w6.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/other/path" type="text/css" media="all" rel="stylesheet" /> <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/other/js"></script>""") <script type="text/javascript" src="/other/js"></script>"""
)
def test_media_inheritance(self): def test_media_inheritance(self):
############################################################### ###############################################################
@ -193,11 +225,14 @@ class FormsMediaTestCase(SimpleTestCase):
pass pass
w7 = MyWidget7() w7 = MyWidget7()
self.assertEqual(str(w7.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w7.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# If a widget extends another but defines media, it extends the parent widget's media by default # If a widget extends another but defines media, it extends the parent widget's media by default
class MyWidget8(MyWidget1): class MyWidget8(MyWidget1):
@ -208,13 +243,16 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w8 = MyWidget8() w8 = MyWidget8()
self.assertEqual(str(w8.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w8.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_media_inheritance_from_property(self): def test_media_inheritance_from_property(self):
# If a widget extends another but defines media, it extends the parents widget's media, # If a widget extends another but defines media, it extends the parents widget's media,
@ -239,10 +277,13 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/other/js',) js = ('/other/js',)
w9 = MyWidget9() w9 = MyWidget9()
self.assertEqual(str(w9.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w9.media),
"""<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
<link href="/other/path" type="text/css" media="all" rel="stylesheet" /> <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/some/js"></script> <script type="text/javascript" src="/some/js"></script>
<script type="text/javascript" src="/other/js"></script>""") <script type="text/javascript" src="/other/js"></script>"""
)
# A widget can disable media inheritance by specifying 'extend=False' # A widget can disable media inheritance by specifying 'extend=False'
class MyWidget10(MyWidget1): class MyWidget10(MyWidget1):
@ -277,13 +318,16 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w11 = MyWidget11() w11 = MyWidget11()
self.assertEqual(str(w11.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w11.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_media_inheritance_single_type(self): def test_media_inheritance_single_type(self):
# A widget can enable inheritance of one media type by specifying extend as a tuple # A widget can enable inheritance of one media type by specifying extend as a tuple
@ -303,11 +347,14 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w12 = MyWidget12() w12 = MyWidget12()
self.assertEqual(str(w12.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w12.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_multi_media(self): def test_multi_media(self):
############################################################### ###############################################################
@ -325,12 +372,15 @@ class FormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
multimedia = MultimediaWidget() multimedia = MultimediaWidget()
self.assertEqual(str(multimedia.media), """<link href="/file4" type="text/css" media="print" rel="stylesheet" /> self.assertEqual(
str(multimedia.media),
"""<link href="/file4" type="text/css" media="print" rel="stylesheet" />
<link href="/file3" type="text/css" media="screen" rel="stylesheet" /> <link href="/file3" type="text/css" media="screen" rel="stylesheet" />
<link href="/file1" type="text/css" media="screen, print" rel="stylesheet" /> <link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
<link href="/file2" type="text/css" media="screen, print" rel="stylesheet" /> <link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_multi_widget(self): def test_multi_widget(self):
############################################################### ###############################################################
@ -366,13 +416,16 @@ class FormsMediaTestCase(SimpleTestCase):
super(MyMultiWidget, self).__init__(widgets, attrs) super(MyMultiWidget, self).__init__(widgets, attrs)
mymulti = MyMultiWidget() mymulti = MyMultiWidget()
self.assertEqual(str(mymulti.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(mymulti.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_form_media(self): def test_form_media(self):
############################################################### ###############################################################
@ -405,25 +458,31 @@ class FormsMediaTestCase(SimpleTestCase):
field1 = CharField(max_length=20, widget=MyWidget1()) field1 = CharField(max_length=20, widget=MyWidget1())
field2 = CharField(max_length=20, widget=MyWidget2()) field2 = CharField(max_length=20, widget=MyWidget2())
f1 = MyForm() f1 = MyForm()
self.assertEqual(str(f1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f1.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Form media can be combined to produce a single media definition. # Form media can be combined to produce a single media definition.
class AnotherForm(Form): class AnotherForm(Form):
field3 = CharField(max_length=20, widget=MyWidget3()) field3 = CharField(max_length=20, widget=MyWidget3())
f2 = AnotherForm() f2 = AnotherForm()
self.assertEqual(str(f1.media + f2.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f1.media + f2.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Forms can also define media, following the same rules as widgets. # Forms can also define media, following the same rules as widgets.
class FormWithMedia(Form): class FormWithMedia(Form):
@ -436,7 +495,9 @@ class FormsMediaTestCase(SimpleTestCase):
'all': ('/some/form/css',) 'all': ('/some/form/css',)
} }
f3 = FormWithMedia() f3 = FormWithMedia()
self.assertEqual(str(f3.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f3.media),
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" /> <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
@ -444,17 +505,23 @@ class FormsMediaTestCase(SimpleTestCase):
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script> <script type="text/javascript" src="/path/to/js4"></script>
<script type="text/javascript" src="/some/form/javascript"></script>""") <script type="text/javascript" src="/some/form/javascript"></script>"""
)
# Media works in templates # Media works in templates
self.assertEqual(Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), """<script type="text/javascript" src="/path/to/js1"></script> self.assertEqual(
Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})),
"""<script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script> <script type="text/javascript" src="/path/to/js4"></script>
<script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="/some/form/javascript"></script>"""
"""<link href="http://media.example.com/media/path/to/css1" type="text/css" """
"""media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""") <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />"""
)
def test_html_safe(self): def test_html_safe(self):
media = Media(css={'all': ['/path/to/css']}, js=['/path/to/js']) media = Media(css={'all': ['/path/to/css']}, js=['/path/to/js'])
@ -471,12 +538,18 @@ class StaticFormsMediaTestCase(SimpleTestCase):
def test_construction(self): def test_construction(self):
# Check construction of media objects # Check construction of media objects
m = Media(css={'all': ('path/to/css1', '/path/to/css2')}, js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')) m = Media(
self.assertEqual(str(m), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> css={'all': ('path/to/css1', '/path/to/css2')},
js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'),
)
self.assertEqual(
str(m),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
class Foo: class Foo:
css = { css = {
@ -485,11 +558,14 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')
m3 = Media(Foo) m3 = Media(Foo)
self.assertEqual(str(m3), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(m3),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# A widget can exist without a media definition # A widget can exist without a media definition
class MyWidget(TextInput): class MyWidget(TextInput):
@ -514,19 +590,28 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3')
w1 = MyWidget1() w1 = MyWidget1()
self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# Media objects can be interrogated by media type # Media objects can be interrogated by media type
self.assertEqual(str(w1.media['css']), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""") str(w1.media['css']),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />"""
)
self.assertEqual(str(w1.media['js']), """<script type="text/javascript" src="/path/to/js1"></script> self.assertEqual(
str(w1.media['js']),
"""<script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
def test_combine_media(self): def test_combine_media(self):
# Media objects can be combined. Any given media resource will appear only # Media objects can be combined. Any given media resource will appear only
@ -555,20 +640,26 @@ class StaticFormsMediaTestCase(SimpleTestCase):
w1 = MyWidget1() w1 = MyWidget1()
w2 = MyWidget2() w2 = MyWidget2()
w3 = MyWidget3() w3 = MyWidget3()
self.assertEqual(str(w1.media + w2.media + w3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media + w2.media + w3.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Check that media addition hasn't affected the original objects # Check that media addition hasn't affected the original objects
self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w1.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# Regression check for #12879: specifying the same CSS or JS file # Regression check for #12879: specifying the same CSS or JS file
# multiple times in a single Media instance should result in that file # multiple times in a single Media instance should result in that file
@ -625,13 +716,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
media = property(_media) media = property(_media)
w6 = MyWidget6() w6 = MyWidget6()
self.assertEqual(str(w6.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w6.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/other/path" type="text/css" media="all" rel="stylesheet" /> <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/other/js"></script>""") <script type="text/javascript" src="/other/js"></script>"""
)
def test_media_inheritance(self): def test_media_inheritance(self):
############################################################### ###############################################################
@ -650,11 +744,14 @@ class StaticFormsMediaTestCase(SimpleTestCase):
pass pass
w7 = MyWidget7() w7 = MyWidget7()
self.assertEqual(str(w7.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w7.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""") <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
)
# If a widget extends another but defines media, it extends the parent widget's media by default # If a widget extends another but defines media, it extends the parent widget's media by default
class MyWidget8(MyWidget1): class MyWidget8(MyWidget1):
@ -665,13 +762,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w8 = MyWidget8() w8 = MyWidget8()
self.assertEqual(str(w8.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w8.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_media_inheritance_from_property(self): def test_media_inheritance_from_property(self):
# If a widget extends another but defines media, it extends the parents widget's media, # If a widget extends another but defines media, it extends the parents widget's media,
@ -696,10 +796,13 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/other/js',) js = ('/other/js',)
w9 = MyWidget9() w9 = MyWidget9()
self.assertEqual(str(w9.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w9.media),
"""<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
<link href="/other/path" type="text/css" media="all" rel="stylesheet" /> <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/some/js"></script> <script type="text/javascript" src="/some/js"></script>
<script type="text/javascript" src="/other/js"></script>""") <script type="text/javascript" src="/other/js"></script>"""
)
# A widget can disable media inheritance by specifying 'extend=False' # A widget can disable media inheritance by specifying 'extend=False'
class MyWidget10(MyWidget1): class MyWidget10(MyWidget1):
@ -734,13 +837,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w11 = MyWidget11() w11 = MyWidget11()
self.assertEqual(str(w11.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w11.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_media_inheritance_single_type(self): def test_media_inheritance_single_type(self):
# A widget can enable inheritance of one media type by specifying extend as a tuple # A widget can enable inheritance of one media type by specifying extend as a tuple
@ -760,11 +866,14 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
w12 = MyWidget12() w12 = MyWidget12()
self.assertEqual(str(w12.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(w12.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_multi_media(self): def test_multi_media(self):
############################################################### ###############################################################
@ -782,12 +891,15 @@ class StaticFormsMediaTestCase(SimpleTestCase):
js = ('/path/to/js1', '/path/to/js4') js = ('/path/to/js1', '/path/to/js4')
multimedia = MultimediaWidget() multimedia = MultimediaWidget()
self.assertEqual(str(multimedia.media), """<link href="/file4" type="text/css" media="print" rel="stylesheet" /> self.assertEqual(
str(multimedia.media),
"""<link href="/file4" type="text/css" media="print" rel="stylesheet" />
<link href="/file3" type="text/css" media="screen" rel="stylesheet" /> <link href="/file3" type="text/css" media="screen" rel="stylesheet" />
<link href="/file1" type="text/css" media="screen, print" rel="stylesheet" /> <link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
<link href="/file2" type="text/css" media="screen, print" rel="stylesheet" /> <link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_multi_widget(self): def test_multi_widget(self):
############################################################### ###############################################################
@ -823,13 +935,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
super(MyMultiWidget, self).__init__(widgets, attrs) super(MyMultiWidget, self).__init__(widgets, attrs)
mymulti = MyMultiWidget() mymulti = MyMultiWidget()
self.assertEqual(str(mymulti.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(mymulti.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
def test_form_media(self): def test_form_media(self):
############################################################### ###############################################################
@ -862,25 +977,31 @@ class StaticFormsMediaTestCase(SimpleTestCase):
field1 = CharField(max_length=20, widget=MyWidget1()) field1 = CharField(max_length=20, widget=MyWidget1())
field2 = CharField(max_length=20, widget=MyWidget2()) field2 = CharField(max_length=20, widget=MyWidget2())
f1 = MyForm() f1 = MyForm()
self.assertEqual(str(f1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f1.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Form media can be combined to produce a single media definition. # Form media can be combined to produce a single media definition.
class AnotherForm(Form): class AnotherForm(Form):
field3 = CharField(max_length=20, widget=MyWidget3()) field3 = CharField(max_length=20, widget=MyWidget3())
f2 = AnotherForm() f2 = AnotherForm()
self.assertEqual(str(f1.media + f2.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f1.media + f2.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/path/to/js1"></script> <script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script>""") <script type="text/javascript" src="/path/to/js4"></script>"""
)
# Forms can also define media, following the same rules as widgets. # Forms can also define media, following the same rules as widgets.
class FormWithMedia(Form): class FormWithMedia(Form):
@ -893,7 +1014,9 @@ class StaticFormsMediaTestCase(SimpleTestCase):
'all': ('/some/form/css',) 'all': ('/some/form/css',)
} }
f3 = FormWithMedia() f3 = FormWithMedia()
self.assertEqual(str(f3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> self.assertEqual(
str(f3.media),
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" /> <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
@ -901,14 +1024,19 @@ class StaticFormsMediaTestCase(SimpleTestCase):
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script> <script type="text/javascript" src="/path/to/js4"></script>
<script type="text/javascript" src="/some/form/javascript"></script>""") <script type="text/javascript" src="/some/form/javascript"></script>"""
)
# Media works in templates # Media works in templates
self.assertEqual(Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), """<script type="text/javascript" src="/path/to/js1"></script> self.assertEqual(
Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})),
"""<script type="text/javascript" src="/path/to/js1"></script>
<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script> <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
<script type="text/javascript" src="/path/to/js4"></script> <script type="text/javascript" src="/path/to/js4"></script>
<script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="/some/form/javascript"></script>"""
"""<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""") <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />"""
)

View File

@ -22,7 +22,11 @@ class FormsRegressionsTestCase(TestCase):
f1 = CharField(max_length=10, widget=TextInput(attrs=extra_attrs)) f1 = CharField(max_length=10, widget=TextInput(attrs=extra_attrs))
f2 = CharField(widget=TextInput(attrs=extra_attrs)) f2 = CharField(widget=TextInput(attrs=extra_attrs))
self.assertHTMLEqual(TestForm(auto_id=False).as_p(), '<p>F1: <input type="text" class="special" name="f1" maxlength="10" /></p>\n<p>F2: <input type="text" class="special" name="f2" /></p>') self.assertHTMLEqual(
TestForm(auto_id=False).as_p(),
'<p>F1: <input type="text" class="special" name="f1" maxlength="10" /></p>\n'
'<p>F2: <input type="text" class="special" name="f2" /></p>'
)
def test_regression_3600(self): def test_regression_3600(self):
# Tests for form i18n # # Tests for form i18n #
@ -32,19 +36,35 @@ class FormsRegressionsTestCase(TestCase):
username = CharField(max_length=10, label=ugettext_lazy('username')) username = CharField(max_length=10, label=ugettext_lazy('username'))
f = SomeForm() f = SomeForm()
self.assertHTMLEqual(f.as_p(), '<p><label for="id_username">username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>') self.assertHTMLEqual(
f.as_p(),
'<p><label for="id_username">username:</label>'
'<input id="id_username" type="text" name="username" maxlength="10" /></p>'
)
# Translations are done at rendering time, so multi-lingual apps can define forms) # Translations are done at rendering time, so multi-lingual apps can define forms)
with translation.override('de'): with translation.override('de'):
self.assertHTMLEqual(f.as_p(), '<p><label for="id_username">Benutzername:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>') self.assertHTMLEqual(
f.as_p(),
'<p><label for="id_username">Benutzername:</label>'
'<input id="id_username" type="text" name="username" maxlength="10" /></p>'
)
with translation.override('pl'): with translation.override('pl'):
self.assertHTMLEqual(f.as_p(), '<p><label for="id_username">u\u017cytkownik:</label> <input id="id_username" type="text" name="username" maxlength="10" /></p>') self.assertHTMLEqual(
f.as_p(),
'<p><label for="id_username">u\u017cytkownik:</label>'
'<input id="id_username" type="text" name="username" maxlength="10" /></p>'
)
def test_regression_5216(self): def test_regression_5216(self):
# There was some problems with form translations in #5216 # There was some problems with form translations in #5216
class SomeForm(Form): class SomeForm(Form):
field_1 = CharField(max_length=10, label=ugettext_lazy('field_1')) field_1 = CharField(max_length=10, label=ugettext_lazy('field_1'))
field_2 = CharField(max_length=10, label=ugettext_lazy('field_2'), widget=TextInput(attrs={'id': 'field_2_id'})) field_2 = CharField(
max_length=10,
label=ugettext_lazy('field_2'),
widget=TextInput(attrs={'id': 'field_2_id'}),
)
f = SomeForm() f = SomeForm()
self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>') self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>')
@ -57,12 +77,38 @@ class FormsRegressionsTestCase(TestCase):
somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf') somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf')
f = SomeForm() f = SomeForm()
self.assertHTMLEqual(f.as_p(), '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(
f.as_p(),
'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
'<ul id="id_somechoice">\n'
'<li><label for="id_somechoice_0">'
'<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> '
'En tied\xe4</label></li>\n'
'<li><label for="id_somechoice_1">'
'<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> '
'Mies</label></li>\n<li><label for="id_somechoice_2">'
'<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> '
'Nainen</label></li>\n</ul></p>'
)
# Translated error messages used to be buggy. # Translated error messages used to be buggy.
with translation.override('ru'): with translation.override('ru'):
f = SomeForm({}) f = SomeForm({})
self.assertHTMLEqual(f.as_p(), '<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(
f.as_p(),
'<ul class="errorlist"><li>'
'\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c'
'\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n'
'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
' <ul id="id_somechoice">\n<li><label for="id_somechoice_0">'
'<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> '
'En tied\xe4</label></li>\n'
'<li><label for="id_somechoice_1">'
'<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> '
'Mies</label></li>\n<li><label for="id_somechoice_2">'
'<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> '
'Nainen</label></li>\n</ul></p>'
)
# Deep copying translated text shouldn't raise an error) # Deep copying translated text shouldn't raise an error)
class CopyForm(Form): class CopyForm(Form):
@ -95,8 +141,18 @@ class FormsRegressionsTestCase(TestCase):
data = IntegerField(widget=HiddenInput) data = IntegerField(widget=HiddenInput)
f = HiddenForm({}) f = HiddenForm({})
self.assertHTMLEqual(f.as_p(), '<ul class="errorlist nonfield"><li>(Hidden field data) This field is required.</li></ul>\n<p> <input type="hidden" name="data" id="id_data" /></p>') self.assertHTMLEqual(
self.assertHTMLEqual(f.as_table(), '<tr><td colspan="2"><ul class="errorlist nonfield"><li>(Hidden field data) This field is required.</li></ul><input type="hidden" name="data" id="id_data" /></td></tr>') f.as_p(),
'<ul class="errorlist nonfield">'
'<li>(Hidden field data) This field is required.</li></ul>\n<p> '
'<input type="hidden" name="data" id="id_data" /></p>'
)
self.assertHTMLEqual(
f.as_table(),
'<tr><td colspan="2"><ul class="errorlist nonfield">'
'<li>(Hidden field data) This field is required.</li></ul>'
'<input type="hidden" name="data" id="id_data" /></td></tr>'
)
def test_xss_error_messages(self): def test_xss_error_messages(self):
################################################### ###################################################
@ -114,13 +170,23 @@ class FormsRegressionsTestCase(TestCase):
field = ChoiceField(choices=[('one', 'One')]) field = ChoiceField(choices=[('one', 'One')])
f = SomeForm({'field': '<script>'}) f = SomeForm({'field': '<script>'})
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. &lt;script&gt; is not one of the available choices.</li></ul></li></ul>') self.assertHTMLEqual(
t.render(Context({'form': f})),
'<ul class="errorlist"><li>field<ul class="errorlist">'
'<li>Select a valid choice. &lt;script&gt; is not one of the '
'available choices.</li></ul></li></ul>'
)
class SomeForm(Form): class SomeForm(Form):
field = MultipleChoiceField(choices=[('one', 'One')]) field = MultipleChoiceField(choices=[('one', 'One')])
f = SomeForm({'field': ['<script>']}) f = SomeForm({'field': ['<script>']})
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. &lt;script&gt; is not one of the available choices.</li></ul></li></ul>') self.assertHTMLEqual(
t.render(Context({'form': f})),
'<ul class="errorlist"><li>field<ul class="errorlist">'
'<li>Select a valid choice. &lt;script&gt; is not one of the '
'available choices.</li></ul></li></ul>'
)
from forms_tests.models import ChoiceModel from forms_tests.models import ChoiceModel
@ -128,7 +194,12 @@ class FormsRegressionsTestCase(TestCase):
field = ModelMultipleChoiceField(ChoiceModel.objects.all()) field = ModelMultipleChoiceField(ChoiceModel.objects.all())
f = SomeForm({'field': ['<script>']}) f = SomeForm({'field': ['<script>']})
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>&quot;&lt;script&gt;&quot; is not a valid value for a primary key.</li></ul></li></ul>') self.assertHTMLEqual(
t.render(Context({'form': f})),
'<ul class="errorlist"><li>field<ul class="errorlist">'
'<li>&quot;&lt;script&gt;&quot; is not a valid value for a '
'primary key.</li></ul></li></ul>'
)
def test_regression_14234(self): def test_regression_14234(self):
""" """

View File

@ -22,9 +22,18 @@ class FormsUtilsTestCase(SimpleTestCase):
self.assertEqual(flatatt({'id': "header"}), ' id="header"') self.assertEqual(flatatt({'id': "header"}), ' id="header"')
self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), ' class="news" title="Read this"') self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), ' class="news" title="Read this"')
self.assertEqual(flatatt({'class': "news", 'title': "Read this", 'required': "required"}), ' class="news" required="required" title="Read this"') self.assertEqual(
self.assertEqual(flatatt({'class': "news", 'title': "Read this", 'required': True}), ' class="news" title="Read this" required') flatatt({'class': "news", 'title': "Read this", 'required': "required"}),
self.assertEqual(flatatt({'class': "news", 'title': "Read this", 'required': False}), ' class="news" title="Read this"') ' class="news" required="required" title="Read this"'
)
self.assertEqual(
flatatt({'class': "news", 'title': "Read this", 'required': True}),
' class="news" title="Read this" required'
)
self.assertEqual(
flatatt({'class': "news", 'title': "Read this", 'required': False}),
' class="news" title="Read this"'
)
self.assertEqual(flatatt({}), '') self.assertEqual(flatatt({}), '')
def test_flatatt_no_side_effects(self): def test_flatatt_no_side_effects(self):
@ -97,19 +106,33 @@ class FormsUtilsTestCase(SimpleTestCase):
return "A very bad error." return "A very bad error."
# Can take a non-string. # Can take a non-string.
self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)), self.assertHTMLEqual(
'<ul class="errorlist"><li>A very bad error.</li></ul>') str(ErrorList(ValidationError(VeryBadError()).messages)),
'<ul class="errorlist"><li>A very bad error.</li></ul>'
)
# Escapes non-safe input but not input marked safe. # Escapes non-safe input but not input marked safe.
example = 'Example of link: <a href="http://www.example.com/">example</a>' example = 'Example of link: <a href="http://www.example.com/">example</a>'
self.assertHTMLEqual(str(ErrorList([example])), self.assertHTMLEqual(
'<ul class="errorlist"><li>Example of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') str(ErrorList([example])),
self.assertHTMLEqual(str(ErrorList([mark_safe(example)])), '<ul class="errorlist"><li>Example of link: '
'<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>') '&lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>'
self.assertHTMLEqual(str(ErrorDict({'name': example})), )
'<ul class="errorlist"><li>nameExample of link: &lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>') self.assertHTMLEqual(
self.assertHTMLEqual(str(ErrorDict({'name': mark_safe(example)})), str(ErrorList([mark_safe(example)])),
'<ul class="errorlist"><li>nameExample of link: <a href="http://www.example.com/">example</a></li></ul>') '<ul class="errorlist"><li>Example of link: '
'<a href="http://www.example.com/">example</a></li></ul>'
)
self.assertHTMLEqual(
str(ErrorDict({'name': example})),
'<ul class="errorlist"><li>nameExample of link: '
'&lt;a href=&quot;http://www.example.com/&quot;&gt;example&lt;/a&gt;</li></ul>'
)
self.assertHTMLEqual(
str(ErrorDict({'name': mark_safe(example)})),
'<ul class="errorlist"><li>nameExample of link: '
'<a href="http://www.example.com/">example</a></li></ul>'
)
def test_error_dict_copy(self): def test_error_dict_copy(self):
e = ErrorDict() e = ErrorDict()

View File

@ -40,7 +40,11 @@ class UserForm(forms.Form):
class TestFieldWithValidators(TestCase): class TestFieldWithValidators(TestCase):
def test_all_errors_get_reported(self): def test_all_errors_get_reported(self):
form = UserForm({'full_name': 'not int nor mail', 'string': '2 is not correct', 'ignore_case_string': "IgnORE Case strIng"}) form = UserForm({
'full_name': 'not int nor mail',
'string': '2 is not correct',
'ignore_case_string': "IgnORE Case strIng",
})
self.assertRaises(ValidationError, form.fields['full_name'].clean, 'not int nor mail') self.assertRaises(ValidationError, form.fields['full_name'].clean, 'not int nor mail')
try: try:

View File

@ -34,7 +34,15 @@ class FormsWidgetTests(SimpleTestCase):
inp_set1.append(str(inp)) inp_set1.append(str(inp))
inp_set2.append('%s<br />' % inp) inp_set2.append('%s<br />' % inp)
inp_set3.append('<p>%s %s</p>' % (inp.tag(), inp.choice_label)) inp_set3.append('<p>%s %s</p>' % (inp.tag(), inp.choice_label))
inp_set4.append('%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())) inp_set4.append(
'%s %s %s %s %s' % (
inp.name,
inp.value,
inp.choice_value,
inp.choice_label,
inp.is_checked(),
)
)
self.assertHTMLEqual('\n'.join(inp_set1), """<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label> self.assertHTMLEqual('\n'.join(inp_set1), """<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="P" /> Paul</label>
@ -57,7 +65,10 @@ beatle J R Ringo False""")
w = RadioSelect() w = RadioSelect()
r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
self.assertHTMLEqual(str(r[1]), '<label><input type="radio" name="beatle" value="P" /> Paul</label>') self.assertHTMLEqual(str(r[1]), '<label><input type="radio" name="beatle" value="P" /> Paul</label>')
self.assertHTMLEqual(str(r[0]), '<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>') self.assertHTMLEqual(
str(r[0]),
'<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>'
)
self.assertTrue(r[0].is_checked()) self.assertTrue(r[0].is_checked())
self.assertFalse(r[1].is_checked()) self.assertFalse(r[1].is_checked())
self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul')) self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul'))
@ -76,30 +87,39 @@ beatle J R Ringo False""")
def render(self): def render(self):
return '<br />\n'.join(six.text_type(choice) for choice in self) return '<br />\n'.join(six.text_type(choice) for choice in self)
w = RadioSelect(renderer=MyRenderer) w = RadioSelect(renderer=MyRenderer)
self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br /> self.assertHTMLEqual(
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 type="radio" name="beatle" value="P" /> Paul</label><br />
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</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>""") <label><input type="radio" name="beatle" value="R" /> Ringo</label>"""
)
# Or you can use custom RadioSelect fields that use your custom renderer. # Or you can use custom RadioSelect fields that use your custom renderer.
class CustomRadioSelect(RadioSelect): class CustomRadioSelect(RadioSelect):
renderer = MyRenderer renderer = MyRenderer
w = CustomRadioSelect() w = CustomRadioSelect()
self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br /> self.assertHTMLEqual(
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 type="radio" name="beatle" value="P" /> Paul</label><br />
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</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>""") <label><input type="radio" name="beatle" value="R" /> Ringo</label>"""
)
# You can customize rendering with outer_html/inner_html renderer variables (#22950) # You can customize rendering with outer_html/inner_html renderer variables (#22950)
class MyRenderer(RadioFieldRenderer): class MyRenderer(RadioFieldRenderer):
outer_html = str('<div{id_attr}>{content}</div>') # str is just to test some Python 2 issue with bytestrings # str is just to test some Python 2 issue with bytestrings
outer_html = str('<div{id_attr}>{content}</div>')
inner_html = '<p>{choice_value}{sub_widgets}</p>' inner_html = '<p>{choice_value}{sub_widgets}</p>'
w = RadioSelect(renderer=MyRenderer) w = RadioSelect(renderer=MyRenderer)
output = w.render('beatle', 'J', output = w.render('beatle', 'J',
choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')),
attrs={'id': 'bar'}) attrs={'id': 'bar'})
self.assertIsInstance(output, SafeData) self.assertIsInstance(output, SafeData)
self.assertHTMLEqual(output, """<div id="bar"> self.assertHTMLEqual(
output,
"""<div id="bar">
<p><label for="bar_0"><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></p> <p><label for="bar_0"><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></p>
<p><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></p> <p><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></p>
<p><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></p> <p><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></p>

View File

@ -101,7 +101,9 @@ class ModelFormCallableModelDefault(TestCase):
ChoiceOptionModel.objects.create(id=1, name='default') ChoiceOptionModel.objects.create(id=1, name='default')
ChoiceOptionModel.objects.create(id=2, name='option 2') ChoiceOptionModel.objects.create(id=2, name='option 2')
ChoiceOptionModel.objects.create(id=3, name='option 3') ChoiceOptionModel.objects.create(id=3, name='option 3')
self.assertHTMLEqual(ChoiceFieldForm().as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice"> self.assertHTMLEqual(
ChoiceFieldForm().as_p(),
"""<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice">
<option value="1" selected="selected">ChoiceOption 1</option> <option value="1" selected="selected">ChoiceOption 1</option>
<option value="2">ChoiceOption 2</option> <option value="2">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
@ -111,28 +113,33 @@ class ModelFormCallableModelDefault(TestCase):
<option value="2">ChoiceOption 2</option> <option value="2">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
</select><input type="hidden" name="initial-choice_int" value="1" id="initial-id_choice_int" /></p> </select><input type="hidden" name="initial-choice_int" value="1" id="initial-id_choice_int" /></p>
<p><label for="id_multi_choice">Multi choice:</label> <select multiple="multiple" name="multi_choice" id="id_multi_choice"> <p><label for="id_multi_choice">Multi choice:</label>
<select multiple="multiple" name="multi_choice" id="id_multi_choice">
<option value="1" selected="selected">ChoiceOption 1</option> <option value="1" selected="selected">ChoiceOption 1</option>
<option value="2">ChoiceOption 2</option> <option value="2">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
</select><input type="hidden" name="initial-multi_choice" value="1" id="initial-id_multi_choice_0" /></p> </select><input type="hidden" name="initial-multi_choice" value="1" id="initial-id_multi_choice_0" /></p>
<p><label for="id_multi_choice_int">Multi choice int:</label> <select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int"> <p><label for="id_multi_choice_int">Multi choice int:</label>
<select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int">
<option value="1" selected="selected">ChoiceOption 1</option> <option value="1" selected="selected">ChoiceOption 1</option>
<option value="2">ChoiceOption 2</option> <option value="2">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
</select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0" /></p>""") </select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0" /></p>"""
)
def test_initial_instance_value(self): def test_initial_instance_value(self):
"Initial instances for model fields may also be instances (refs #7287)" "Initial instances for model fields may also be instances (refs #7287)"
ChoiceOptionModel.objects.create(id=1, name='default') ChoiceOptionModel.objects.create(id=1, name='default')
obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2') obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2')
obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3') obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3')
self.assertHTMLEqual(ChoiceFieldForm(initial={ self.assertHTMLEqual(
'choice': obj2, ChoiceFieldForm(initial={
'choice_int': obj2, 'choice': obj2,
'multi_choice': [obj2, obj3], 'choice_int': obj2,
'multi_choice_int': ChoiceOptionModel.objects.exclude(name="default"), 'multi_choice': [obj2, obj3],
}).as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice"> 'multi_choice_int': ChoiceOptionModel.objects.exclude(name="default"),
}).as_p(),
"""<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice">
<option value="1">ChoiceOption 1</option> <option value="1">ChoiceOption 1</option>
<option value="2" selected="selected">ChoiceOption 2</option> <option value="2" selected="selected">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
@ -142,24 +149,28 @@ class ModelFormCallableModelDefault(TestCase):
<option value="2" selected="selected">ChoiceOption 2</option> <option value="2" selected="selected">ChoiceOption 2</option>
<option value="3">ChoiceOption 3</option> <option value="3">ChoiceOption 3</option>
</select><input type="hidden" name="initial-choice_int" value="2" id="initial-id_choice_int" /></p> </select><input type="hidden" name="initial-choice_int" value="2" id="initial-id_choice_int" /></p>
<p><label for="id_multi_choice">Multi choice:</label> <select multiple="multiple" name="multi_choice" id="id_multi_choice"> <p><label for="id_multi_choice">Multi choice:</label>
<select multiple="multiple" name="multi_choice" id="id_multi_choice">
<option value="1">ChoiceOption 1</option> <option value="1">ChoiceOption 1</option>
<option value="2" selected="selected">ChoiceOption 2</option> <option value="2" selected="selected">ChoiceOption 2</option>
<option value="3" selected="selected">ChoiceOption 3</option> <option value="3" selected="selected">ChoiceOption 3</option>
</select><input type="hidden" name="initial-multi_choice" value="2" id="initial-id_multi_choice_0" /> </select><input type="hidden" name="initial-multi_choice" value="2" id="initial-id_multi_choice_0" />
<input type="hidden" name="initial-multi_choice" value="3" id="initial-id_multi_choice_1" /></p> <input type="hidden" name="initial-multi_choice" value="3" id="initial-id_multi_choice_1" /></p>
<p><label for="id_multi_choice_int">Multi choice int:</label> <select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int"> <p><label for="id_multi_choice_int">Multi choice int:</label>
<select multiple="multiple" name="multi_choice_int" id="id_multi_choice_int">
<option value="1">ChoiceOption 1</option> <option value="1">ChoiceOption 1</option>
<option value="2" selected="selected">ChoiceOption 2</option> <option value="2" selected="selected">ChoiceOption 2</option>
<option value="3" selected="selected">ChoiceOption 3</option> <option value="3" selected="selected">ChoiceOption 3</option>
</select><input type="hidden" name="initial-multi_choice_int" value="2" id="initial-id_multi_choice_int_0" /> </select><input type="hidden" name="initial-multi_choice_int" value="2" id="initial-id_multi_choice_int_0" />
<input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1" /></p>""") <input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1" /></p>"""
)
class FormsModelTestCase(TestCase): class FormsModelTestCase(TestCase):
def test_unicode_filename(self): def test_unicode_filename(self):
# FileModel with unicode filename and data ######################### # FileModel with unicode filename and data #########################
f = FileForm(data={}, files={'file1': SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode('utf-8'))}, auto_id=False) file1 = SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode('utf-8'))
f = FileForm(data={}, files={'file1': file1}, auto_id=False)
self.assertTrue(f.is_valid()) self.assertTrue(f.is_valid())
self.assertIn('file1', f.cleaned_data) self.assertIn('file1', f.cleaned_data)
m = FileModel.objects.create(file=f.cleaned_data['file1']) m = FileModel.objects.create(file=f.cleaned_data['file1'])
@ -287,23 +298,28 @@ class ManyToManyExclusionTestCase(TestCase):
class EmptyLabelTestCase(TestCase): class EmptyLabelTestCase(TestCase):
def test_empty_field_char(self): def test_empty_field_char(self):
f = EmptyCharLabelChoiceForm() f = EmptyCharLabelChoiceForm()
self.assertHTMLEqual(f.as_p(), self.assertHTMLEqual(
f.as_p(),
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p> """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
<p><label for="id_choice">Choice:</label> <select id="id_choice" name="choice"> <p><label for="id_choice">Choice:</label> <select id="id_choice" name="choice">
<option value="" selected="selected">No Preference</option> <option value="" selected="selected">No Preference</option>
<option value="f">Foo</option> <option value="f">Foo</option>
<option value="b">Bar</option> <option value="b">Bar</option>
</select></p>""") </select></p>"""
)
def test_empty_field_char_none(self): def test_empty_field_char_none(self):
f = EmptyCharLabelNoneChoiceForm() f = EmptyCharLabelNoneChoiceForm()
self.assertHTMLEqual(f.as_p(), self.assertHTMLEqual(
f.as_p(),
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p> """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
<p><label for="id_choice_string_w_none">Choice string w none:</label> <select id="id_choice_string_w_none" name="choice_string_w_none"> <p><label for="id_choice_string_w_none">Choice string w none:</label>
<select id="id_choice_string_w_none" name="choice_string_w_none">
<option value="" selected="selected">No Preference</option> <option value="" selected="selected">No Preference</option>
<option value="f">Foo</option> <option value="f">Foo</option>
<option value="b">Bar</option> <option value="b">Bar</option>
</select></p>""") </select></p>"""
)
def test_save_empty_label_forms(self): def test_save_empty_label_forms(self):
# Test that saving a form with a blank choice results in the expected # Test that saving a form with a blank choice results in the expected
@ -324,13 +340,16 @@ class EmptyLabelTestCase(TestCase):
def test_empty_field_integer(self): def test_empty_field_integer(self):
f = EmptyIntegerLabelChoiceForm() f = EmptyIntegerLabelChoiceForm()
self.assertHTMLEqual(f.as_p(), self.assertHTMLEqual(
f.as_p(),
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p> """<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" /></p>
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer"> <p><label for="id_choice_integer">Choice integer:</label>
<select id="id_choice_integer" name="choice_integer">
<option value="" selected="selected">No Preference</option> <option value="" selected="selected">No Preference</option>
<option value="1">Foo</option> <option value="1">Foo</option>
<option value="2">Bar</option> <option value="2">Bar</option>
</select></p>""") </select></p>"""
)
def test_get_display_value_on_none(self): def test_get_display_value_on_none(self):
m = ChoiceModel.objects.create(name='test', choice='', choice_integer=None) m = ChoiceModel.objects.create(name='test', choice='', choice_integer=None)
@ -340,20 +359,28 @@ class EmptyLabelTestCase(TestCase):
def test_html_rendering_of_prepopulated_models(self): def test_html_rendering_of_prepopulated_models(self):
none_model = ChoiceModel(name='none-test', choice_integer=None) none_model = ChoiceModel(name='none-test', choice_integer=None)
f = EmptyIntegerLabelChoiceForm(instance=none_model) f = EmptyIntegerLabelChoiceForm(instance=none_model)
self.assertHTMLEqual(f.as_p(), self.assertHTMLEqual(
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="none-test"/></p> f.as_p(),
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer"> """<p><label for="id_name">Name:</label>
<input id="id_name" maxlength="10" name="name" type="text" value="none-test"/></p>
<p><label for="id_choice_integer">Choice integer:</label>
<select id="id_choice_integer" name="choice_integer">
<option value="" selected="selected">No Preference</option> <option value="" selected="selected">No Preference</option>
<option value="1">Foo</option> <option value="1">Foo</option>
<option value="2">Bar</option> <option value="2">Bar</option>
</select></p>""") </select></p>"""
)
foo_model = ChoiceModel(name='foo-test', choice_integer=1) foo_model = ChoiceModel(name='foo-test', choice_integer=1)
f = EmptyIntegerLabelChoiceForm(instance=foo_model) f = EmptyIntegerLabelChoiceForm(instance=foo_model)
self.assertHTMLEqual(f.as_p(), self.assertHTMLEqual(
"""<p><label for="id_name">Name:</label> <input id="id_name" maxlength="10" name="name" type="text" value="foo-test"/></p> f.as_p(),
<p><label for="id_choice_integer">Choice integer:</label> <select id="id_choice_integer" name="choice_integer"> """<p><label for="id_name">Name:</label>
<input id="id_name" maxlength="10" name="name" type="text" value="foo-test"/></p>
<p><label for="id_choice_integer">Choice integer:</label>
<select id="id_choice_integer" name="choice_integer">
<option value="">No Preference</option> <option value="">No Preference</option>
<option value="1" selected="selected">Foo</option> <option value="1" selected="selected">Foo</option>
<option value="2">Bar</option> <option value="2">Bar</option>
</select></p>""") </select></p>"""
)

View File

@ -110,28 +110,99 @@ class GenericAdminViewTest(TestDataMixin, TestCase):
self.assertEqual(response.status_code, 302) # redirect somewhere self.assertEqual(response.status_code, 302) # redirect somewhere
def test_generic_inline_formset(self): def test_generic_inline_formset(self):
EpisodeMediaFormSet = generic_inlineformset_factory(Media, can_delete=False, exclude=['description', 'keywords'], extra=3) EpisodeMediaFormSet = generic_inlineformset_factory(
Media,
can_delete=False,
exclude=['description', 'keywords'],
extra=3,
)
e = Episode.objects.get(name='This Week in Django') e = Episode.objects.get(name='This Week in Django')
# Works with no queryset # Works with no queryset
formset = EpisodeMediaFormSet(instance=e) formset = EpisodeMediaFormSet(instance=e)
self.assertEqual(len(formset.forms), 5) self.assertEqual(len(formset.forms), 5)
self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.mp3_media_pk) self.assertHTMLEqual(
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.png_media_pk) formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="url" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">'
'Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" '
'type="url" name="generic_inline_admin-media-content_type-object_id-0-url" '
'value="http://example.com/podcast.mp3" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" '
'value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>'
% self.mp3_media_pk
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">'
'Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" '
'type="url" name="generic_inline_admin-media-content_type-object_id-1-url" '
'value="http://example.com/logo.png" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" '
'value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>'
% self.png_media_pk
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label>'
'<input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="url" '
'name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" '
'id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>'
)
# A queryset can be used to alter display ordering # A queryset can be used to alter display ordering
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url')) formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url'))
self.assertEqual(len(formset.forms), 5) self.assertEqual(len(formset.forms), 5)
self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) self.assertHTMLEqual(
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.mp3_media_pk) formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="url" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label>'
'<input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" '
'name="generic_inline_admin-media-content_type-object_id-0-url"'
'value="http://example.com/logo.png" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" '
'value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>'
% self.png_media_pk
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label>'
'<input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" '
'name="generic_inline_admin-media-content_type-object_id-1-url" '
'value="http://example.com/podcast.mp3" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" '
'value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>'
% self.mp3_media_pk
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">'
'Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" '
'type="url" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" '
'id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>'
)
# Works with a queryset that omits items # Works with a queryset that omits items
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png")) formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png"))
self.assertEqual(len(formset.forms), 4) self.assertEqual(len(formset.forms), 4)
self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) self.assertHTMLEqual(
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') formset.forms[0].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label>'
' <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" '
'name="generic_inline_admin-media-content_type-object_id-0-url" '
'value="http://example.com/logo.png" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" '
'value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>'
% self.png_media_pk
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">'
'Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" '
'type="url" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" />'
'<input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" '
'id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>'
)
def test_generic_inline_formset_factory(self): def test_generic_inline_formset_factory(self):
# Regression test for #10522. # Regression test for #10522.

View File

@ -403,12 +403,30 @@ class GenericRelationsTests(TestCase):
def test_generic_inline_formsets(self): def test_generic_inline_formsets(self):
GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1) GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1)
formset = GenericFormSet() formset = GenericFormSet()
self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p> self.assertHTMLEqual(
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>""") ''.join(form.as_p() for form in formset.forms),
"""<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">
Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text"
name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p>
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
<input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" />
<input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id"
id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>"""
)
formset = GenericFormSet(instance=Animal()) formset = GenericFormSet(instance=Animal())
self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p> self.assertHTMLEqual(
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>""") ''.join(form.as_p() for form in formset.forms),
"""<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">
Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag"
type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p>
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
<input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden"
name="generic_relations-taggeditem-content_type-object_id-0-id"
id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>"""
)
platypus = Animal.objects.create( platypus = Animal.objects.create(
common_name="Platypus", latin_name="Ornithorhynchus anatinus" common_name="Platypus", latin_name="Ornithorhynchus anatinus"
@ -419,14 +437,35 @@ class GenericRelationsTests(TestCase):
tagged_item_id = TaggedItem.objects.get( tagged_item_id = TaggedItem.objects.get(
tag='shiny', object_id=platypus.id tag='shiny', object_id=platypus.id
).id ).id
self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" value="shiny" maxlength="50" /></p> self.assertHTMLEqual(
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" value="%s" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p><p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50" /></p> ''.join(form.as_p() for form in formset.forms),
<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id" id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>""" % tagged_item_id) """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label>
<input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text"
name="generic_relations-taggeditem-content_type-object_id-0-tag" value="shiny" maxlength="50" /></p>
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label>
<input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE"
id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" />
<input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id"
value="%s" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>
<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label>
<input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text"
name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50" /></p>
<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label>
<input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE"
id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE" />
<input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id"
id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>""" % tagged_item_id
)
lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo") lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo")
formset = GenericFormSet(instance=lion, prefix='x') formset = GenericFormSet(instance=lion, prefix='x')
self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_x-0-tag">Tag:</label> <input id="id_x-0-tag" type="text" name="x-0-tag" maxlength="50" /></p> self.assertHTMLEqual(
<p><label for="id_x-0-DELETE">Delete:</label> <input type="checkbox" name="x-0-DELETE" id="id_x-0-DELETE" /><input type="hidden" name="x-0-id" id="id_x-0-id" /></p>""") ''.join(form.as_p() for form in formset.forms),
"""<p><label for="id_x-0-tag">Tag:</label>
<input id="id_x-0-tag" type="text" name="x-0-tag" maxlength="50" /></p>
<p><label for="id_x-0-DELETE">Delete:</label> <input type="checkbox" name="x-0-DELETE" id="id_x-0-DELETE" />
<input type="hidden" name="x-0-id" id="id_x-0-id" /></p>"""
)
def test_gfk_manager(self): def test_gfk_manager(self):
# GenericForeignKey should not use the default manager (which may filter objects) #16048 # GenericForeignKey should not use the default manager (which may filter objects) #16048

View File

@ -216,8 +216,14 @@ class YearArchiveViewTests(TestDataMixin, TestCase):
res = self.client.get('/dates/books/2006/sortedbyname/') res = self.client.get('/dates/books/2006/sortedbyname/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['date_list']), [datetime.date(2006, 5, 1), datetime.date(2006, 9, 1)]) self.assertEqual(list(res.context['date_list']), [datetime.date(2006, 5, 1), datetime.date(2006, 9, 1)])
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__year=2006).order_by('name'))) self.assertEqual(
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2006).order_by('name'))) list(res.context['book_list']),
list(Book.objects.filter(pubdate__year=2006).order_by('name'))
)
self.assertEqual(
list(res.context['object_list']),
list(Book.objects.filter(pubdate__year=2006).order_by('name'))
)
self.assertTemplateUsed(res, 'generic_views/book_archive_year.html') self.assertTemplateUsed(res, 'generic_views/book_archive_year.html')
def test_year_view_two_custom_sort_orders(self): def test_year_view_two_custom_sort_orders(self):
@ -225,9 +231,18 @@ class YearArchiveViewTests(TestDataMixin, TestCase):
Book.objects.create(name="Hunting Hippos", pages=400, pubdate=datetime.date(2006, 3, 1)) Book.objects.create(name="Hunting Hippos", pages=400, pubdate=datetime.date(2006, 3, 1))
res = self.client.get('/dates/books/2006/sortedbypageandnamedec/') res = self.client.get('/dates/books/2006/sortedbypageandnamedec/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['date_list']), [datetime.date(2006, 3, 1), datetime.date(2006, 5, 1), datetime.date(2006, 9, 1)]) self.assertEqual(
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__year=2006).order_by('pages', '-name'))) list(res.context['date_list']),
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2006).order_by('pages', '-name'))) [datetime.date(2006, 3, 1), datetime.date(2006, 5, 1), datetime.date(2006, 9, 1)]
)
self.assertEqual(
list(res.context['book_list']),
list(Book.objects.filter(pubdate__year=2006).order_by('pages', '-name'))
)
self.assertEqual(
list(res.context['object_list']),
list(Book.objects.filter(pubdate__year=2006).order_by('pages', '-name'))
)
self.assertTemplateUsed(res, 'generic_views/book_archive_year.html') self.assertTemplateUsed(res, 'generic_views/book_archive_year.html')
def test_year_view_invalid_pattern(self): def test_year_view_invalid_pattern(self):
@ -327,8 +342,14 @@ class MonthArchiveViewTests(TestDataMixin, TestCase):
def test_month_view_paginated(self): def test_month_view_paginated(self):
res = self.client.get('/dates/books/2008/oct/paginated/') res = self.client.get('/dates/books/2008/oct/paginated/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10))) self.assertEqual(
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10))) list(res.context['book_list']),
list(Book.objects.filter(pubdate__year=2008, pubdate__month=10))
)
self.assertEqual(
list(res.context['object_list']),
list(Book.objects.filter(pubdate__year=2008, pubdate__month=10))
)
self.assertTemplateUsed(res, 'generic_views/book_archive_month.html') self.assertTemplateUsed(res, 'generic_views/book_archive_month.html')
def test_custom_month_format(self): def test_custom_month_format(self):
@ -450,8 +471,14 @@ class WeekArchiveViewTests(TestDataMixin, TestCase):
week_end = week_start + datetime.timedelta(days=7) week_end = week_start + datetime.timedelta(days=7)
res = self.client.get('/dates/books/2008/week/39/') res = self.client.get('/dates/books/2008/week/39/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end))) self.assertEqual(
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end))) list(res.context['book_list']),
list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end))
)
self.assertEqual(
list(res.context['object_list']),
list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end))
)
self.assertTemplateUsed(res, 'generic_views/book_archive_week.html') self.assertTemplateUsed(res, 'generic_views/book_archive_week.html')
def test_week_view_invalid_pattern(self): def test_week_view_invalid_pattern(self):
@ -551,8 +578,14 @@ class DayArchiveViewTests(TestDataMixin, TestCase):
def test_day_view_paginated(self): def test_day_view_paginated(self):
res = self.client.get('/dates/books/2008/oct/1/') res = self.client.get('/dates/books/2008/oct/1/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10, pubdate__day=1))) self.assertEqual(
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10, pubdate__day=1))) list(res.context['book_list']),
list(Book.objects.filter(pubdate__year=2008, pubdate__month=10, pubdate__day=1))
)
self.assertEqual(
list(res.context['object_list']),
list(Book.objects.filter(pubdate__year=2008, pubdate__month=10, pubdate__day=1))
)
self.assertTemplateUsed(res, 'generic_views/book_archive_day.html') self.assertTemplateUsed(res, 'generic_views/book_archive_day.html')
def test_next_prev_context(self): def test_next_prev_context(self):

View File

@ -278,8 +278,11 @@ urlpatterns = [
url(r'^dates/books/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/byslug/(?P<slug>[\w-]+)/$', url(r'^dates/books/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/byslug/(?P<slug>[\w-]+)/$',
views.BookDetail.as_view()), views.BookDetail.as_view()),
url(r'^dates/books/get_object_custom_queryset/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/(?P<pk>[0-9]+)/$', url(
views.BookDetailGetObjectCustomQueryset.as_view()), r'^dates/books/get_object_custom_queryset/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/'
r'(?P<pk>[0-9]+)/$',
views.BookDetailGetObjectCustomQueryset.as_view(),
),
url(r'^dates/booksignings/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/(?P<pk>[0-9]+)/$', url(r'^dates/booksignings/(?P<year>[0-9]{4})/(?P<month>[a-z]{3})/(?P<day>[0-9]{1,2})/(?P<pk>[0-9]+)/$',
views.BookSigningDetail.as_view()), views.BookSigningDetail.as_view()),

View File

@ -430,7 +430,7 @@ ST_Distance(geom1, geom2, use_ellipsoid=True) | N/A | OK (
ST_Distance(geom1, geom2, use_ellipsoid=False) | N/A | OK (meters), less accurate, quick ST_Distance(geom1, geom2, use_ellipsoid=False) | N/A | OK (meters), less accurate, quick
''' ''' # NOQA
@skipUnlessDBFeature("gis_enabled") @skipUnlessDBFeature("gis_enabled")

View File

@ -180,7 +180,11 @@ class BasicExtractorTests(ExtractorTests):
# Comments in templates # Comments in templates
self.assertIn('#. Translators: This comment should be extracted', po_contents) self.assertIn('#. Translators: This comment should be extracted', po_contents)
self.assertIn("#. Translators: Django comment block for translators\n#. string's meaning unveiled", po_contents) self.assertIn(
"#. Translators: Django comment block for translators\n#. "
"string's meaning unveiled",
po_contents
)
self.assertIn('#. Translators: One-line translator comment #1', po_contents) self.assertIn('#. Translators: One-line translator comment #1', po_contents)
self.assertIn('#. Translators: Two-line translator comment #1\n#. continued here.', po_contents) self.assertIn('#. Translators: Two-line translator comment #1\n#. continued here.', po_contents)
self.assertIn('#. Translators: One-line translator comment #2', po_contents) self.assertIn('#. Translators: One-line translator comment #2', po_contents)
@ -189,8 +193,16 @@ class BasicExtractorTests(ExtractorTests):
self.assertIn('#. Translators: Two-line translator comment #3\n#. continued here.', po_contents) self.assertIn('#. Translators: Two-line translator comment #3\n#. continued here.', po_contents)
self.assertIn('#. Translators: One-line translator comment #4', po_contents) self.assertIn('#. Translators: One-line translator comment #4', po_contents)
self.assertIn('#. Translators: Two-line translator comment #4\n#. continued here.', po_contents) self.assertIn('#. Translators: Two-line translator comment #4\n#. continued here.', po_contents)
self.assertIn('#. Translators: One-line translator comment #5 -- with non ASCII characters: áéíóúö', po_contents) self.assertIn(
self.assertIn('#. Translators: Two-line translator comment #5 -- with non ASCII characters: áéíóúö\n#. continued here.', po_contents) '#. Translators: One-line translator comment #5 -- with '
'non ASCII characters: áéíóúö',
po_contents
)
self.assertIn(
'#. Translators: Two-line translator comment #5 -- with '
'non ASCII characters: áéíóúö\n#. continued here.',
po_contents
)
def test_blocktrans_trimmed(self): def test_blocktrans_trimmed(self):
os.chdir(self.test_dir) os.chdir(self.test_dir)
@ -212,13 +224,12 @@ class BasicExtractorTests(ExtractorTests):
def test_extraction_error(self): def test_extraction_error(self):
os.chdir(self.test_dir) os.chdir(self.test_dir)
self.assertRaises(SyntaxError, management.call_command, 'makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0) msg = (
with self.assertRaises(SyntaxError) as context_manager: 'Translation blocks must not include other block tags: blocktrans '
management.call_command('makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0) '(file %s, line 3)' % os.path.join('templates', 'template_with_error.tpl')
six.assertRegex(
self, str(context_manager.exception),
r'Translation blocks must not include other block tags: blocktrans \(file templates[/\\]template_with_error\.tpl, line 3\)'
) )
with self.assertRaisesMessage(SyntaxError, msg):
management.call_command('makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0)
# Check that the temporary file was cleaned up # Check that the temporary file was cleaned up
self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py')) self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py'))
@ -303,15 +314,21 @@ class BasicExtractorTests(ExtractorTests):
self.assertTrue(issubclass(w.category, TranslatorCommentWarning)) self.assertTrue(issubclass(w.category, TranslatorCommentWarning))
six.assertRegex( six.assertRegex(
self, str(ws[0].message), self, str(ws[0].message),
r"The translator-targeted comment 'Translators: ignored i18n comment #1' \(file templates[/\\]comments.thtml, line 4\) was ignored, because it wasn't the last item on the line\." r"The translator-targeted comment 'Translators: ignored i18n "
r"comment #1' \(file templates[/\\]comments.thtml, line 4\) "
r"was ignored, because it wasn't the last item on the line\."
) )
six.assertRegex( six.assertRegex(
self, str(ws[1].message), self, str(ws[1].message),
r"The translator-targeted comment 'Translators: ignored i18n comment #3' \(file templates[/\\]comments.thtml, line 6\) was ignored, because it wasn't the last item on the line\." r"The translator-targeted comment 'Translators: ignored i18n "
r"comment #3' \(file templates[/\\]comments.thtml, line 6\) "
r"was ignored, because it wasn't the last item on the line\."
) )
six.assertRegex( six.assertRegex(
self, str(ws[2].message), self, str(ws[2].message),
r"The translator-targeted comment 'Translators: ignored i18n comment #4' \(file templates[/\\]comments.thtml, line 8\) was ignored, because it wasn't the last item on the line\." r"The translator-targeted comment 'Translators: ignored i18n "
r"comment #4' \(file templates[/\\]comments.thtml, line 8\) "
"was ignored, because it wasn't the last item on the line\."
) )
# Now test .po file contents # Now test .po file contents
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
@ -581,7 +598,11 @@ class NoWrapExtractorTests(ExtractorTests):
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
po_contents = force_text(fp.read()) po_contents = force_text(fp.read())
self.assertMsgId('This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option.', po_contents) self.assertMsgId(
'This literal should also be included wrapped or not wrapped '
'depending on the use of the --no-wrap option.',
po_contents
)
def test_no_wrap_disabled(self): def test_no_wrap_disabled(self):
os.chdir(self.test_dir) os.chdir(self.test_dir)
@ -589,7 +610,12 @@ class NoWrapExtractorTests(ExtractorTests):
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
po_contents = force_text(fp.read()) po_contents = force_text(fp.read())
self.assertMsgId('""\n"This literal should also be included wrapped or not wrapped depending on the "\n"use of the --no-wrap option."', po_contents, use_quotes=False) self.assertMsgId(
'""\n"This literal should also be included wrapped or not '
'wrapped depending on the "\n"use of the --no-wrap option."',
po_contents,
use_quotes=False
)
class LocationCommentsTests(ExtractorTests): class LocationCommentsTests(ExtractorTests):

View File

@ -181,11 +181,21 @@ class TranslationTests(SimpleTestCase):
self.assertEqual(simple_without_format % 4, 'guten Resultate') self.assertEqual(simple_without_format % 4, 'guten Resultate')
complex_nonlazy = ungettext_lazy('Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4) complex_nonlazy = ungettext_lazy('Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4)
complex_deferred = ungettext_lazy('Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num') complex_deferred = ungettext_lazy(
complex_str_nonlazy = ngettext_lazy(str('Hi %(name)s, %(num)d good result'), str('Hi %(name)s, %(num)d good results'), 4) 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num'
complex_str_deferred = ngettext_lazy(str('Hi %(name)s, %(num)d good result'), str('Hi %(name)s, %(num)d good results'), 'num') )
complex_context_nonlazy = npgettext_lazy('Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4) complex_str_nonlazy = ngettext_lazy(
complex_context_deferred = npgettext_lazy('Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num') str('Hi %(name)s, %(num)d good result'), str('Hi %(name)s, %(num)d good results'), 4
)
complex_str_deferred = ngettext_lazy(
str('Hi %(name)s, %(num)d good result'), str('Hi %(name)s, %(num)d good results'), 'num'
)
complex_context_nonlazy = npgettext_lazy(
'Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4
)
complex_context_deferred = npgettext_lazy(
'Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num'
)
with translation.override('de'): with translation.override('de'):
self.assertEqual(complex_nonlazy % {'num': 4, 'name': 'Jim'}, 'Hallo Jim, 4 guten Resultate') self.assertEqual(complex_nonlazy % {'num': 4, 'name': 'Jim'}, 'Hallo Jim, 4 guten Resultate')
self.assertEqual(complex_deferred % {'name': 'Jim', 'num': 1}, 'Hallo Jim, 1 gutes Resultat') self.assertEqual(complex_deferred % {'name': 'Jim', 'num': 1}, 'Hallo Jim, 1 gutes Resultat')
@ -311,42 +321,76 @@ class TranslationTests(SimpleTestCase):
self.assertEqual(rendered, 'Kann') self.assertEqual(rendered, 'Kann')
# Using 'count' # Using 'count'
t = Template('{% load i18n %}{% blocktrans count number=1 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans count number=1 context "super search" %}'
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, '1 Super-Ergebnis') self.assertEqual(rendered, '1 Super-Ergebnis')
t = Template('{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans count number=2 context "super search" %}{{ number }}'
' super result{% plural %}{{ number }} super results{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, '2 Super-Ergebnisse') self.assertEqual(rendered, '2 Super-Ergebnisse')
t = Template('{% load i18n %}{% blocktrans context "other super search" count number=1 %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans context "other super search" count number=1 %}'
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, '1 anderen Super-Ergebnis') self.assertEqual(rendered, '1 anderen Super-Ergebnis')
t = Template('{% load i18n %}{% blocktrans context "other super search" count number=2 %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans context "other super search" count number=2 %}'
'{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, '2 andere Super-Ergebnisse') self.assertEqual(rendered, '2 andere Super-Ergebnisse')
# Using 'with' # Using 'with'
t = Template('{% load i18n %}{% blocktrans with num_comments=5 context "comment count" %}There are {{ num_comments }} comments{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" %}'
'There are {{ num_comments }} comments{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, 'Es gibt 5 Kommentare') self.assertEqual(rendered, 'Es gibt 5 Kommentare')
t = Template('{% load i18n %}{% blocktrans with num_comments=5 context "other comment count" %}There are {{ num_comments }} comments{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans with num_comments=5 context "other comment count" %}'
'There are {{ num_comments }} comments{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare') self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare')
# Using trimmed # Using trimmed
t = Template('{% load i18n %}{% blocktrans trimmed %}\n\nThere\n\t are 5 \n\n comments\n{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans trimmed %}\n\nThere\n\t are 5 '
'\n\n comments\n{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, 'There are 5 comments') self.assertEqual(rendered, 'There are 5 comments')
t = Template('{% load i18n %}{% blocktrans with num_comments=5 context "comment count" trimmed %}\n\nThere are \t\n \t {{ num_comments }} comments\n\n{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans with num_comments=5 context "comment count" trimmed %}\n\n'
'There are \t\n \t {{ num_comments }} comments\n\n{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, 'Es gibt 5 Kommentare') self.assertEqual(rendered, 'Es gibt 5 Kommentare')
t = Template('{% load i18n %}{% blocktrans context "other super search" count number=2 trimmed %}\n{{ number }} super \n result{% plural %}{{ number }} super results{% endblocktrans %}') t = Template(
'{% load i18n %}{% blocktrans context "other super search" count number=2 trimmed %}\n'
'{{ number }} super \n result{% plural %}{{ number }} super results{% endblocktrans %}'
)
rendered = t.render(Context()) rendered = t.render(Context())
self.assertEqual(rendered, '2 andere Super-Ergebnisse') self.assertEqual(rendered, '2 andere Super-Ergebnisse')
# Mis-uses # Mis-uses
self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}') with self.assertRaises(TemplateSyntaxError):
self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context %}{% endblocktrans %}') Template('{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}')
self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans count number=2 context %}{{ number }} super result{% plural %}{{ number }} super results{% endblocktrans %}') with self.assertRaises(TemplateSyntaxError):
Template('{% load i18n %}{% blocktrans context %}{% endblocktrans %}')
with self.assertRaises(TemplateSyntaxError):
Template(
'{% load i18n %}{% blocktrans count number=2 context %}'
'{{ number }} super result{% plural %}{{ number }}'
' super results{% endblocktrans %}'
)
def test_string_concat(self): def test_string_concat(self):
""" """
@ -496,8 +540,14 @@ class FormattingTests(SimpleTestCase):
self.assertEqual('66666', nformat(self.n, decimal_sep='X', decimal_pos=0, grouping=1, thousand_sep='Y')) self.assertEqual('66666', nformat(self.n, decimal_sep='X', decimal_pos=0, grouping=1, thousand_sep='Y'))
with self.settings(USE_THOUSAND_SEPARATOR=True): with self.settings(USE_THOUSAND_SEPARATOR=True):
self.assertEqual('66,666.66', nformat(self.n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',')) self.assertEqual(
self.assertEqual('6B6B6B6B6A6', nformat(self.n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B')) '66,666.66',
nformat(self.n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',')
)
self.assertEqual(
'6B6B6B6B6A6',
nformat(self.n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B')
)
self.assertEqual('-66666.6', nformat(-66666.666, decimal_sep='.', decimal_pos=1)) self.assertEqual('-66666.6', nformat(-66666.666, decimal_sep='.', decimal_pos=1))
self.assertEqual('-66666.0', nformat(int('-66666'), decimal_sep='.', decimal_pos=1)) self.assertEqual('-66666.0', nformat(int('-66666'), decimal_sep='.', decimal_pos=1))
self.assertEqual('10000.0', nformat(self.l, decimal_sep='.', decimal_pos=1)) self.assertEqual('10000.0', nformat(self.l, decimal_sep='.', decimal_pos=1))
@ -537,7 +587,9 @@ class FormattingTests(SimpleTestCase):
self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt)) self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
self.assertEqual('10:15 a.m.', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt)) self.assertEqual('10:15 a.m.', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt))
self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
self.assertEqual('12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)) self.assertEqual(
'12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)
)
form = I18nForm({ form = I18nForm({
'decimal_field': '66666,666', 'decimal_field': '66666,666',
@ -562,7 +614,68 @@ class FormattingTests(SimpleTestCase):
self.assertTrue(form2.is_valid()) self.assertTrue(form2.is_valid())
self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field']) self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field'])
self.assertHTMLEqual( self.assertHTMLEqual(
'<select name="mydate_month" id="id_mydate_month">\n<option value="0">---</option>\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="0">---</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="0">---</option>\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>', '<select name="mydate_month" id="id_mydate_month">'
'<option value="0">---</option>'
'<option value="1">gener</option>'
'<option value="2">febrer</option>'
'<option value="3">mar\xe7</option>'
'<option value="4">abril</option>'
'<option value="5">maig</option>'
'<option value="6">juny</option>'
'<option value="7">juliol</option>'
'<option value="8">agost</option>'
'<option value="9">setembre</option>'
'<option value="10">octubre</option>'
'<option value="11">novembre</option>'
'<option value="12" selected="selected">desembre</option>'
'</select>'
'<select name="mydate_day" id="id_mydate_day">'
'<option value="0">---</option>'
'<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" selected="selected">31</option>'
'</select>'
'<select name="mydate_year" id="id_mydate_year">'
'<option value="0">---</option>'
'<option value="2009" selected="selected">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>'
'<option value="2017">2017</option>'
'<option value="2018">2018</option>'
'</select>',
forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
) )
@ -651,7 +764,10 @@ class FormattingTests(SimpleTestCase):
self.assertEqual('100000,0', Template('{{ f|floatformat }}').render(self.ctxt)) self.assertEqual('100000,0', Template('{{ f|floatformat }}').render(self.ctxt))
self.assertEqual('10:15', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt)) self.assertEqual('10:15', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt))
self.assertEqual('31/12/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual('31/12/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
self.assertEqual('31/12/2009 20:50', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)) self.assertEqual(
'31/12/2009 20:50',
Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)
)
self.assertEqual(date_format(datetime.datetime.now(), "DATE_FORMAT"), self.assertEqual(date_format(datetime.datetime.now(), "DATE_FORMAT"),
Template('{% now "DATE_FORMAT" %}').render(self.ctxt)) Template('{% now "DATE_FORMAT" %}').render(self.ctxt))
@ -680,14 +796,136 @@ class FormattingTests(SimpleTestCase):
self.assertTrue(form5.is_valid()) self.assertTrue(form5.is_valid())
self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field']) self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field'])
self.assertHTMLEqual( self.assertHTMLEqual(
'<select name="mydate_day" id="id_mydate_day">\n<option value="0">---</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_month" id="id_mydate_month">\n<option value="0">---</option>\n<option value="1">gener</option>\n<option value="2">febrer</option>\n<option value="3">mar\xe7</option>\n<option value="4">abril</option>\n<option value="5">maig</option>\n<option value="6">juny</option>\n<option value="7">juliol</option>\n<option value="8">agost</option>\n<option value="9">setembre</option>\n<option value="10">octubre</option>\n<option value="11">novembre</option>\n<option value="12" selected="selected">desembre</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="0">---</option>\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>', '<select name="mydate_day" id="id_mydate_day">'
'<option value="0">---</option>'
'<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" selected="selected">31</option>'
'</select>'
'<select name="mydate_month" id="id_mydate_month">'
'<option value="0">---</option>'
'<option value="1">gener</option>'
'<option value="2">febrer</option>'
'<option value="3">mar\xe7</option>'
'<option value="4">abril</option>'
'<option value="5">maig</option>'
'<option value="6">juny</option>'
'<option value="7">juliol</option>'
'<option value="8">agost</option>'
'<option value="9">setembre</option>'
'<option value="10">octubre</option>'
'<option value="11">novembre</option>'
'<option value="12" selected="selected">desembre</option>'
'</select>'
'<select name="mydate_year" id="id_mydate_year">'
'<option value="0">---</option>'
'<option value="2009" selected="selected">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>'
'<option value="2017">2017</option>'
'<option value="2018">2018</option>'
'</select>',
forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
) )
# Russian locale (with E as month) # Russian locale (with E as month)
with translation.override('ru', deactivate=True): with translation.override('ru', deactivate=True):
self.assertHTMLEqual( self.assertHTMLEqual(
'<select name="mydate_day" id="id_mydate_day">\n<option value="0">---</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_month" id="id_mydate_month">\n<option value="0">---</option>\n<option value="1">\u042f\u043d\u0432\u0430\u0440\u044c</option>\n<option value="2">\u0424\u0435\u0432\u0440\u0430\u043b\u044c</option>\n<option value="3">\u041c\u0430\u0440\u0442</option>\n<option value="4">\u0410\u043f\u0440\u0435\u043b\u044c</option>\n<option value="5">\u041c\u0430\u0439</option>\n<option value="6">\u0418\u044e\u043d\u044c</option>\n<option value="7">\u0418\u044e\u043b\u044c</option>\n<option value="8">\u0410\u0432\u0433\u0443\u0441\u0442</option>\n<option value="9">\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c</option>\n<option value="10">\u041e\u043a\u0442\u044f\u0431\u0440\u044c</option>\n<option value="11">\u041d\u043e\u044f\u0431\u0440\u044c</option>\n<option value="12" selected="selected">\u0414\u0435\u043a\u0430\u0431\u0440\u044c</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="0">---</option>\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>', '<select name="mydate_day" id="id_mydate_day">'
'<option value="0">---</option>'
'<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" selected="selected">31</option>'
'</select>'
'<select name="mydate_month" id="id_mydate_month">'
'<option value="0">---</option>'
'<option value="1">\u042f\u043d\u0432\u0430\u0440\u044c</option>'
'<option value="2">\u0424\u0435\u0432\u0440\u0430\u043b\u044c</option>'
'<option value="3">\u041c\u0430\u0440\u0442</option>'
'<option value="4">\u0410\u043f\u0440\u0435\u043b\u044c</option>'
'<option value="5">\u041c\u0430\u0439</option>'
'<option value="6">\u0418\u044e\u043d\u044c</option>'
'<option value="7">\u0418\u044e\u043b\u044c</option>'
'<option value="8">\u0410\u0432\u0433\u0443\u0441\u0442</option>'
'<option value="9">\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c</option>'
'<option value="10">\u041e\u043a\u0442\u044f\u0431\u0440\u044c</option>'
'<option value="11">\u041d\u043e\u044f\u0431\u0440\u044c</option>'
'<option value="12" selected="selected">\u0414\u0435\u043a\u0430\u0431\u0440\u044c</option>'
'</select>'
'<select name="mydate_year" id="id_mydate_year">'
'<option value="0">---</option>'
'<option value="2009" selected="selected">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>'
'<option value="2017">2017</option>'
'<option value="2018">2018</option>'
'</select>',
forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
) )
@ -726,7 +964,10 @@ class FormattingTests(SimpleTestCase):
self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt)) self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt)) self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
self.assertEqual('12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)) self.assertEqual(
'12/31/2009 8:50 p.m.',
Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt)
)
form5 = I18nForm({ form5 = I18nForm({
'decimal_field': '66666.666', 'decimal_field': '66666.666',
@ -752,7 +993,68 @@ class FormattingTests(SimpleTestCase):
self.assertTrue(form6.is_valid()) self.assertTrue(form6.is_valid())
self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field']) self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
self.assertHTMLEqual( self.assertHTMLEqual(
'<select name="mydate_month" id="id_mydate_month">\n<option value="0">---</option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12" selected="selected">December</option>\n</select>\n<select name="mydate_day" id="id_mydate_day">\n<option value="0">---</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31" selected="selected">31</option>\n</select>\n<select name="mydate_year" id="id_mydate_year">\n<option value="0">---</option>\n<option value="2009" selected="selected">2009</option>\n<option value="2010">2010</option>\n<option value="2011">2011</option>\n<option value="2012">2012</option>\n<option value="2013">2013</option>\n<option value="2014">2014</option>\n<option value="2015">2015</option>\n<option value="2016">2016</option>\n<option value="2017">2017</option>\n<option value="2018">2018</option>\n</select>', '<select name="mydate_month" id="id_mydate_month">'
'<option value="0">---</option>'
'<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" selected="selected">December</option>'
'</select>'
'<select name="mydate_day" id="id_mydate_day">'
'<option value="0">---</option>'
'<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" selected="selected">31</option>'
'</select>'
'<select name="mydate_year" id="id_mydate_year">'
'<option value="0">---</option>'
'<option value="2009" selected="selected">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>'
'<option value="2017">2017</option>'
'<option value="2018">2018</option>'
'</select>',
forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31))
) )
@ -781,13 +1083,23 @@ class FormattingTests(SimpleTestCase):
self.assertTrue(form6.is_valid()) self.assertTrue(form6.is_valid())
self.assertHTMLEqual( self.assertHTMLEqual(
form6.as_ul(), form6.as_ul(),
'<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="acme" maxlength="50" /></li>\n<li><label for="id_date_added">Date added:</label> <input type="text" name="date_added" value="31.12.2009 06:00:00" id="id_date_added" /></li>\n<li><label for="id_cents_paid">Cents paid:</label> <input type="text" name="cents_paid" value="59,47" id="id_cents_paid" /></li>\n<li><label for="id_products_delivered">Products delivered:</label> <input type="text" name="products_delivered" value="12000" id="id_products_delivered" /></li>' '<li><label for="id_name">Name:</label>'
'<input id="id_name" type="text" name="name" value="acme" maxlength="50" /></li>'
'<li><label for="id_date_added">Date added:</label>'
'<input type="text" name="date_added" value="31.12.2009 06:00:00" id="id_date_added" /></li>'
'<li><label for="id_cents_paid">Cents paid:</label>'
'<input type="text" name="cents_paid" value="59,47" id="id_cents_paid" /></li>'
'<li><label for="id_products_delivered">Products delivered:</label>'
'<input type="text" name="products_delivered" value="12000" id="id_products_delivered" /></li>'
) )
self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00') self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00')
self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added']) self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
with self.settings(USE_THOUSAND_SEPARATOR=True): with self.settings(USE_THOUSAND_SEPARATOR=True):
# Checking for the localized "products_delivered" field # Checking for the localized "products_delivered" field
self.assertInHTML('<input type="text" name="products_delivered" value="12.000" id="id_products_delivered" />', form6.as_ul()) self.assertInHTML(
'<input type="text" name="products_delivered" value="12.000" id="id_products_delivered" />',
form6.as_ul()
)
def test_sanitize_separators(self): def test_sanitize_separators(self):
""" """
@ -864,7 +1176,10 @@ class FormattingTests(SimpleTestCase):
Tests the {% localize %} templatetag Tests the {% localize %} templatetag
""" """
context = Context({'value': 3.14}) context = Context({'value': 3.14})
template1 = Template("{% load l10n %}{% localize %}{{ value }}{% endlocalize %};{% localize on %}{{ value }}{% endlocalize %}") template1 = Template(
'{% load l10n %}{% localize %}{{ value }}{% endlocalize %};'
'{% localize on %}{{ value }}{% endlocalize %}'
)
template2 = Template("{% load l10n %}{{ value }};{% localize off %}{{ value }};{% endlocalize %}{{ value }}") template2 = Template("{% load l10n %}{{ value }};{% localize off %}{{ value }};{% endlocalize %}{{ value }}")
template3 = Template('{% load l10n %}{{ value }};{{ value|unlocalize }}') template3 = Template('{% load l10n %}{{ value }};{{ value|unlocalize }}')
template4 = Template('{% load l10n %}{{ value }};{{ value|localize }}') template4 = Template('{% load l10n %}{{ value }};{{ value|localize }}')
@ -890,7 +1205,9 @@ class FormattingTests(SimpleTestCase):
with translation.override('de-at', deactivate=True): with translation.override('de-at', deactivate=True):
template = Template('{% load l10n %}{{ form.date_added }}; {{ form.cents_paid }}') template = Template('{% load l10n %}{{ form.date_added }}; {{ form.cents_paid }}')
template_as_text = Template('{% load l10n %}{{ form.date_added.as_text }}; {{ form.cents_paid.as_text }}') template_as_text = Template('{% load l10n %}{{ form.date_added.as_text }}; {{ form.cents_paid.as_text }}')
template_as_hidden = Template('{% load l10n %}{{ form.date_added.as_hidden }}; {{ form.cents_paid.as_hidden }}') template_as_hidden = Template(
'{% load l10n %}{{ form.date_added.as_hidden }}; {{ form.cents_paid.as_hidden }}'
)
form = CompanyForm({ form = CompanyForm({
'name': 'acme', 'name': 'acme',
'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0), 'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0),
@ -902,15 +1219,18 @@ class FormattingTests(SimpleTestCase):
self.assertHTMLEqual( self.assertHTMLEqual(
template.render(context), template.render(context),
'<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />' '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />;'
'<input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />'
) )
self.assertHTMLEqual( self.assertHTMLEqual(
template_as_text.render(context), template_as_text.render(context),
'<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />' '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" />;'
' <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" />'
) )
self.assertHTMLEqual( self.assertHTMLEqual(
template_as_hidden.render(context), template_as_hidden.render(context),
'<input id="id_date_added" name="date_added" type="hidden" value="31.12.2009 06:00:00" />; <input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47" />' '<input id="id_date_added" name="date_added" type="hidden" value="31.12.2009 06:00:00" />;'
'<input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47" />'
) )
@ -952,7 +1272,10 @@ class MiscTests(SimpleTestCase):
self.assertEqual([('en-au', 1.0)], p('en-au;q=1.0')) self.assertEqual([('en-au', 1.0)], p('en-au;q=1.0'))
self.assertEqual([('da', 1.0), ('en', 0.5), ('en-gb', 0.25)], p('da, en-gb;q=0.25, en;q=0.5')) self.assertEqual([('da', 1.0), ('en', 0.5), ('en-gb', 0.25)], p('da, en-gb;q=0.25, en;q=0.5'))
self.assertEqual([('en-au-xx', 1.0)], p('en-au-xx')) self.assertEqual([('en-au-xx', 1.0)], p('en-au-xx'))
self.assertEqual([('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)], p('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125')) self.assertEqual(
[('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)],
p('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125')
)
self.assertEqual([('*', 1.0)], p('*')) self.assertEqual([('*', 1.0)], p('*'))
self.assertEqual([('de', 1.0)], p('de;q=0.')) self.assertEqual([('de', 1.0)], p('de;q=0.'))
self.assertEqual([('en', 1.0), ('*', 0.5)], p('en; q=1.0, * ; q=0.5')) self.assertEqual([('en', 1.0), ('*', 0.5)], p('en; q=1.0, * ; q=0.5'))
@ -966,7 +1289,10 @@ class MiscTests(SimpleTestCase):
self.assertEqual([], p('**')) self.assertEqual([], p('**'))
self.assertEqual([], p('en,,gb')) self.assertEqual([], p('en,,gb'))
self.assertEqual([], p('en-au;q=0.1.0')) self.assertEqual([], p('en-au;q=0.1.0'))
self.assertEqual([], p('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZ,en')) self.assertEqual(
[],
p('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZ,en')
)
self.assertEqual([], p('da, en-gb;q=0.8, en;q=0.7,#')) self.assertEqual([], p('da, en-gb;q=0.8, en;q=0.7,#'))
self.assertEqual([], p('de;q=2.0')) self.assertEqual([], p('de;q=2.0'))
self.assertEqual([], p('de;q=0.a')) self.assertEqual([], p('de;q=0.a'))
@ -1110,7 +1436,11 @@ class MiscTests(SimpleTestCase):
@override_settings(LOCALE_PATHS=extended_locale_paths) @override_settings(LOCALE_PATHS=extended_locale_paths)
def test_percent_in_translatable_block(self): def test_percent_in_translatable_block(self):
t_sing = Template("{% load i18n %}{% blocktrans %}The result was {{ percent }}%{% endblocktrans %}") t_sing = Template("{% load i18n %}{% blocktrans %}The result was {{ percent }}%{% endblocktrans %}")
t_plur = Template("{% load i18n %}{% blocktrans count num as number %}{{ percent }}% represents {{ num }} object{% plural %}{{ percent }}% represents {{ num }} objects{% endblocktrans %}") t_plur = Template(
"{% load i18n %}{% blocktrans count num as number %}"
"{{ percent }}% represents {{ num }} object{% plural %}"
"{{ percent }}% represents {{ num }} objects{% endblocktrans %}"
)
with translation.override('de'): with translation.override('de'):
self.assertEqual(t_sing.render(Context({'percent': 42})), 'Das Ergebnis war 42%') self.assertEqual(t_sing.render(Context({'percent': 42})), 'Das Ergebnis war 42%')
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '42% stellt 1 Objekt dar') self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '42% stellt 1 Objekt dar')
@ -1123,7 +1453,11 @@ class MiscTests(SimpleTestCase):
singular or plural singular or plural
""" """
t_sing = Template("{% load i18n %}{% blocktrans %}There are %(num_comments)s comments{% endblocktrans %}") t_sing = Template("{% load i18n %}{% blocktrans %}There are %(num_comments)s comments{% endblocktrans %}")
t_plur = Template("{% load i18n %}{% blocktrans count num as number %}%(percent)s% represents {{ num }} object{% plural %}%(percent)s% represents {{ num }} objects{% endblocktrans %}") t_plur = Template(
"{% load i18n %}{% blocktrans count num as number %}"
"%(percent)s% represents {{ num }} object{% plural %}"
"%(percent)s% represents {{ num }} objects{% endblocktrans %}"
)
with translation.override('de'): with translation.override('de'):
# Strings won't get translated as they don't match after escaping % # Strings won't get translated as they don't match after escaping %
self.assertEqual(t_sing.render(Context({'num_comments': 42})), 'There are %(num_comments)s comments') self.assertEqual(t_sing.render(Context({'num_comments': 42})), 'There are %(num_comments)s comments')
@ -1265,7 +1599,10 @@ class MultipleLocaleActivationTests(SimpleTestCase):
with translation.override('fr'): with translation.override('fr'):
self.assertEqual(Template("{{ _('Yes') }}").render(Context({})), 'Oui') self.assertEqual(Template("{{ _('Yes') }}").render(Context({})), 'Oui')
self.assertEqual(Template("{% load i18n %}{% trans 'Yes' %}").render(Context({})), 'Oui') self.assertEqual(Template("{% load i18n %}{% trans 'Yes' %}").render(Context({})), 'Oui')
self.assertEqual(Template("{% load i18n %}{% blocktrans %}Yes{% endblocktrans %}").render(Context({})), 'Oui') self.assertEqual(
Template("{% load i18n %}{% blocktrans %}Yes{% endblocktrans %}").render(Context({})),
'Oui'
)
# Literal marked up with _() in a filter expression # Literal marked up with _() in a filter expression

View File

@ -234,7 +234,10 @@ class InspectDBTestCase(TestCase):
table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'), table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'),
stdout=out) stdout=out)
output = out.getvalue() output = out.getvalue()
self.assertIn(" unique_together = (('field1', 'field2'),)", output, msg='inspectdb should generate unique_together.') self.assertIn(
" unique_together = (('field1', 'field2'),)", output,
msg='inspectdb should generate unique_together.'
)
@skipUnless(connection.vendor == 'sqlite', @skipUnless(connection.vendor == 'sqlite',
"Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test") "Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")

View File

@ -138,9 +138,13 @@ class IntrospectionTests(TransactionTestCase):
def test_get_relations_alt_format(self): def test_get_relations_alt_format(self):
"""With SQLite, foreign keys can be added with different syntaxes.""" """With SQLite, foreign keys can be added with different syntaxes."""
with connection.cursor() as cursor: with connection.cursor() as cursor:
cursor.fetchone = mock.Mock(return_value=[ cursor.fetchone = mock.Mock(
"CREATE TABLE track(id, art_id INTEGER, FOREIGN KEY(art_id) REFERENCES %s(id));" % Article._meta.db_table return_value=[
]) "CREATE TABLE track(id, art_id INTEGER, FOREIGN KEY(art_id) REFERENCES {}(id));".format(
Article._meta.db_table
)
]
)
relations = connection.introspection.get_relations(cursor, 'mocked_table') relations = connection.introspection.get_relations(cursor, 'mocked_table')
self.assertEqual(relations, {'art_id': ('id', Article._meta.db_table)}) self.assertEqual(relations, {'art_id': ('id', Article._meta.db_table)})

View File

@ -357,7 +357,10 @@ class RelativeFieldTests(IsolatedModelsTestCase):
self.assertEqual(errors, expected) self.assertEqual(errors, expected)
def test_symmetric_self_reference_with_intermediate_table_and_through_fields(self): def test_symmetric_self_reference_with_intermediate_table_and_through_fields(self):
"""Using through_fields in a m2m with an intermediate model shouldn't mask its incompatibility with symmetry.""" """
Using through_fields in a m2m with an intermediate model shouldn't
mask its incompatibility with symmetry.
"""
class Person(models.Model): class Person(models.Model):
# Explicit symmetrical=True. # Explicit symmetrical=True.
friends = models.ManyToManyField('self', friends = models.ManyToManyField('self',
@ -394,8 +397,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
errors = field.check() errors = field.check()
expected = [ expected = [
Error( Error(
("Field defines a relation with model 'AbstractModel', " "Field defines a relation with model 'AbstractModel', "
"which is either not installed, or is abstract."), "which is either not installed, or is abstract.",
hint=None, hint=None,
obj=field, obj=field,
id='fields.E300', id='fields.E300',
@ -415,8 +418,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
errors = field.check(from_model=Model) errors = field.check(from_model=Model)
expected = [ expected = [
Error( Error(
("Field defines a relation with model 'AbstractModel', " "Field defines a relation with model 'AbstractModel', "
"which is either not installed, or is abstract."), "which is either not installed, or is abstract.",
hint=None, hint=None,
obj=field, obj=field,
id='fields.E300', id='fields.E300',
@ -500,8 +503,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
errors = field.check() errors = field.check()
expected = [ expected = [
Error( Error(
("None of the fields 'country_id', 'city_id' on model 'Person' " "None of the fields 'country_id', 'city_id' on model 'Person' "
"have a unique=True constraint."), "have a unique=True constraint.",
hint=None, hint=None,
obj=field, obj=field,
id='fields.E310', id='fields.E310',
@ -1333,7 +1336,11 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
pass pass
class Event(models.Model): class Event(models.Model):
invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('invalid_field_1', 'invalid_field_2')) invitees = models.ManyToManyField(
Fan,
through='Invitation',
through_fields=('invalid_field_1', 'invalid_field_2'),
)
class Invitation(models.Model): class Invitation(models.Model):
event = models.ForeignKey(Event, models.CASCADE) event = models.ForeignKey(Event, models.CASCADE)
@ -1344,12 +1351,12 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
errors = field.check(from_model=Event) errors = field.check(from_model=Event)
expected = [ expected = [
Error( Error(
("The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_1'."), "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_1'.",
hint="Did you mean one of the following foreign keys to 'Event': event?", hint="Did you mean one of the following foreign keys to 'Event': event?",
obj=field, obj=field,
id='fields.E338'), id='fields.E338'),
Error( Error(
("The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_2'."), "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_2'.",
hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?", hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?",
obj=field, obj=field,
id='fields.E338'), id='fields.E338'),
@ -1376,9 +1383,9 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
errors = field.check(from_model=Event) errors = field.check(from_model=Event)
expected = [ expected = [
Error( Error(
("Field specifies 'through_fields' but does not provide the names " "Field specifies 'through_fields' but does not provide the names "
"of the two link fields that should be used for the relation " "of the two link fields that should be used for the relation "
"through model 'invalid_models_tests.Invitation'."), "through model 'invalid_models_tests.Invitation'.",
hint=("Make sure you specify 'through_fields' as " hint=("Make sure you specify 'through_fields' as "
"through_fields=('field1', 'field2')"), "through_fields=('field1', 'field2')"),
obj=field, obj=field,

View File

@ -229,7 +229,11 @@ class LookupTests(TestCase):
{'name': self.au2.name, 'article__headline': self.a7.headline}, {'name': self.au2.name, 'article__headline': self.a7.headline},
], transform=identity) ], transform=identity)
self.assertQuerysetEqual( self.assertQuerysetEqual(
Author.objects.values('name', 'article__headline', 'article__tag__name').order_by('name', 'article__headline', 'article__tag__name'), (
Author.objects
.values('name', 'article__headline', 'article__tag__name')
.order_by('name', 'article__headline', 'article__tag__name')
),
[ [
{'name': self.au1.name, 'article__headline': self.a1.headline, 'article__tag__name': self.t1.name}, {'name': self.au1.name, 'article__headline': self.a1.headline, 'article__tag__name': self.t1.name},
{'name': self.au1.name, 'article__headline': self.a2.headline, 'article__tag__name': self.t1.name}, {'name': self.au1.name, 'article__headline': self.a2.headline, 'article__tag__name': self.t1.name},
@ -311,7 +315,11 @@ class LookupTests(TestCase):
], ],
transform=identity) transform=identity)
self.assertQuerysetEqual( self.assertQuerysetEqual(
Author.objects.values_list('name', 'article__headline', 'article__tag__name').order_by('name', 'article__headline', 'article__tag__name'), (
Author.objects
.values_list('name', 'article__headline', 'article__tag__name')
.order_by('name', 'article__headline', 'article__tag__name')
),
[ [
(self.au1.name, self.a1.headline, self.t1.name), (self.au1.name, self.a1.headline, self.t1.name),
(self.au1.name, self.a2.headline, self.t1.name), (self.au1.name, self.a2.headline, self.t1.name),

View File

@ -21,7 +21,11 @@ class Group(models.Model):
name = models.CharField(max_length=128) name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership') members = models.ManyToManyField(Person, through='Membership')
custom_members = models.ManyToManyField(Person, through='CustomMembership', related_name="custom") custom_members = models.ManyToManyField(Person, through='CustomMembership', related_name="custom")
nodefaultsnonulls = models.ManyToManyField(Person, through='TestNoDefaultsOrNulls', related_name="testnodefaultsnonulls") nodefaultsnonulls = models.ManyToManyField(
Person,
through='TestNoDefaultsOrNulls',
related_name="testnodefaultsnonulls",
)
class Meta: class Meta:
ordering = ('name',) ordering = ('name',)
@ -88,7 +92,11 @@ class Friendship(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class Event(models.Model): class Event(models.Model):
title = models.CharField(max_length=50) title = models.CharField(max_length=50)
invitees = models.ManyToManyField(Person, through='Invitation', through_fields=('event', 'invitee'), related_name='events_invited') invitees = models.ManyToManyField(
Person, through='Invitation',
through_fields=('event', 'invitee'),
related_name='events_invited',
)
def __str__(self): def __str__(self):
return self.title return self.title
@ -104,7 +112,12 @@ class Invitation(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class Employee(models.Model): class Employee(models.Model):
name = models.CharField(max_length=5) name = models.CharField(max_length=5)
subordinates = models.ManyToManyField('self', through="Relationship", through_fields=('source', 'target'), symmetrical=False) subordinates = models.ManyToManyField(
'self',
through="Relationship",
through_fields=('source', 'target'),
symmetrical=False,
)
class Meta: class Meta:
ordering = ('pk',) ordering = ('pk',)

View File

@ -105,7 +105,13 @@ class M2MThroughSerializationTestCase(TestCase):
out = StringIO() out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out) management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out)
self.assertJSONEqual(out.getvalue().strip(), """[{"pk": %(m_pk)s, "model": "m2m_through_regress.membership", "fields": {"person": %(p_pk)s, "price": 100, "group": %(g_pk)s}}, {"pk": %(p_pk)s, "model": "m2m_through_regress.person", "fields": {"name": "Bob"}}, {"pk": %(g_pk)s, "model": "m2m_through_regress.group", "fields": {"name": "Roll"}}]""" % pks) self.assertJSONEqual(
out.getvalue().strip(),
'[{"pk": %(m_pk)s, "model": "m2m_through_regress.membership", "fields": {"person": %(p_pk)s, "price": '
'100, "group": %(g_pk)s}}, {"pk": %(p_pk)s, "model": "m2m_through_regress.person", "fields": {"name": '
'"Bob"}}, {"pk": %(g_pk)s, "model": "m2m_through_regress.group", "fields": {"name": "Roll"}}]'
% pks
)
out = StringIO() out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="xml", management.call_command("dumpdata", "m2m_through_regress", format="xml",
@ -237,7 +243,15 @@ class ThroughLoadDataTestCase(TestCase):
fixtures = ["m2m_through"] fixtures = ["m2m_through"]
def test_sequence_creation(self): def test_sequence_creation(self):
"Check that sequences on an m2m_through are created for the through model, not a phantom auto-generated m2m table. Refs #11107" """
Sequences on an m2m_through are created for the through model, not a
phantom auto-generated m2m table (#11107).
"""
out = StringIO() out = StringIO()
management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out) management.call_command("dumpdata", "m2m_through_regress", format="json", stdout=out)
self.assertJSONEqual(out.getvalue().strip(), """[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user": 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, "model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}]""") self.assertJSONEqual(
out.getvalue().strip(),
'[{"pk": 1, "model": "m2m_through_regress.usermembership", "fields": {"price": 100, "group": 1, "user"'
': 1}}, {"pk": 1, "model": "m2m_through_regress.person", "fields": {"name": "Guido"}}, {"pk": 1, '
'"model": "m2m_through_regress.group", "fields": {"name": "Python Core Group"}}]'
)

View File

@ -81,16 +81,28 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
self.assertEqual(email.recipients(), ['to@example.com', 'cc@example.com']) self.assertEqual(email.recipients(), ['to@example.com', 'cc@example.com'])
# Test multiple CC with multiple To # Test multiple CC with multiple To
email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com', 'other@example.com'], cc=['cc@example.com', 'cc.other@example.com']) email = EmailMessage(
'Subject', 'Content', 'from@example.com', ['to@example.com', 'other@example.com'],
cc=['cc@example.com', 'cc.other@example.com']
)
message = email.message() message = email.message()
self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com') self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com')
self.assertEqual(email.recipients(), ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com']) self.assertEqual(
email.recipients(),
['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com']
)
# Testing with Bcc # Testing with Bcc
email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com', 'other@example.com'], cc=['cc@example.com', 'cc.other@example.com'], bcc=['bcc@example.com']) email = EmailMessage(
'Subject', 'Content', 'from@example.com', ['to@example.com', 'other@example.com'],
cc=['cc@example.com', 'cc.other@example.com'], bcc=['bcc@example.com']
)
message = email.message() message = email.message()
self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com') self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com')
self.assertEqual(email.recipients(), ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']) self.assertEqual(
email.recipients(),
['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']
)
def test_reply_to(self): def test_reply_to(self):
email = EmailMessage( email = EmailMessage(
@ -108,10 +120,16 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
self.assertEqual(message['Reply-To'], 'reply_to1@example.com, reply_to2@example.com') self.assertEqual(message['Reply-To'], 'reply_to1@example.com, reply_to2@example.com')
def test_recipients_as_tuple(self): def test_recipients_as_tuple(self):
email = EmailMessage('Subject', 'Content', 'from@example.com', ('to@example.com', 'other@example.com'), cc=('cc@example.com', 'cc.other@example.com'), bcc=('bcc@example.com',)) email = EmailMessage(
'Subject', 'Content', 'from@example.com', ('to@example.com', 'other@example.com'),
cc=('cc@example.com', 'cc.other@example.com'), bcc=('bcc@example.com',)
)
message = email.message() message = email.message()
self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com') self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com')
self.assertEqual(email.recipients(), ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']) self.assertEqual(
email.recipients(),
['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']
)
def test_recipients_as_string(self): def test_recipients_as_string(self):
with self.assertRaisesMessage(TypeError, '"to" argument must be a list or tuple'): with self.assertRaisesMessage(TypeError, '"to" argument must be a list or tuple'):
@ -126,17 +144,27 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
def test_header_injection(self): def test_header_injection(self):
email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com']) email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com'])
self.assertRaises(BadHeaderError, email.message) self.assertRaises(BadHeaderError, email.message)
email = EmailMessage(ugettext_lazy('Subject\nInjection Test'), 'Content', 'from@example.com', ['to@example.com']) email = EmailMessage(
ugettext_lazy('Subject\nInjection Test'), 'Content', 'from@example.com', ['to@example.com']
)
self.assertRaises(BadHeaderError, email.message) self.assertRaises(BadHeaderError, email.message)
def test_space_continuation(self): def test_space_continuation(self):
""" """
Test for space continuation character in long (ASCII) subject headers (#7747) Test for space continuation character in long (ASCII) subject headers (#7747)
""" """
email = EmailMessage('Long subject lines that get wrapped should contain a space continuation character to get expected behavior in Outlook and Thunderbird', 'Content', 'from@example.com', ['to@example.com']) email = EmailMessage(
'Long subject lines that get wrapped should contain a space '
'continuation character to get expected behavior in Outlook and Thunderbird',
'Content', 'from@example.com', ['to@example.com']
)
message = email.message() message = email.message()
# Note that in Python 3, maximum line length has increased from 76 to 78 # Note that in Python 3, maximum line length has increased from 76 to 78
self.assertEqual(message['Subject'].encode(), b'Long subject lines that get wrapped should contain a space continuation\n character to get expected behavior in Outlook and Thunderbird') self.assertEqual(
message['Subject'].encode(),
b'Long subject lines that get wrapped should contain a space continuation\n'
b' character to get expected behavior in Outlook and Thunderbird'
)
def test_message_header_overrides(self): def test_message_header_overrides(self):
""" """
@ -161,7 +189,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
""" """
Make sure we can manually set the From header (#9214) Make sure we can manually set the From header (#9214)
""" """
email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
message = email.message() message = email.message()
self.assertEqual(message['From'], 'from@example.com') self.assertEqual(message['From'], 'from@example.com')
@ -199,7 +230,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
Regression for #13259 - Make sure that headers are not changed when Regression for #13259 - Make sure that headers are not changed when
calling EmailMessage.message() calling EmailMessage.message()
""" """
email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
message = email.message() message = email.message()
self.assertEqual(message['From'], 'from@example.com') self.assertEqual(message['From'], 'from@example.com')
message = email.message() message = email.message()
@ -211,10 +245,22 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
make sure the email addresses are parsed correctly (especially with make sure the email addresses are parsed correctly (especially with
regards to commas) regards to commas)
""" """
email = EmailMessage('Subject', 'Content', 'from@example.com', ['"Firstname Sürname" <to@example.com>', 'other@example.com']) email = EmailMessage(
self.assertEqual(email.message()['To'], '=?utf-8?q?Firstname_S=C3=BCrname?= <to@example.com>, other@example.com') 'Subject', 'Content', 'from@example.com',
email = EmailMessage('Subject', 'Content', 'from@example.com', ['"Sürname, Firstname" <to@example.com>', 'other@example.com']) ['"Firstname Sürname" <to@example.com>', 'other@example.com'],
self.assertEqual(email.message()['To'], '=?utf-8?q?S=C3=BCrname=2C_Firstname?= <to@example.com>, other@example.com') )
self.assertEqual(
email.message()['To'],
'=?utf-8?q?Firstname_S=C3=BCrname?= <to@example.com>, other@example.com'
)
email = EmailMessage(
'Subject', 'Content', 'from@example.com',
['"Sürname, Firstname" <to@example.com>', 'other@example.com'],
)
self.assertEqual(
email.message()['To'],
'=?utf-8?q?S=C3=BCrname=2C_Firstname?= <to@example.com>, other@example.com'
)
def test_unicode_headers(self): def test_unicode_headers(self):
email = EmailMessage("Gżegżółka", "Content", "from@example.com", ["to@example.com"], email = EmailMessage("Gżegżółka", "Content", "from@example.com", ["to@example.com"],
@ -274,7 +320,9 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
('MIME-Version', '1.0'), ('MIME-Version', '1.0'),
('Content-Type', 'text/html; charset="iso-8859-1"'), ('Content-Type', 'text/html; charset="iso-8859-1"'),
('Content-Transfer-Encoding', 'quoted-printable')}) ('Content-Transfer-Encoding', 'quoted-printable')})
self.assertTrue(payload1.as_bytes().endswith(b'\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>')) self.assertTrue(
payload1.as_bytes().endswith(b'\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>')
)
def test_attachments(self): def test_attachments(self):
"""Regression test for #9367""" """Regression test for #9367"""
@ -341,7 +389,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
Make sure that dummy backends returns correct number of sent messages Make sure that dummy backends returns correct number of sent messages
""" """
connection = dummy.EmailBackend() connection = dummy.EmailBackend()
email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
self.assertEqual(connection.send_messages([email, email, email]), 3) self.assertEqual(connection.send_messages([email, email, email]), 3)
def test_arbitrary_keyword(self): def test_arbitrary_keyword(self):
@ -356,19 +407,31 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
"""Test custom backend defined in this suite.""" """Test custom backend defined in this suite."""
conn = mail.get_connection('mail.custombackend.EmailBackend') conn = mail.get_connection('mail.custombackend.EmailBackend')
self.assertTrue(hasattr(conn, 'test_outbox')) self.assertTrue(hasattr(conn, 'test_outbox'))
email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
conn.send_messages([email]) conn.send_messages([email])
self.assertEqual(len(conn.test_outbox), 1) self.assertEqual(len(conn.test_outbox), 1)
def test_backend_arg(self): def test_backend_arg(self):
"""Test backend argument of mail.get_connection()""" """Test backend argument of mail.get_connection()"""
self.assertIsInstance(mail.get_connection('django.core.mail.backends.smtp.EmailBackend'), smtp.EmailBackend) self.assertIsInstance(mail.get_connection('django.core.mail.backends.smtp.EmailBackend'), smtp.EmailBackend)
self.assertIsInstance(mail.get_connection('django.core.mail.backends.locmem.EmailBackend'), locmem.EmailBackend) self.assertIsInstance(
mail.get_connection('django.core.mail.backends.locmem.EmailBackend'),
locmem.EmailBackend
)
self.assertIsInstance(mail.get_connection('django.core.mail.backends.dummy.EmailBackend'), dummy.EmailBackend) self.assertIsInstance(mail.get_connection('django.core.mail.backends.dummy.EmailBackend'), dummy.EmailBackend)
self.assertIsInstance(mail.get_connection('django.core.mail.backends.console.EmailBackend'), console.EmailBackend) self.assertIsInstance(
mail.get_connection('django.core.mail.backends.console.EmailBackend'),
console.EmailBackend
)
tmp_dir = tempfile.mkdtemp() tmp_dir = tempfile.mkdtemp()
try: try:
self.assertIsInstance(mail.get_connection('django.core.mail.backends.filebased.EmailBackend', file_path=tmp_dir), filebased.EmailBackend) self.assertIsInstance(
mail.get_connection('django.core.mail.backends.filebased.EmailBackend', file_path=tmp_dir),
filebased.EmailBackend
)
finally: finally:
shutil.rmtree(tmp_dir) shutil.rmtree(tmp_dir)
self.assertIsInstance(mail.get_connection(), locmem.EmailBackend) self.assertIsInstance(mail.get_connection(), locmem.EmailBackend)
@ -413,29 +476,44 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
def test_dont_mangle_from_in_body(self): def test_dont_mangle_from_in_body(self):
# Regression for #13433 - Make sure that EmailMessage doesn't mangle # Regression for #13433 - Make sure that EmailMessage doesn't mangle
# 'From ' in message body. # 'From ' in message body.
email = EmailMessage('Subject', 'From the future', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'From the future', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
self.assertNotIn(b'>From the future', email.message().as_bytes()) self.assertNotIn(b'>From the future', email.message().as_bytes())
def test_dont_base64_encode(self): def test_dont_base64_encode(self):
# Ticket #3472 # Ticket #3472
# Shouldn't use Base64 encoding at all # Shouldn't use Base64 encoding at all
msg = EmailMessage('Subject', 'UTF-8 encoded body', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) msg = EmailMessage(
'Subject', 'UTF-8 encoded body', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
self.assertNotIn(b'Content-Transfer-Encoding: base64', msg.message().as_bytes()) self.assertNotIn(b'Content-Transfer-Encoding: base64', msg.message().as_bytes())
# Ticket #11212 # Ticket #11212
# Shouldn't use quoted printable, should detect it can represent content with 7 bit data # Shouldn't use quoted printable, should detect it can represent content with 7 bit data
msg = EmailMessage('Subject', 'Body with only ASCII characters.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) msg = EmailMessage(
'Subject', 'Body with only ASCII characters.', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
s = msg.message().as_bytes() s = msg.message().as_bytes()
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s) self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s)
self.assertIn(b'Content-Transfer-Encoding: 7bit', s) self.assertIn(b'Content-Transfer-Encoding: 7bit', s)
# Shouldn't use quoted printable, should detect it can represent content with 8 bit data # Shouldn't use quoted printable, should detect it can represent content with 8 bit data
msg = EmailMessage('Subject', 'Body with latin characters: àáä.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) msg = EmailMessage(
'Subject', 'Body with latin characters: àáä.', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
s = msg.message().as_bytes() s = msg.message().as_bytes()
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s) self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s)
self.assertIn(b'Content-Transfer-Encoding: 8bit', s) self.assertIn(b'Content-Transfer-Encoding: 8bit', s)
msg = EmailMessage('Subject', 'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) msg = EmailMessage(
'Subject', 'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', 'bounce@example.com',
['to@example.com'], headers={'From': 'from@example.com'},
)
s = msg.message().as_bytes() s = msg.message().as_bytes()
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s) self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s)
self.assertIn(b'Content-Transfer-Encoding: 8bit', s) self.assertIn(b'Content-Transfer-Encoding: 8bit', s)
@ -444,11 +522,17 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
# Ticket #18967 # Ticket #18967
# Shouldn't use base64 encoding for a child EmailMessage attachment. # Shouldn't use base64 encoding for a child EmailMessage attachment.
# Create a child message first # Create a child message first
child_msg = EmailMessage('Child Subject', 'Some body of child message', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) child_msg = EmailMessage(
'Child Subject', 'Some body of child message', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
child_s = child_msg.message().as_string() child_s = child_msg.message().as_string()
# Now create a parent # Now create a parent
parent_msg = EmailMessage('Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) parent_msg = EmailMessage(
'Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
# Attach to parent as a string # Attach to parent as a string
parent_msg.attach(content=child_s, mimetype='message/rfc822') parent_msg.attach(content=child_s, mimetype='message/rfc822')
@ -458,7 +542,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
self.assertIn(str('Child Subject'), parent_s) self.assertIn(str('Child Subject'), parent_s)
# Feature test: try attaching email.Message object directly to the mail. # Feature test: try attaching email.Message object directly to the mail.
parent_msg = EmailMessage('Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) parent_msg = EmailMessage(
'Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
parent_msg.attach(content=child_msg.message(), mimetype='message/rfc822') parent_msg.attach(content=child_msg.message(), mimetype='message/rfc822')
parent_s = parent_msg.message().as_string() parent_s = parent_msg.message().as_string()
@ -466,7 +553,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
self.assertIn(str('Child Subject'), parent_s) self.assertIn(str('Child Subject'), parent_s)
# Feature test: try attaching Django's EmailMessage object directly to the mail. # Feature test: try attaching Django's EmailMessage object directly to the mail.
parent_msg = EmailMessage('Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) parent_msg = EmailMessage(
'Parent Subject', 'Some parent body', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
parent_msg.attach(content=child_msg, mimetype='message/rfc822') parent_msg.attach(content=child_msg, mimetype='message/rfc822')
parent_s = parent_msg.message().as_string() parent_s = parent_msg.message().as_string()
@ -769,7 +859,10 @@ class LocmemBackendTests(BaseEmailBackendTests, SimpleTestCase):
""" """
connection = locmem.EmailBackend() connection = locmem.EmailBackend()
connection2 = locmem.EmailBackend() connection2 = locmem.EmailBackend()
email = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) email = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
connection.send_messages([email]) connection.send_messages([email])
connection2.send_messages([email]) connection2.send_messages([email])
self.assertEqual(len(mail.outbox), 2) self.assertEqual(len(mail.outbox), 2)
@ -808,7 +901,10 @@ class FileBackendTests(BaseEmailBackendTests, SimpleTestCase):
def test_file_sessions(self): def test_file_sessions(self):
"""Make sure opening a connection creates a new file""" """Make sure opening a connection creates a new file"""
msg = EmailMessage('Subject', 'Content', 'bounce@example.com', ['to@example.com'], headers={'From': 'from@example.com'}) msg = EmailMessage(
'Subject', 'Content', 'bounce@example.com', ['to@example.com'],
headers={'From': 'from@example.com'},
)
connection = mail.get_connection() connection = mail.get_connection()
connection.send_messages([msg]) connection.send_messages([msg])

View File

@ -485,10 +485,12 @@ class ManyToOneTests(TestCase):
expected_message % ', '.join(sorted(f.name for f in Reporter._meta.get_fields())), expected_message % ', '.join(sorted(f.name for f in Reporter._meta.get_fields())),
Article.objects.values_list, Article.objects.values_list,
'reporter__notafield') 'reporter__notafield')
self.assertRaisesMessage(FieldError, self.assertRaisesMessage(
expected_message % ', '.join(['EXTRA'] + sorted(f.name for f in Article._meta.get_fields())), FieldError,
Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list, expected_message % ', '.join(['EXTRA'] + sorted(f.name for f in Article._meta.get_fields())),
'notafield') Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list,
'notafield'
)
def test_fk_assignment_and_related_object_cache(self): def test_fk_assignment_and_related_object_cache(self):
# Tests of ForeignKey assignment and the related-object cache (see #6886). # Tests of ForeignKey assignment and the related-object cache (see #6886).

View File

@ -395,10 +395,13 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(middleware) self._add_middleware(middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [ self.assert_exceptions_handled(
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead.", '/middleware_exceptions/null_view/', [
], "The view middleware_exceptions.views.null_view didn't return "
ValueError()) "an HttpResponse object. It returned None instead."
],
ValueError()
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, False) self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
@ -412,10 +415,13 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(middleware) self._add_middleware(middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [ self.assert_exceptions_handled(
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead." '/middleware_exceptions/null_view/', [
], "The view middleware_exceptions.views.null_view didn't return "
ValueError()) "an HttpResponse object. It returned None instead."
],
ValueError()
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, False) self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
@ -534,7 +540,10 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(bad_middleware) self._add_middleware(bad_middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/template_response/', ['Test Template Response Exception']) self.assert_exceptions_handled(
'/middleware_exceptions/template_response/',
['Test Template Response Exception']
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, False) self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
@ -716,10 +725,13 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(bad_middleware) self._add_middleware(bad_middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [ self.assert_exceptions_handled(
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead.", '/middleware_exceptions/null_view/', [
'Test Response Exception' "The view middleware_exceptions.views.null_view didn't return "
]) "an HttpResponse object. It returned None instead.",
'Test Response Exception'
]
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, False, False) self.assert_middleware_usage(pre_middleware, True, True, False, False, False)
@ -733,10 +745,13 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(bad_middleware) self._add_middleware(bad_middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [ self.assert_exceptions_handled(
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead." '/middleware_exceptions/null_view/', [
], "The view middleware_exceptions.views.null_view didn't return "
ValueError()) "an HttpResponse object. It returned None instead."
],
ValueError()
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, False) self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
@ -823,10 +838,13 @@ class BadMiddlewareTests(BaseMiddlewareExceptionTest):
self._add_middleware(post_middleware) self._add_middleware(post_middleware)
self._add_middleware(middleware) self._add_middleware(middleware)
self._add_middleware(pre_middleware) self._add_middleware(pre_middleware)
self.assert_exceptions_handled('/middleware_exceptions/template_response/', [ self.assert_exceptions_handled(
"NoTemplateResponseMiddleware.process_template_response didn't return an HttpResponse object. It returned None instead." '/middleware_exceptions/template_response/', [
], "NoTemplateResponseMiddleware.process_template_response didn't "
ValueError()) "return an HttpResponse object. It returned None instead."
],
ValueError()
)
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(pre_middleware, True, True, False, True, False) self.assert_middleware_usage(pre_middleware, True, True, False, True, False)

View File

@ -1337,7 +1337,10 @@ class AutodetectorTests(TestCase):
self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user') self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user')
fk_field = changes['testapp'][0].operations[0].field fk_field = changes['testapp'][0].operations[0].field
to_model = '%s.%s' % (fk_field.remote_field.model._meta.app_label, fk_field.remote_field.model._meta.object_name) to_model = '%s.%s' % (
fk_field.remote_field.model._meta.app_label,
fk_field.remote_field.model._meta.object_name,
)
self.assertEqual(to_model, 'thirdapp.CustomUser') self.assertEqual(to_model, 'thirdapp.CustomUser')
def test_add_field_with_default(self): def test_add_field_with_default(self):

View File

@ -505,8 +505,10 @@ class MakeMigrationsTests(MigrationTestBase):
self.assertIn('ÚÑÍ¢ÓÐÉ', content) # title.verbose_name self.assertIn('ÚÑÍ¢ÓÐÉ', content) # title.verbose_name
self.assertIn('“Ðjáñgó”', content) # title.default self.assertIn('“Ðjáñgó”', content) # title.default
else: else:
self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8', content) # Meta.verbose_name # Meta.verbose_name
self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8\\xdf', content) # Meta.verbose_name_plural self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8', content)
# Meta.verbose_name_plural
self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8\\xdf', content)
self.assertIn('\\xda\\xd1\\xcd\\xa2\\xd3\\xd0\\xc9', content) # title.verbose_name self.assertIn('\\xda\\xd1\\xcd\\xa2\\xd3\\xd0\\xc9', content) # title.verbose_name
self.assertIn('\\u201c\\xd0j\\xe1\\xf1g\\xf3\\u201d', content) # title.default self.assertIn('\\u201c\\xd0j\\xe1\\xf1g\\xf3\\u201d', content) # title.default
@ -878,7 +880,8 @@ class MakeMigrationsTests(MigrationTestBase):
app_label = "migrations" app_label = "migrations"
out = six.StringIO() out = six.StringIO()
with self.temporary_migration_module(module="migrations.test_migrations_path_doesnt_exist.foo.bar") as migration_dir: migration_module = "migrations.test_migrations_path_doesnt_exist.foo.bar"
with self.temporary_migration_module(module=migration_module) as migration_dir:
call_command("makemigrations", "migrations", stdout=out) call_command("makemigrations", "migrations", stdout=out)
# Migrations file is actually created in the expected path. # Migrations file is actually created in the expected path.

View File

@ -47,7 +47,10 @@ class GraphTests(SimpleTestCase):
# Test whole graph # Test whole graph
self.assertEqual( self.assertEqual(
graph.forwards_plan(("app_a", "0004")), graph.forwards_plan(("app_a", "0004")),
[('app_b', '0001'), ('app_b', '0002'), ('app_a', '0001'), ('app_a', '0002'), ('app_a', '0003'), ('app_a', '0004')], [
('app_b', '0001'), ('app_b', '0002'), ('app_a', '0001'),
('app_a', '0002'), ('app_a', '0003'), ('app_a', '0004'),
],
) )
# Test reverse to b:0002 # Test reverse to b:0002
self.assertEqual( self.assertEqual(
@ -101,12 +104,19 @@ class GraphTests(SimpleTestCase):
# Test whole graph # Test whole graph
self.assertEqual( self.assertEqual(
graph.forwards_plan(("app_a", "0004")), graph.forwards_plan(("app_a", "0004")),
[('app_b', '0001'), ('app_c', '0001'), ('app_a', '0001'), ('app_a', '0002'), ('app_c', '0002'), ('app_b', '0002'), ('app_a', '0003'), ('app_a', '0004')], [
('app_b', '0001'), ('app_c', '0001'), ('app_a', '0001'),
('app_a', '0002'), ('app_c', '0002'), ('app_b', '0002'),
('app_a', '0003'), ('app_a', '0004'),
],
) )
# Test reverse to b:0001 # Test reverse to b:0001
self.assertEqual( self.assertEqual(
graph.backwards_plan(("app_b", "0001")), graph.backwards_plan(("app_b", "0001")),
[('app_a', '0004'), ('app_c', '0002'), ('app_c', '0001'), ('app_a', '0003'), ('app_b', '0002'), ('app_b', '0001')], [
('app_a', '0004'), ('app_c', '0002'), ('app_c', '0001'),
('app_a', '0003'), ('app_b', '0002'), ('app_b', '0001'),
],
) )
# Test roots and leaves # Test roots and leaves
self.assertEqual( self.assertEqual(

View File

@ -517,7 +517,10 @@ class OperationTests(OperationTestBase):
self.assertNotIn(("test_rmwsrf", "rider"), new_state.models) self.assertNotIn(("test_rmwsrf", "rider"), new_state.models)
self.assertIn(("test_rmwsrf", "horserider"), new_state.models) self.assertIn(("test_rmwsrf", "horserider"), new_state.models)
# Remember, RenameModel also repoints all incoming FKs and M2Ms # Remember, RenameModel also repoints all incoming FKs and M2Ms
self.assertEqual("test_rmwsrf.HorseRider", new_state.models["test_rmwsrf", "horserider"].fields[2][1].remote_field.model) self.assertEqual(
"test_rmwsrf.HorseRider",
new_state.models["test_rmwsrf", "horserider"].fields[2][1].remote_field.model
)
# Test the database alteration # Test the database alteration
self.assertTableExists("test_rmwsrf_rider") self.assertTableExists("test_rmwsrf_rider")
self.assertTableNotExists("test_rmwsrf_horserider") self.assertTableNotExists("test_rmwsrf_horserider")
@ -889,7 +892,9 @@ class OperationTests(OperationTestBase):
self.assertFalse(Pony._meta.get_field('stables').blank) self.assertFalse(Pony._meta.get_field('stables').blank)
project_state = self.apply_operations("test_alflmm", project_state, operations=[ project_state = self.apply_operations("test_alflmm", project_state, operations=[
migrations.AlterField("Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True)) migrations.AlterField(
"Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True)
)
]) ])
Pony = project_state.apps.get_model("test_alflmm", "Pony") Pony = project_state.apps.get_model("test_alflmm", "Pony")
self.assertTrue(Pony._meta.get_field('stables').blank) self.assertTrue(Pony._meta.get_field('stables').blank)
@ -939,7 +944,10 @@ class OperationTests(OperationTestBase):
("pony", models.ForeignKey('test_rmflmmwt.Pony', models.CASCADE)), ("pony", models.ForeignKey('test_rmflmmwt.Pony', models.CASCADE)),
("stable", models.ForeignKey('test_rmflmmwt.Stable', models.CASCADE)), ("stable", models.ForeignKey('test_rmflmmwt.Stable', models.CASCADE)),
]), ]),
migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies", through='test_rmflmmwt.PonyStables')) migrations.AddField(
"Pony", "stables",
models.ManyToManyField("Stable", related_name="ponies", through='test_rmflmmwt.PonyStables')
)
]) ])
self.assertTableExists("test_rmflmmwt_ponystables") self.assertTableExists("test_rmflmmwt_ponystables")
@ -1323,8 +1331,13 @@ class OperationTests(OperationTestBase):
self.assertEqual(operation.describe(), "Set order_with_respect_to on Rider to pony") self.assertEqual(operation.describe(), "Set order_with_respect_to on Rider to pony")
new_state = project_state.clone() new_state = project_state.clone()
operation.state_forwards("test_alorwrtto", new_state) operation.state_forwards("test_alorwrtto", new_state)
self.assertEqual(project_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), None) self.assertIsNone(
self.assertEqual(new_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), "pony") project_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None)
)
self.assertEqual(
new_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None),
"pony"
)
# Make sure there's no matching index # Make sure there's no matching index
self.assertColumnNotExists("test_alorwrtto_rider", "_order") self.assertColumnNotExists("test_alorwrtto_rider", "_order")
# Create some rows before alteration # Create some rows before alteration

View File

@ -25,9 +25,13 @@ class OptimizerTests(SimpleTestCase):
expected = [repr(f.deconstruct()) for f in expected] expected = [repr(f.deconstruct()) for f in expected]
self.assertEqual(expected, result) self.assertEqual(expected, result)
if exact is not None and iterations != exact: if exact is not None and iterations != exact:
raise self.failureException("Optimization did not take exactly %s iterations (it took %s)" % (exact, iterations)) raise self.failureException(
"Optimization did not take exactly %s iterations (it took %s)" % (exact, iterations)
)
if less_than is not None and iterations >= less_than: if less_than is not None and iterations >= less_than:
raise self.failureException("Optimization did not take less than %s iterations (it took %s)" % (less_than, iterations)) raise self.failureException(
"Optimization did not take less than %s iterations (it took %s)" % (less_than, iterations)
)
def assertDoesNotOptimize(self, operations): def assertDoesNotOptimize(self, operations):
self.assertOptimizesTo(operations, operations) self.assertOptimizesTo(operations, operations)
@ -280,12 +284,16 @@ class OptimizerTests(SimpleTestCase):
[ [
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
migrations.CreateModel("LinkThrough", []), migrations.CreateModel("LinkThrough", []),
migrations.AddField("Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")), migrations.AddField(
"Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")
),
], ],
[ [
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
migrations.CreateModel("LinkThrough", []), migrations.CreateModel("LinkThrough", []),
migrations.AddField("Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")), migrations.AddField(
"Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")
),
], ],
) )

View File

@ -122,7 +122,10 @@ class StateTests(SimpleTestCase):
self.assertEqual(author_state.fields[1][1].max_length, 255) self.assertEqual(author_state.fields[1][1].max_length, 255)
self.assertEqual(author_state.fields[2][1].null, False) self.assertEqual(author_state.fields[2][1].null, False)
self.assertEqual(author_state.fields[3][1].null, True) self.assertEqual(author_state.fields[3][1].null, True)
self.assertEqual(author_state.options, {"unique_together": {("name", "bio")}, "index_together": {("bio", "age")}}) self.assertEqual(
author_state.options,
{"unique_together": {("name", "bio")}, "index_together": {("bio", "age")}}
)
self.assertEqual(author_state.bases, (models.Model, )) self.assertEqual(author_state.bases, (models.Model, ))
self.assertEqual(book_state.app_label, "migrations") self.assertEqual(book_state.app_label, "migrations")

View File

@ -441,7 +441,9 @@ class WriterTests(SimpleTestCase):
"operations": [ "operations": [
migrations.CreateModel("MyModel", tuple(fields.items()), options, (models.Model,)), migrations.CreateModel("MyModel", tuple(fields.items()), options, (models.Model,)),
migrations.CreateModel("MyModel2", tuple(fields.items()), bases=(models.Model,)), migrations.CreateModel("MyModel2", tuple(fields.items()), bases=(models.Model,)),
migrations.CreateModel(name="MyModel3", fields=tuple(fields.items()), options=options, bases=(models.Model,)), migrations.CreateModel(
name="MyModel3", fields=tuple(fields.items()), options=options, bases=(models.Model,)
),
migrations.DeleteModel("MyModel"), migrations.DeleteModel("MyModel"),
migrations.AddField("OtherModel", "datetimefield", fields["datetimefield"]), migrations.AddField("OtherModel", "datetimefield", fields["datetimefield"]),
], ],

View File

@ -86,7 +86,10 @@ class TestQuerying(TestCase):
class TestSerialization(SimpleTestCase): class TestSerialization(SimpleTestCase):
test_data = '[{"fields": {"field": "550e8400-e29b-41d4-a716-446655440000"}, "model": "model_fields.uuidmodel", "pk": null}]' test_data = (
'[{"fields": {"field": "550e8400-e29b-41d4-a716-446655440000"}, '
'"model": "model_fields.uuidmodel", "pk": null}]'
)
def test_dumping(self): def test_dumping(self):
instance = UUIDModel(field=uuid.UUID('550e8400e29b41d4a716446655440000')) instance = UUIDModel(field=uuid.UUID('550e8400e29b41d4a716446655440000'))

View File

@ -494,9 +494,12 @@ class ModelFormBaseTest(TestCase):
self.assertHTMLEqual( self.assertHTMLEqual(
str(SubclassMeta()), str(SubclassMeta()),
"""<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> """<tr><th><label for="id_name">Name:</label></th>
<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr> <td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
<tr><th><label for="id_checkbox">Checkbox:</label></th><td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>""" <tr><th><label for="id_slug">Slug:</label></th>
<td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
<tr><th><label for="id_checkbox">Checkbox:</label></th>
<td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>"""
) )
def test_orderfields_form(self): def test_orderfields_form(self):
@ -509,8 +512,10 @@ class ModelFormBaseTest(TestCase):
['url', 'name']) ['url', 'name'])
self.assertHTMLEqual( self.assertHTMLEqual(
str(OrderFields()), str(OrderFields()),
"""<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr> """<tr><th><label for="id_url">The URL:</label></th>
<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>""" <td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
<tr><th><label for="id_name">Name:</label></th>
<td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>"""
) )
def test_orderfields2_form(self): def test_orderfields2_form(self):
@ -894,7 +899,10 @@ class UniqueTest(TestCase):
class Meta(PostForm.Meta): class Meta(PostForm.Meta):
error_messages = { error_messages = {
'title': { 'title': {
'unique_for_date': "%(model_name)s's %(field_label)s not unique for %(date_field_label)s date.", 'unique_for_date': (
"%(model_name)s's %(field_label)s not unique "
"for %(date_field_label)s date."
),
} }
} }
@ -993,9 +1001,12 @@ class ModelFormBasicTests(TestCase):
f = BaseCategoryForm() f = BaseCategoryForm()
self.assertHTMLEqual( self.assertHTMLEqual(
str(f), str(f),
"""<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> """<tr><th><label for="id_name">Name:</label></th>
<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr> <td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>""" <tr><th><label for="id_slug">Slug:</label></th>
<td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
<tr><th><label for="id_url">The URL:</label></th>
<td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>"""
) )
self.assertHTMLEqual( self.assertHTMLEqual(
str(f.as_ul()), str(f.as_ul()),
@ -1025,7 +1036,9 @@ class ModelFormBasicTests(TestCase):
'headline': 'Your headline here', 'headline': 'Your headline here',
'categories': [str(self.c1.id), str(self.c2.id)] 'categories': [str(self.c1.id), str(self.c2.id)]
}) })
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="Your headline here" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" value="Your headline here" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" /></li> <li>Pub date: <input type="text" name="pub_date" /></li>
<li>Writer: <select name="writer"> <li>Writer: <select name="writer">
@ -1049,7 +1062,11 @@ class ModelFormBasicTests(TestCase):
# When the ModelForm is passed an instance, that instance's current values are # When the ModelForm is passed an instance, that instance's current values are
# inserted as 'initial' data in each Field. # inserted as 'initial' data in each Field.
f = RoykoForm(auto_id=False, instance=self.w_royko) f = RoykoForm(auto_id=False, instance=self.w_royko)
self.assertHTMLEqual(six.text_type(f), '''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br /><span class="helptext">Use both first and last names.</span></td></tr>''') self.assertHTMLEqual(
six.text_type(f),
'''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />
<span class="helptext">Use both first and last names.</span></td></tr>'''
)
art = Article.objects.create( art = Article.objects.create(
headline='Test article', headline='Test article',
@ -1061,7 +1078,9 @@ class ModelFormBasicTests(TestCase):
art_id_1 = art.id art_id_1 = art.id
f = ArticleForm(auto_id=False, instance=art) f = ArticleForm(auto_id=False, instance=art)
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
<li>Writer: <select name="writer"> <li>Writer: <select name="writer">
@ -1113,8 +1132,12 @@ class ModelFormBasicTests(TestCase):
ModelForm = modelform_factory(Article, fields=['headline', 'categories'], ModelForm = modelform_factory(Article, fields=['headline', 'categories'],
formfield_callback=formfield_for_dbfield) formfield_callback=formfield_for_dbfield)
form = ModelForm() form = ModelForm()
self.assertHTMLEqual(form.as_ul(), """<li><label for="id_headline">Headline:</label> <input id="id_headline" type="text" name="headline" maxlength="50" /></li> self.assertHTMLEqual(
<li><label for="id_categories">Categories:</label> <select multiple="multiple" name="categories" id="id_categories"> form.as_ul(),
"""<li><label for="id_headline">Headline:</label>
<input id="id_headline" type="text" name="headline" maxlength="50" /></li>
<li><label for="id_categories">Categories:</label>
<select multiple="multiple" name="categories" id="id_categories">
<option value="%d" selected="selected">Entertainment</option> <option value="%d" selected="selected">Entertainment</option>
<option value="%d" selected="selected">It&39;s a test</option> <option value="%d" selected="selected">It&39;s a test</option>
<option value="%d">Third test</option> <option value="%d">Third test</option>
@ -1154,7 +1177,10 @@ class ModelFormBasicTests(TestCase):
# If you call save() with invalid data, you'll get a ValueError. # If you call save() with invalid data, you'll get a ValueError.
f = BaseCategoryForm({'name': '', 'slug': 'not a slug!', 'url': 'foo'}) f = BaseCategoryForm({'name': '', 'slug': 'not a slug!', 'url': 'foo'})
self.assertEqual(f.errors['name'], ['This field is required.']) self.assertEqual(f.errors['name'], ['This field is required.'])
self.assertEqual(f.errors['slug'], ["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."]) self.assertEqual(
f.errors['slug'],
["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."]
)
self.assertEqual(f.cleaned_data, {'url': 'foo'}) self.assertEqual(f.cleaned_data, {'url': 'foo'})
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
f.save() f.save()
@ -1168,7 +1194,9 @@ class ModelFormBasicTests(TestCase):
# ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any # ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
# fields with the 'choices' attribute are represented by a ChoiceField. # fields with the 'choices' attribute are represented by a ChoiceField.
f = ArticleForm(auto_id=False) f = ArticleForm(auto_id=False)
self.assertHTMLEqual(six.text_type(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> self.assertHTMLEqual(
six.text_type(f),
'''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
<tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr> <tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr>
<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
<tr><th>Writer:</th><td><select name="writer"> <tr><th>Writer:</th><td><select name="writer">
@ -1196,7 +1224,9 @@ class ModelFormBasicTests(TestCase):
new_art.categories.add(Category.objects.get(name='Entertainment')) new_art.categories.add(Category.objects.get(name='Entertainment'))
self.assertQuerysetEqual(new_art.categories.all(), ["Entertainment"]) self.assertQuerysetEqual(new_art.categories.all(), ["Entertainment"])
f = ArticleForm(auto_id=False, instance=new_art) f = ArticleForm(auto_id=False, instance=new_art)
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
<li>Writer: <select name="writer"> <li>Writer: <select name="writer">
@ -1230,7 +1260,9 @@ class ModelFormBasicTests(TestCase):
fields = ('headline', 'pub_date') fields = ('headline', 'pub_date')
f = PartialArticleForm(auto_id=False) f = PartialArticleForm(auto_id=False)
self.assertHTMLEqual(six.text_type(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> self.assertHTMLEqual(
six.text_type(f),
'''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>''') <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>''')
# You can create a form over a subset of the available fields # You can create a form over a subset of the available fields
@ -1249,9 +1281,12 @@ class ModelFormBasicTests(TestCase):
'slug': 'new-headline', 'slug': 'new-headline',
'pub_date': '1988-01-04' 'pub_date': '1988-01-04'
}, auto_id=False, instance=art) }, auto_id=False, instance=art)
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>''') <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>'''
)
self.assertTrue(f.is_valid()) self.assertTrue(f.is_valid())
new_art = f.save() new_art = f.save()
self.assertEqual(new_art.id, art.id) self.assertEqual(new_art.id, art.id)
@ -1337,7 +1372,9 @@ class ModelFormBasicTests(TestCase):
# the data in the database when the form is instantiated. # the data in the database when the form is instantiated.
self.create_basic_data() self.create_basic_data()
f = ArticleForm(auto_id=False) f = ArticleForm(auto_id=False)
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" /></li> <li>Pub date: <input type="text" name="pub_date" /></li>
<li>Writer: <select name="writer"> <li>Writer: <select name="writer">
@ -1360,7 +1397,9 @@ class ModelFormBasicTests(TestCase):
c4 = Category.objects.create(name='Fourth', url='4th') c4 = Category.objects.create(name='Fourth', url='4th')
w_bernstein = Writer.objects.create(name='Carl Bernstein') w_bernstein = Writer.objects.create(name='Carl Bernstein')
self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" maxlength="50" /></li> self.assertHTMLEqual(
f.as_ul(),
'''<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
<li>Slug: <input type="text" name="slug" maxlength="50" /></li> <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
<li>Pub date: <input type="text" name="pub_date" /></li> <li>Pub date: <input type="text" name="pub_date" /></li>
<li>Writer: <select name="writer"> <li>Writer: <select name="writer">
@ -1714,12 +1753,17 @@ class ModelOneToOneFieldTests(TestCase):
self.w_woodward = Writer.objects.create(name='Bob Woodward') self.w_woodward = Writer.objects.create(name='Bob Woodward')
form = WriterProfileForm() form = WriterProfileForm()
self.assertHTMLEqual(form.as_p(), '''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer"> self.assertHTMLEqual(
form.as_p(),
'''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer">
<option value="" selected="selected">---------</option> <option value="" selected="selected">---------</option>
<option value="%s">Bob Woodward</option> <option value="%s">Bob Woodward</option>
<option value="%s">Mike Royko</option> <option value="%s">Mike Royko</option>
</select></p> </select></p>
<p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" min="0" /></p>''' % (self.w_woodward.pk, self.w_royko.pk)) <p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" min="0" /></p>''' % (
self.w_woodward.pk, self.w_royko.pk,
)
)
data = { data = {
'writer': six.text_type(self.w_woodward.pk), 'writer': six.text_type(self.w_woodward.pk),
@ -1730,12 +1774,17 @@ class ModelOneToOneFieldTests(TestCase):
self.assertEqual(six.text_type(instance), 'Bob Woodward is 65') self.assertEqual(six.text_type(instance), 'Bob Woodward is 65')
form = WriterProfileForm(instance=instance) form = WriterProfileForm(instance=instance)
self.assertHTMLEqual(form.as_p(), '''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer"> self.assertHTMLEqual(
form.as_p(),
'''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer">
<option value="">---------</option> <option value="">---------</option>
<option value="%s" selected="selected">Bob Woodward</option> <option value="%s" selected="selected">Bob Woodward</option>
<option value="%s">Mike Royko</option> <option value="%s">Mike Royko</option>
</select></p> </select></p>
<p><label for="id_age">Age:</label> <input type="number" name="age" value="65" id="id_age" min="0" /></p>''' % (self.w_woodward.pk, self.w_royko.pk)) <p><label for="id_age">Age:</label> <input type="number" name="age" value="65" id="id_age" min="0" /></p>''' % (
self.w_woodward.pk, self.w_royko.pk,
)
)
def test_assignment_of_none(self): def test_assignment_of_none(self):
class AuthorForm(forms.ModelForm): class AuthorForm(forms.ModelForm):
@ -2082,7 +2131,8 @@ class FileAndImageFieldTests(TestCase):
self.assertEqual(instance.width, 16) self.assertEqual(instance.width, 16)
self.assertEqual(instance.height, 16) self.assertEqual(instance.height, 16)
# Editing the instance without re-uploading the image should not affect the image or its width/height properties # Editing the instance without re-uploading the image should not affect
# the image or its width/height properties.
f = OptionalImageFileForm( f = OptionalImageFileForm(
data={'description': 'New Description'}, data={'description': 'New Description'},
instance=instance) instance=instance)
@ -2123,7 +2173,10 @@ class ModelOtherFieldTests(SimpleTestCase):
self.assertTrue(bif.is_valid()) self.assertTrue(bif.is_valid())
bif = BigIntForm({'biggie': '-9223372036854775809'}) bif = BigIntForm({'biggie': '-9223372036854775809'})
self.assertFalse(bif.is_valid()) self.assertFalse(bif.is_valid())
self.assertEqual(bif.errors, {'biggie': ['Ensure this value is greater than or equal to -9223372036854775808.']}) self.assertEqual(
bif.errors,
{'biggie': ['Ensure this value is greater than or equal to -9223372036854775808.']}
)
bif = BigIntForm({'biggie': '9223372036854775807'}) bif = BigIntForm({'biggie': '9223372036854775807'})
self.assertTrue(bif.is_valid()) self.assertTrue(bif.is_valid())
bif = BigIntForm({'biggie': '9223372036854775808'}) bif = BigIntForm({'biggie': '9223372036854775808'})
@ -2203,8 +2256,11 @@ class OtherModelFormTests(TestCase):
# Similar to a regular Form class you can define custom media to be used on # Similar to a regular Form class you can define custom media to be used on
# the ModelForm. # the ModelForm.
f = ModelFormWithMedia() f = ModelFormWithMedia()
self.assertHTMLEqual(six.text_type(f.media), '''<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" /> self.assertHTMLEqual(
<script type="text/javascript" src="/some/form/javascript"></script>''') six.text_type(f.media),
'''<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/some/form/javascript"></script>'''
)
def test_choices_type(self): def test_choices_type(self):
# Choices on CharField and IntegerField # Choices on CharField and IntegerField
@ -2251,8 +2307,13 @@ class OtherModelFormTests(TestCase):
self.assertEqual(list(CategoryForm.base_fields), self.assertEqual(list(CategoryForm.base_fields),
['description', 'url']) ['description', 'url'])
self.assertHTMLEqual(six.text_type(CategoryForm()), '''<tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr> self.assertHTMLEqual(
<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>''') six.text_type(CategoryForm()),
'''<tr><th><label for="id_description">Description:</label></th>
<td><input type="text" name="description" id="id_description" /></td></tr>
<tr><th><label for="id_url">The URL:</label></th>
<td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>'''
)
# to_field_name should also work on ModelMultipleChoiceField ################## # to_field_name should also work on ModelMultipleChoiceField ##################
field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode') field = forms.ModelMultipleChoiceField(Inventory.objects.all(), to_field_name='barcode')
@ -2267,8 +2328,11 @@ class OtherModelFormTests(TestCase):
def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self): def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self):
self.assertEqual(list(CustomFieldForExclusionForm.base_fields), self.assertEqual(list(CustomFieldForExclusionForm.base_fields),
['name']) ['name'])
self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()), self.assertHTMLEqual(
'''<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>''') six.text_type(CustomFieldForExclusionForm()),
'''<tr><th><label for="id_name">Name:</label></th>
<td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>'''
)
def test_iterable_model_m2m(self): def test_iterable_model_m2m(self):
class ColourfulItemForm(forms.ModelForm): class ColourfulItemForm(forms.ModelForm):
@ -2298,19 +2362,20 @@ class OtherModelFormTests(TestCase):
today_str = str(datetime.date.today()) today_str = str(datetime.date.today())
self.assertHTMLEqual( self.assertHTMLEqual(
form.as_p(), form.as_p(),
"""<p><label for="id_title">Title:</label> <input id="id_title" maxlength="30" name="title" type="text" /></p> """
<p><label for="id_date_published">Date published:</label> <p><label for="id_title">Title:</label> <input id="id_title" maxlength="30" name="title" type="text" /></p>
<input id="id_date_published" name="date_published" type="text" value="{0}" /> <p><label for="id_date_published">Date published:</label>
<input id="initial-id_date_published" name="initial-date_published" type="hidden" value="{0}" /></p> <input id="id_date_published" name="date_published" type="text" value="{0}" />
<p><label for="id_mode">Mode:</label> <select id="id_mode" name="mode"> <input id="initial-id_date_published" name="initial-date_published" type="hidden" value="{0}" /></p>
<option value="di" selected="selected">direct</option> <p><label for="id_mode">Mode:</label> <select id="id_mode" name="mode">
<option value="de">delayed</option></select> <option value="di" selected="selected">direct</option>
<input id="initial-id_mode" name="initial-mode" type="hidden" value="di" /></p> <option value="de">delayed</option></select>
<p><label for="id_category">Category:</label> <select id="id_category" name="category"> <input id="initial-id_mode" name="initial-mode" type="hidden" value="di" /></p>
<option value="1">Games</option> <p><label for="id_category">Category:</label> <select id="id_category" name="category">
<option value="2">Comics</option> <option value="1">Games</option>
<option value="3" selected="selected">Novel</option></select> <option value="2">Comics</option>
<input id="initial-id_category" name="initial-category" type="hidden" value="3" /> <option value="3" selected="selected">Novel</option></select>
<input id="initial-id_category" name="initial-category" type="hidden" value="3" />
""".format(today_str) """.format(today_str)
) )
empty_data = { empty_data = {

View File

@ -151,12 +151,24 @@ class ModelFormsetTest(TestCase):
formset = AuthorFormSet(queryset=qs) formset = AuthorFormSet(queryset=qs)
self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.forms), 3)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></p>') formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_form-0-name">Name:</label>'
'<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /><input type="hidden" name="form-1-id" id="id_form-1-id" /></p>') '<input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" />'
self.assertHTMLEqual(formset.forms[2].as_p(), '<input type="hidden" name="form-0-id" id="id_form-0-id" /></p>'
'<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" /><input type="hidden" name="form-2-id" id="id_form-2-id" /></p>') )
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_form-1-name">Name:</label>'
'<input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" />'
'<input type="hidden" name="form-1-id" id="id_form-1-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_form-2-name">Name:</label>'
' <input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" />'
'<input type="hidden" name="form-2-id" id="id_form-2-id" /></p>'
)
data = { data = {
'form-TOTAL_FORMS': '3', # the number of forms rendered 'form-TOTAL_FORMS': '3', # the number of forms rendered
@ -189,12 +201,24 @@ class ModelFormsetTest(TestCase):
formset = AuthorFormSet(queryset=qs) formset = AuthorFormSet(queryset=qs)
self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.forms), 3)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Arthur Rimbaud" maxlength="100" /><input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /></p>' % author2.id) formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_form-0-name">Name:</label>'
'<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" /></p>' % author1.id) '<input id="id_form-0-name" type="text" name="form-0-name" value="Arthur Rimbaud" maxlength="100" />'
self.assertHTMLEqual(formset.forms[2].as_p(), '<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /></p>' % author2.id
'<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" /><input type="hidden" name="form-2-id" id="id_form-2-id" /></p>') )
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_form-1-name">Name:</label>'
'<input id="id_form-1-name" type="text" name="form-1-name" value="Charles Baudelaire" maxlength="100" />'
'<input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" /></p>' % author1.id
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_form-2-name">Name:</label>'
'<input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" />'
'<input type="hidden" name="form-2-id" id="id_form-2-id" /></p>'
)
data = { data = {
'form-TOTAL_FORMS': '3', # the number of forms rendered 'form-TOTAL_FORMS': '3', # the number of forms rendered
@ -227,18 +251,41 @@ class ModelFormsetTest(TestCase):
formset = AuthorFormSet(queryset=qs) formset = AuthorFormSet(queryset=qs)
self.assertEqual(len(formset.forms), 4) self.assertEqual(len(formset.forms), 4)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Arthur Rimbaud" maxlength="100" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_form-0-DELETE">Delete:</label> <input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /><input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /></p>' % author2.id) '<p><label for="id_form-0-name">Name:</label>'
self.assertHTMLEqual(formset.forms[1].as_p(), '<input id="id_form-0-name" type="text" name="form-0-name" '
'<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" value="Charles Baudelaire" maxlength="100" /></p>\n' 'value="Arthur Rimbaud" maxlength="100" /></p>'
'<p><label for="id_form-1-DELETE">Delete:</label> <input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /><input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" /></p>' % author1.id) '<p><label for="id_form-0-DELETE">Delete:</label>'
self.assertHTMLEqual(formset.forms[2].as_p(), '<input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" />'
'<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" value="Paul Verlaine" maxlength="100" /></p>\n' '<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id" /></p>' % author2.id
'<p><label for="id_form-2-DELETE">Delete:</label> <input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /><input type="hidden" name="form-2-id" value="%d" id="id_form-2-id" /></p>' % author3.id) )
self.assertHTMLEqual(formset.forms[3].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-3-name">Name:</label> <input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /></p>\n' formset.forms[1].as_p(),
'<p><label for="id_form-3-DELETE">Delete:</label> <input type="checkbox" name="form-3-DELETE" id="id_form-3-DELETE" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></p>') '<p><label for="id_form-1-name">Name:</label>'
'<input id="id_form-1-name" type="text" name="form-1-name" '
'value="Charles Baudelaire" maxlength="100" /></p>'
'<p><label for="id_form-1-DELETE">Delete:</label>'
'<input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" />'
'<input type="hidden" name="form-1-id" value="%d" id="id_form-1-id" /></p>' % author1.id
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_form-2-name">Name:</label>'
'<input id="id_form-2-name" type="text" name="form-2-name" '
'value="Paul Verlaine" maxlength="100" /></p>'
'<p><label for="id_form-2-DELETE">Delete:</label>'
'<input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" />'
'<input type="hidden" name="form-2-id" value="%d" id="id_form-2-id" /></p>' % author3.id
)
self.assertHTMLEqual(
formset.forms[3].as_p(),
'<p><label for="id_form-3-name">Name:</label>'
'<input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /></p>'
'<p><label for="id_form-3-DELETE">Delete:</label>'
'<input type="checkbox" name="form-3-DELETE" id="id_form-3-DELETE" />'
'<input type="hidden" name="form-3-id" id="id_form-3-id" /></p>'
)
data = { data = {
'form-TOTAL_FORMS': '4', # the number of forms rendered 'form-TOTAL_FORMS': '4', # the number of forms rendered
@ -480,9 +527,14 @@ class ModelFormsetTest(TestCase):
BetterAuthorFormSet = modelformset_factory(BetterAuthor, fields="__all__") BetterAuthorFormSet = modelformset_factory(BetterAuthor, fields="__all__")
formset = BetterAuthorFormSet() formset = BetterAuthorFormSet()
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_form-0-write_speed">Write speed:</label> <input type="number" name="form-0-write_speed" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" id="id_form-0-author_ptr" /></p>') '<p><label for="id_form-0-name">Name:</label>'
'<input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></p>'
'<p><label for="id_form-0-write_speed">Write speed:</label>'
'<input type="number" name="form-0-write_speed" id="id_form-0-write_speed" />'
'<input type="hidden" name="form-0-author_ptr" id="id_form-0-author_ptr" /></p>'
)
data = { data = {
'form-TOTAL_FORMS': '1', # the number of forms rendered 'form-TOTAL_FORMS': '1', # the number of forms rendered
@ -503,12 +555,22 @@ class ModelFormsetTest(TestCase):
formset = BetterAuthorFormSet() formset = BetterAuthorFormSet()
self.assertEqual(len(formset.forms), 2) self.assertEqual(len(formset.forms), 2)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Ernest Hemingway" maxlength="100" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_form-0-write_speed">Write speed:</label> <input type="number" name="form-0-write_speed" value="10" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" value="%d" id="id_form-0-author_ptr" /></p>' % hemingway_id) '<p><label for="id_form-0-name">Name:</label>'
self.assertHTMLEqual(formset.forms[1].as_p(), '<input id="id_form-0-name" type="text" name="form-0-name" value="Ernest Hemingway" maxlength="100" /></p>'
'<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /></p>\n' '<p><label for="id_form-0-write_speed">Write speed:</label>'
'<p><label for="id_form-1-write_speed">Write speed:</label> <input type="number" name="form-1-write_speed" id="id_form-1-write_speed" /><input type="hidden" name="form-1-author_ptr" id="id_form-1-author_ptr" /></p>') '<input type="number" name="form-0-write_speed" value="10" id="id_form-0-write_speed" />'
'<input type="hidden" name="form-0-author_ptr" value="%d" id="id_form-0-author_ptr" /></p>' % hemingway_id
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_form-1-name">Name:</label>'
'<input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /></p>'
'<p><label for="id_form-1-write_speed">Write speed:</label>'
'<input type="number" name="form-1-write_speed" id="id_form-1-write_speed" />'
'<input type="hidden" name="form-1-author_ptr" id="id_form-1-author_ptr" /></p>'
)
data = { data = {
'form-TOTAL_FORMS': '2', # the number of forms rendered 'form-TOTAL_FORMS': '2', # the number of forms rendered
@ -535,12 +597,27 @@ class ModelFormsetTest(TestCase):
formset = AuthorBooksFormSet(instance=author) formset = AuthorBooksFormSet(instance=author)
self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.forms), 3)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" maxlength="100" /><input type="hidden" name="book_set-0-author" value="%d" id="id_book_set-0-author" /><input type="hidden" name="book_set-0-id" id="id_book_set-0-id" /></p>' % author.id) formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" '
'<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" /><input type="hidden" name="book_set-1-author" value="%d" id="id_book_set-1-author" /><input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>' % author.id) 'name="book_set-0-title" maxlength="100" /><input type="hidden" name="book_set-0-author" value="%d" '
self.assertHTMLEqual(formset.forms[2].as_p(), 'id="id_book_set-0-author" /><input type="hidden" name="book_set-0-id" id="id_book_set-0-id" />'
'<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" /><input type="hidden" name="book_set-2-author" value="%d" id="id_book_set-2-author" /><input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>' % author.id) '</p>' % author.id
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_book_set-1-title">Title:</label>'
'<input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" />'
'<input type="hidden" name="book_set-1-author" value="%d" id="id_book_set-1-author" />'
'<input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>' % author.id
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_book_set-2-title">Title:</label>'
'<input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" />'
'<input type="hidden" name="book_set-2-author" value="%d" id="id_book_set-2-author" />'
'<input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>' % author.id
)
data = { data = {
'book_set-TOTAL_FORMS': '3', # the number of forms rendered 'book_set-TOTAL_FORMS': '3', # the number of forms rendered
@ -569,12 +646,30 @@ class ModelFormsetTest(TestCase):
formset = AuthorBooksFormSet(instance=author) formset = AuthorBooksFormSet(instance=author)
self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.forms), 3)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" value="Les Fleurs du Mal" maxlength="100" /><input type="hidden" name="book_set-0-author" value="%d" id="id_book_set-0-author" /><input type="hidden" name="book_set-0-id" value="%d" id="id_book_set-0-id" /></p>' % (author.id, book1.id)) formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_book_set-0-title">Title:</label>'
'<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" /><input type="hidden" name="book_set-1-author" value="%d" id="id_book_set-1-author" /><input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>' % author.id) '<input id="id_book_set-0-title" type="text" name="book_set-0-title" '
self.assertHTMLEqual(formset.forms[2].as_p(), 'value="Les Fleurs du Mal" maxlength="100" />'
'<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" /><input type="hidden" name="book_set-2-author" value="%d" id="id_book_set-2-author" /><input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>' % author.id) '<input type="hidden" name="book_set-0-author" value="%d" id="id_book_set-0-author" />'
'<input type="hidden" name="book_set-0-id" value="%d" id="id_book_set-0-id" /></p>' % (
author.id, book1.id,
)
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_book_set-1-title">Title:</label>'
'<input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" />'
'<input type="hidden" name="book_set-1-author" value="%d" id="id_book_set-1-author" />'
'<input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>' % author.id
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_book_set-2-title">Title:</label>'
'<input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" />'
'<input type="hidden" name="book_set-2-author" value="%d" id="id_book_set-2-author" />'
'<input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>' % author.id
)
data = { data = {
'book_set-TOTAL_FORMS': '3', # the number of forms rendered 'book_set-TOTAL_FORMS': '3', # the number of forms rendered
@ -633,24 +728,45 @@ class ModelFormsetTest(TestCase):
formset = AuthorBooksFormSet(prefix="test") formset = AuthorBooksFormSet(prefix="test")
self.assertEqual(len(formset.forms), 2) self.assertEqual(len(formset.forms), 2)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_test-0-title">Title:</label> <input id="id_test-0-title" type="text" name="test-0-title" maxlength="100" /><input type="hidden" name="test-0-author" id="id_test-0-author" /><input type="hidden" name="test-0-id" id="id_test-0-id" /></p>') formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_test-0-title">Title:</label>'
'<p><label for="id_test-1-title">Title:</label> <input id="id_test-1-title" type="text" name="test-1-title" maxlength="100" /><input type="hidden" name="test-1-author" id="id_test-1-author" /><input type="hidden" name="test-1-id" id="id_test-1-id" /></p>') '<input id="id_test-0-title" type="text" name="test-0-title" maxlength="100" />'
'<input type="hidden" name="test-0-author" id="id_test-0-author" />'
'<input type="hidden" name="test-0-id" id="id_test-0-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_test-1-title">Title:</label>'
'<input id="id_test-1-title" type="text" name="test-1-title" maxlength="100" />'
'<input type="hidden" name="test-1-author" id="id_test-1-author" />'
'<input type="hidden" name="test-1-id" id="id_test-1-id" /></p>'
)
def test_inline_formsets_with_custom_pk(self): def test_inline_formsets_with_custom_pk(self):
# Test inline formsets where the inline-edited object has a custom # Test inline formsets where the inline-edited object has a custom
# primary key that is not the fk to the parent object. # primary key that is not the fk to the parent object.
self.maxDiff = 1024 self.maxDiff = 1024
AuthorBooksFormSet2 = inlineformset_factory(Author, BookWithCustomPK, can_delete=False, extra=1, fields="__all__") AuthorBooksFormSet2 = inlineformset_factory(
Author, BookWithCustomPK, can_delete=False, extra=1, fields="__all__"
)
author = Author.objects.create(pk=1, name='Charles Baudelaire') author = Author.objects.create(pk=1, name='Charles Baudelaire')
formset = AuthorBooksFormSet2(instance=author) formset = AuthorBooksFormSet2(instance=author)
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_bookwithcustompk_set-0-my_pk">My pk:</label> <input id="id_bookwithcustompk_set-0-my_pk" type="number" name="bookwithcustompk_set-0-my_pk" step="1" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_bookwithcustompk_set-0-title">Title:</label> <input id="id_bookwithcustompk_set-0-title" type="text" name="bookwithcustompk_set-0-title" maxlength="100" /><input type="hidden" name="bookwithcustompk_set-0-author" value="1" id="id_bookwithcustompk_set-0-author" /></p>') '<p><label for="id_bookwithcustompk_set-0-my_pk">My pk:</label>'
'<input id="id_bookwithcustompk_set-0-my_pk" type="number" '
'name="bookwithcustompk_set-0-my_pk" step="1" /></p>'
'<p><label for="id_bookwithcustompk_set-0-title">Title:</label>'
'<input id="id_bookwithcustompk_set-0-title" type="text" '
'name="bookwithcustompk_set-0-title" maxlength="100" />'
'<input type="hidden" name="bookwithcustompk_set-0-author" '
'value="1" id="id_bookwithcustompk_set-0-author" /></p>'
)
data = { data = {
'bookwithcustompk_set-TOTAL_FORMS': '1', # the number of forms rendered 'bookwithcustompk_set-TOTAL_FORMS': '1', # the number of forms rendered
@ -680,9 +796,19 @@ class ModelFormsetTest(TestCase):
formset = AuthorBooksFormSet3(instance=author) formset = AuthorBooksFormSet3(instance=author)
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_alternatebook_set-0-title">Title:</label> <input id="id_alternatebook_set-0-title" type="text" name="alternatebook_set-0-title" maxlength="100" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_alternatebook_set-0-notes">Notes:</label> <input id="id_alternatebook_set-0-notes" type="text" name="alternatebook_set-0-notes" maxlength="100" /><input type="hidden" name="alternatebook_set-0-author" value="1" id="id_alternatebook_set-0-author" /><input type="hidden" name="alternatebook_set-0-book_ptr" id="id_alternatebook_set-0-book_ptr" /></p>') '<p><label for="id_alternatebook_set-0-title">Title:</label>'
'<input id="id_alternatebook_set-0-title" type="text" '
'name="alternatebook_set-0-title" maxlength="100" /></p>'
'<p><label for="id_alternatebook_set-0-notes">Notes:</label>'
'<input id="id_alternatebook_set-0-notes" type="text" '
'name="alternatebook_set-0-notes" maxlength="100" />'
'<input type="hidden" name="alternatebook_set-0-author" value="1" '
'id="id_alternatebook_set-0-author" />'
'<input type="hidden" name="alternatebook_set-0-book_ptr" '
'id="id_alternatebook_set-0-book_ptr" /></p>'
)
data = { data = {
'alternatebook_set-TOTAL_FORMS': '1', # the number of forms rendered 'alternatebook_set-TOTAL_FORMS': '1', # the number of forms rendered
@ -706,7 +832,9 @@ class ModelFormsetTest(TestCase):
# Test inline formsets where the inline-edited object has a # Test inline formsets where the inline-edited object has a
# unique_together constraint with a nullable member # unique_together constraint with a nullable member
AuthorBooksFormSet4 = inlineformset_factory(Author, BookWithOptionalAltEditor, can_delete=False, extra=2, fields="__all__") AuthorBooksFormSet4 = inlineformset_factory(
Author, BookWithOptionalAltEditor, can_delete=False, extra=2, fields="__all__"
)
author = Author.objects.create(pk=1, name='Charles Baudelaire') author = Author.objects.create(pk=1, name='Charles Baudelaire')
data = { data = {
@ -771,16 +899,44 @@ class ModelFormsetTest(TestCase):
custom_qs = Book.objects.order_by('-title') custom_qs = Book.objects.order_by('-title')
formset = AuthorBooksFormSet(instance=author, queryset=custom_qs) formset = AuthorBooksFormSet(instance=author, queryset=custom_qs)
self.assertEqual(len(formset.forms), 5) self.assertEqual(len(formset.forms), 5)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" value="Les Paradis Artificiels" maxlength="100" /><input type="hidden" name="book_set-0-author" value="1" id="id_book_set-0-author" /><input type="hidden" name="book_set-0-id" value="1" id="id_book_set-0-id" /></p>') formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_book_set-0-title">Title:</label>'
'<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" value="Les Fleurs du Mal" maxlength="100" /><input type="hidden" name="book_set-1-author" value="1" id="id_book_set-1-author" /><input type="hidden" name="book_set-1-id" value="2" id="id_book_set-1-id" /></p>') '<input id="id_book_set-0-title" type="text" name="book_set-0-title" '
self.assertHTMLEqual(formset.forms[2].as_p(), 'value="Les Paradis Artificiels" maxlength="100" />'
'<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" value="Flowers of Evil" maxlength="100" /><input type="hidden" name="book_set-2-author" value="1" id="id_book_set-2-author" /><input type="hidden" name="book_set-2-id" value="3" id="id_book_set-2-id" /></p>') '<input type="hidden" name="book_set-0-author" value="1" id="id_book_set-0-author" />'
self.assertHTMLEqual(formset.forms[3].as_p(), '<input type="hidden" name="book_set-0-id" value="1" id="id_book_set-0-id" /></p>'
'<p><label for="id_book_set-3-title">Title:</label> <input id="id_book_set-3-title" type="text" name="book_set-3-title" maxlength="100" /><input type="hidden" name="book_set-3-author" value="1" id="id_book_set-3-author" /><input type="hidden" name="book_set-3-id" id="id_book_set-3-id" /></p>') )
self.assertHTMLEqual(formset.forms[4].as_p(), self.assertHTMLEqual(
'<p><label for="id_book_set-4-title">Title:</label> <input id="id_book_set-4-title" type="text" name="book_set-4-title" maxlength="100" /><input type="hidden" name="book_set-4-author" value="1" id="id_book_set-4-author" /><input type="hidden" name="book_set-4-id" id="id_book_set-4-id" /></p>') formset.forms[1].as_p(),
'<p><label for="id_book_set-1-title">Title:</label>'
'<input id="id_book_set-1-title" type="text" name="book_set-1-title" '
'value="Les Fleurs du Mal" maxlength="100" />'
'<input type="hidden" name="book_set-1-author" value="1" id="id_book_set-1-author" />'
'<input type="hidden" name="book_set-1-id" value="2" id="id_book_set-1-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_book_set-2-title">Title:</label>'
'<input id="id_book_set-2-title" type="text" name="book_set-2-title" '
'value="Flowers of Evil" maxlength="100" />'
'<input type="hidden" name="book_set-2-author" value="1" id="id_book_set-2-author" />'
'<input type="hidden" name="book_set-2-id" value="3" id="id_book_set-2-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[3].as_p(),
'<p><label for="id_book_set-3-title">Title:</label>'
'<input id="id_book_set-3-title" type="text" name="book_set-3-title" maxlength="100" />'
'<input type="hidden" name="book_set-3-author" value="1" id="id_book_set-3-author" />'
'<input type="hidden" name="book_set-3-id" id="id_book_set-3-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[4].as_p(),
'<p><label for="id_book_set-4-title">Title:</label>'
'<input id="id_book_set-4-title" type="text" name="book_set-4-title" maxlength="100" />'
'<input type="hidden" name="book_set-4-author" value="1" id="id_book_set-4-author" />'
'<input type="hidden" name="book_set-4-id" id="id_book_set-4-id" /></p>'
)
data = { data = {
'book_set-TOTAL_FORMS': '5', # the number of forms rendered 'book_set-TOTAL_FORMS': '5', # the number of forms rendered
@ -800,12 +956,28 @@ class ModelFormsetTest(TestCase):
custom_qs = Book.objects.filter(title__startswith='F') custom_qs = Book.objects.filter(title__startswith='F')
formset = AuthorBooksFormSet(instance=author, queryset=custom_qs) formset = AuthorBooksFormSet(instance=author, queryset=custom_qs)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" value="Flowers of Evil" maxlength="100" /><input type="hidden" name="book_set-0-author" value="1" id="id_book_set-0-author" /><input type="hidden" name="book_set-0-id" value="3" id="id_book_set-0-id" /></p>') formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_book_set-0-title">Title:</label>'
'<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" /><input type="hidden" name="book_set-1-author" value="1" id="id_book_set-1-author" /><input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>') '<input id="id_book_set-0-title" type="text" name="book_set-0-title" '
self.assertHTMLEqual(formset.forms[2].as_p(), 'value="Flowers of Evil" maxlength="100" />'
'<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" /><input type="hidden" name="book_set-2-author" value="1" id="id_book_set-2-author" /><input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>') '<input type="hidden" name="book_set-0-author" value="1" id="id_book_set-0-author" />'
'<input type="hidden" name="book_set-0-id" value="3" id="id_book_set-0-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_book_set-1-title">Title:</label>'
'<input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" />'
'<input type="hidden" name="book_set-1-author" value="1" id="id_book_set-1-author" />'
'<input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>'
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_book_set-2-title">Title:</label>'
'<input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" />'
'<input type="hidden" name="book_set-2-author" value="1" id="id_book_set-2-author" />'
'<input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>'
)
data = { data = {
'book_set-TOTAL_FORMS': '3', # the number of forms rendered 'book_set-TOTAL_FORMS': '3', # the number of forms rendered
@ -863,9 +1035,13 @@ class ModelFormsetTest(TestCase):
CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey, fields="__all__") CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey, fields="__all__")
formset = CustomPrimaryKeyFormSet() formset = CustomPrimaryKeyFormSet()
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-my_pk">My pk:</label> <input id="id_form-0-my_pk" type="text" name="form-0-my_pk" maxlength="10" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_form-0-some_field">Some field:</label> <input id="id_form-0-some_field" type="text" name="form-0-some_field" maxlength="100" /></p>') '<p><label for="id_form-0-my_pk">My pk:</label> <input id="id_form-0-my_pk" type="text" '
'name="form-0-my_pk" maxlength="10" /></p>'
'<p><label for="id_form-0-some_field">Some field:</label>'
'<input id="id_form-0-some_field" type="text" name="form-0-some_field" maxlength="100" /></p>'
)
# Custom primary keys with ForeignKey, OneToOneField and AutoField ############ # Custom primary keys with ForeignKey, OneToOneField and AutoField ############
@ -874,10 +1050,20 @@ class ModelFormsetTest(TestCase):
FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False, fields="__all__") FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False, fields="__all__")
formset = FormSet(instance=place) formset = FormSet(instance=place)
self.assertEqual(len(formset.forms), 2) self.assertEqual(len(formset.forms), 2)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_owner_set-0-name">Name:</label> <input id="id_owner_set-0-name" type="text" name="owner_set-0-name" maxlength="100" /><input type="hidden" name="owner_set-0-place" value="1" id="id_owner_set-0-place" /><input type="hidden" name="owner_set-0-auto_id" id="id_owner_set-0-auto_id" /></p>') formset.forms[0].as_p(),
self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_owner_set-0-name">Name:</label>'
'<p><label for="id_owner_set-1-name">Name:</label> <input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" /><input type="hidden" name="owner_set-1-place" value="1" id="id_owner_set-1-place" /><input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>') '<input id="id_owner_set-0-name" type="text" name="owner_set-0-name" maxlength="100" />'
'<input type="hidden" name="owner_set-0-place" value="1" id="id_owner_set-0-place" />'
'<input type="hidden" name="owner_set-0-auto_id" id="id_owner_set-0-auto_id" /></p>'
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_owner_set-1-name">Name:</label>'
'<input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" />'
'<input type="hidden" name="owner_set-1-place" value="1" id="id_owner_set-1-place" />'
'<input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>'
)
data = { data = {
'owner_set-TOTAL_FORMS': '2', 'owner_set-TOTAL_FORMS': '2',
@ -898,13 +1084,28 @@ class ModelFormsetTest(TestCase):
formset = FormSet(instance=place) formset = FormSet(instance=place)
self.assertEqual(len(formset.forms), 3) self.assertEqual(len(formset.forms), 3)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_owner_set-0-name">Name:</label> <input id="id_owner_set-0-name" type="text" name="owner_set-0-name" value="Joe Perry" maxlength="100" /><input type="hidden" name="owner_set-0-place" value="1" id="id_owner_set-0-place" /><input type="hidden" name="owner_set-0-auto_id" value="%d" id="id_owner_set-0-auto_id" /></p>' formset.forms[0].as_p(),
% owner1.auto_id) '<p><label for="id_owner_set-0-name">Name:</label>'
self.assertHTMLEqual(formset.forms[1].as_p(), '<input id="id_owner_set-0-name" type="text" name="owner_set-0-name" value="Joe Perry" maxlength="100" />'
'<p><label for="id_owner_set-1-name">Name:</label> <input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" /><input type="hidden" name="owner_set-1-place" value="1" id="id_owner_set-1-place" /><input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>') '<input type="hidden" name="owner_set-0-place" value="1" id="id_owner_set-0-place" />'
self.assertHTMLEqual(formset.forms[2].as_p(), '<input type="hidden" name="owner_set-0-auto_id" value="%d" id="id_owner_set-0-auto_id" /></p>'
'<p><label for="id_owner_set-2-name">Name:</label> <input id="id_owner_set-2-name" type="text" name="owner_set-2-name" maxlength="100" /><input type="hidden" name="owner_set-2-place" value="1" id="id_owner_set-2-place" /><input type="hidden" name="owner_set-2-auto_id" id="id_owner_set-2-auto_id" /></p>') % owner1.auto_id
)
self.assertHTMLEqual(
formset.forms[1].as_p(),
'<p><label for="id_owner_set-1-name">Name:</label>'
'<input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" />'
'<input type="hidden" name="owner_set-1-place" value="1" id="id_owner_set-1-place" />'
'<input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>'
)
self.assertHTMLEqual(
formset.forms[2].as_p(),
'<p><label for="id_owner_set-2-name">Name:</label>'
'<input id="id_owner_set-2-name" type="text" name="owner_set-2-name" maxlength="100" />'
'<input type="hidden" name="owner_set-2-place" value="1" id="id_owner_set-2-place" />'
'<input type="hidden" name="owner_set-2-auto_id" id="id_owner_set-2-auto_id" /></p>'
)
data = { data = {
'owner_set-TOTAL_FORMS': '3', 'owner_set-TOTAL_FORMS': '3',
@ -929,14 +1130,18 @@ class ModelFormsetTest(TestCase):
FormSet = modelformset_factory(OwnerProfile, fields="__all__") FormSet = modelformset_factory(OwnerProfile, fields="__all__")
formset = FormSet() formset = FormSet()
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_form-0-owner">Owner:</label> <select name="form-0-owner" id="id_form-0-owner">\n' formset.forms[0].as_p(),
'<option value="" selected="selected">---------</option>\n' '<p><label for="id_form-0-owner">Owner:</label>'
'<option value="%d">Joe Perry at Giordanos</option>\n' '<select name="form-0-owner" id="id_form-0-owner">'
'<option value="%d">Jack Berry at Giordanos</option>\n' '<option value="" selected="selected">---------</option>'
'</select></p>\n' '<option value="%d">Joe Perry at Giordanos</option>'
'<p><label for="id_form-0-age">Age:</label> <input type="number" name="form-0-age" id="id_form-0-age" min="0" /></p>' '<option value="%d">Jack Berry at Giordanos</option>'
% (owner1.auto_id, owner2.auto_id)) '</select></p>'
'<p><label for="id_form-0-age">Age:</label>'
'<input type="number" name="form-0-age" id="id_form-0-age" min="0" /></p>'
% (owner1.auto_id, owner2.auto_id)
)
owner1 = Owner.objects.get(name='Joe Perry') owner1 = Owner.objects.get(name='Joe Perry')
FormSet = inlineformset_factory(Owner, OwnerProfile, max_num=1, can_delete=False, fields="__all__") FormSet = inlineformset_factory(Owner, OwnerProfile, max_num=1, can_delete=False, fields="__all__")
@ -944,9 +1149,13 @@ class ModelFormsetTest(TestCase):
formset = FormSet(instance=owner1) formset = FormSet(instance=owner1)
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_ownerprofile-0-age">Age:</label> <input type="number" name="ownerprofile-0-age" id="id_ownerprofile-0-age" min="0" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' formset.forms[0].as_p(),
% owner1.auto_id) '<p><label for="id_ownerprofile-0-age">Age:</label>'
'<input type="number" name="ownerprofile-0-age" id="id_ownerprofile-0-age" min="0" />'
'<input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>'
% owner1.auto_id
)
data = { data = {
'ownerprofile-TOTAL_FORMS': '1', 'ownerprofile-TOTAL_FORMS': '1',
@ -965,9 +1174,13 @@ class ModelFormsetTest(TestCase):
formset = FormSet(instance=owner1) formset = FormSet(instance=owner1)
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_ownerprofile-0-age">Age:</label> <input type="number" name="ownerprofile-0-age" value="54" id="id_ownerprofile-0-age" min="0" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' formset.forms[0].as_p(),
% owner1.auto_id) '<p><label for="id_ownerprofile-0-age">Age:</label>'
'<input type="number" name="ownerprofile-0-age" value="54" id="id_ownerprofile-0-age" min="0" />'
'<input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>'
% owner1.auto_id
)
data = { data = {
'ownerprofile-TOTAL_FORMS': '1', 'ownerprofile-TOTAL_FORMS': '1',
@ -994,9 +1207,15 @@ class ModelFormsetTest(TestCase):
formset = FormSet(instance=place) formset = FormSet(instance=place)
self.assertEqual(len(formset.forms), 1) self.assertEqual(len(formset.forms), 1)
self.assertHTMLEqual(formset.forms[0].as_p(), self.assertHTMLEqual(
'<p><label for="id_location_set-0-lat">Lat:</label> <input id="id_location_set-0-lat" type="text" name="location_set-0-lat" maxlength="100" /></p>\n' formset.forms[0].as_p(),
'<p><label for="id_location_set-0-lon">Lon:</label> <input id="id_location_set-0-lon" type="text" name="location_set-0-lon" maxlength="100" /><input type="hidden" name="location_set-0-place" value="1" id="id_location_set-0-place" /><input type="hidden" name="location_set-0-id" id="id_location_set-0-id" /></p>') '<p><label for="id_location_set-0-lat">Lat:</label>'
'<input id="id_location_set-0-lat" type="text" name="location_set-0-lat" maxlength="100" /></p>'
'<p><label for="id_location_set-0-lon">Lon:</label> '
'<input id="id_location_set-0-lon" type="text" name="location_set-0-lon" maxlength="100" />'
'<input type="hidden" name="location_set-0-place" value="1" id="id_location_set-0-place" />'
'<input type="hidden" name="location_set-0-id" id="id_location_set-0-id" /></p>'
)
def test_foreign_keys_in_parents(self): def test_foreign_keys_in_parents(self):
self.assertEqual(type(_get_foreign_key(Restaurant, Owner)), models.ForeignKey) self.assertEqual(type(_get_foreign_key(Restaurant, Owner)), models.ForeignKey)
@ -1147,9 +1366,17 @@ class ModelFormsetTest(TestCase):
now = form.fields['date_joined'].initial() now = form.fields['date_joined'].initial()
result = form.as_p() result = form.as_p()
result = re.sub(r'[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]+)?', '__DATETIME__', result) result = re.sub(r'[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]+)?', '__DATETIME__', result)
self.assertHTMLEqual(result, self.assertHTMLEqual(
'<p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="__DATETIME__" id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="__DATETIME__" id="initial-membership_set-0-id_membership_set-0-date_joined" /></p>\n' result,
'<p><label for="id_membership_set-0-karma">Karma:</label> <input type="number" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-person" value="%d" id="id_membership_set-0-person" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>' '<p><label for="id_membership_set-0-date_joined">Date joined:</label>'
'<input type="text" name="membership_set-0-date_joined" '
'value="__DATETIME__" id="id_membership_set-0-date_joined" />'
'<input type="hidden" name="initial-membership_set-0-date_joined" value="__DATETIME__" '
'id="initial-membership_set-0-id_membership_set-0-date_joined" /></p>'
'<p><label for="id_membership_set-0-karma">Karma:</label>'
'<input type="number" name="membership_set-0-karma" id="id_membership_set-0-karma" />'
'<input type="hidden" name="membership_set-0-person" value="%d" id="id_membership_set-0-person" />'
'<input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>'
% person.id) % person.id)
# test for validation with callable defaults. Validations rely on hidden fields # test for validation with callable defaults. Validations rely on hidden fields
@ -1192,7 +1419,14 @@ class ModelFormsetTest(TestCase):
super(MembershipForm, self).__init__(**kwargs) super(MembershipForm, self).__init__(**kwargs)
self.fields['date_joined'].widget = forms.SplitDateTimeWidget() self.fields['date_joined'].widget = forms.SplitDateTimeWidget()
FormSet = inlineformset_factory(Person, Membership, form=MembershipForm, can_delete=False, extra=1, fields="__all__") FormSet = inlineformset_factory(
Person,
Membership,
form=MembershipForm,
can_delete=False,
extra=1,
fields="__all__",
)
data = { data = {
'membership_set-TOTAL_FORMS': '1', 'membership_set-TOTAL_FORMS': '1',
'membership_set-INITIAL_FORMS': '0', 'membership_set-INITIAL_FORMS': '0',

View File

@ -202,7 +202,10 @@ class InlineFormsetTests(TestCase):
FormSet(instance=None) FormSet(instance=None)
def test_empty_fields_on_modelformset(self): def test_empty_fields_on_modelformset(self):
"No fields passed to modelformset_factory should result in no fields on returned forms except for the id. See #14119." """
No fields passed to modelformset_factory() should result in no fields
on returned forms except for the id (#14119).
"""
UserFormSet = modelformset_factory(User, fields=()) UserFormSet = modelformset_factory(User, fields=())
formset = UserFormSet() formset = UserFormSet()
for form in formset.forms: for form in formset.forms:

View File

@ -248,13 +248,12 @@ class RelationTreeTests(SimpleTestCase):
self.assertEqual( self.assertEqual(
sorted([field.related_query_name() for field in BasePerson._meta._relation_tree]), sorted([field.related_query_name() for field in BasePerson._meta._relation_tree]),
sorted([ sorted([
'+', '_relating_basepeople_hidden_+', 'BasePerson_following_abstract+', 'BasePerson_following_abstract+', '+', '_relating_basepeople_hidden_+', 'BasePerson_following_abstract+',
'BasePerson_following_base+', 'BasePerson_following_base+', 'BasePerson_friends_abstract+', 'BasePerson_following_abstract+', 'BasePerson_following_base+', 'BasePerson_following_base+',
'BasePerson_friends_abstract+', 'BasePerson_friends_base+', 'BasePerson_friends_base+', 'BasePerson_friends_abstract+', 'BasePerson_friends_abstract+', 'BasePerson_friends_base+',
'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+', 'BasePerson_friends_base+', 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
'Relating_basepeople_hidden+', 'followers_abstract', 'Relating_basepeople_hidden+', 'followers_abstract', 'followers_base', 'friends_abstract_rel_+',
'followers_base', 'friends_abstract_rel_+', 'friends_base_rel_+', 'friends_base_rel_+', 'person', 'relating_basepeople', 'relating_baseperson',
'person', 'relating_basepeople', 'relating_baseperson',
]) ])
) )
self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], []) self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], [])

View File

@ -37,7 +37,8 @@ class ValidationTestModel(models.Model):
is_active = models.BooleanField(default=False) is_active = models.BooleanField(default=False)
pub_date = models.DateTimeField() pub_date = models.DateTimeField()
band = models.ForeignKey(Band, models.CASCADE) band = models.ForeignKey(Band, models.CASCADE)
no = models.IntegerField(verbose_name="Number", blank=True, null=True) # This field is intentionally 2 characters long. See #16080. # This field is intentionally 2 characters long (#16080).
no = models.IntegerField(verbose_name="Number", blank=True, null=True)
def decade_published_in(self): def decade_published_in(self):
return self.pub_date.strftime('%Y')[:3] + "0's" return self.pub_date.strftime('%Y')[:3] + "0's"

View File

@ -1029,9 +1029,11 @@ class ListDisplayLinksCheckTests(CheckTestCase):
list_display_links = ('non_existent_field',) list_display_links = ('non_existent_field',)
self.assertIsInvalid( self.assertIsInvalid(
ValidationTestModelAdmin, ValidationTestModel, ValidationTestModelAdmin, ValidationTestModel, (
"The value of 'list_display_links[0]' refers to 'non_existent_field', which is not defined in 'list_display'.", "The value of 'list_display_links[0]' refers to "
'admin.E111') "'non_existent_field', which is not defined in 'list_display'."
), 'admin.E111'
)
def test_missing_in_list_display(self): def test_missing_in_list_display(self):
class ValidationTestModelAdmin(ModelAdmin): class ValidationTestModelAdmin(ModelAdmin):
@ -1244,9 +1246,10 @@ class OrderingCheckTests(CheckTestCase):
self.assertIsInvalid( self.assertIsInvalid(
ValidationTestModelAdmin, ValidationTestModelAdmin,
ValidationTestModel, ValidationTestModel, (
"The value of 'ordering[0]' refers to 'non_existent_field', which is not an attribute of 'modeladmin.ValidationTestModel'.", "The value of 'ordering[0]' refers to 'non_existent_field', "
'admin.E033', "which is not an attribute of 'modeladmin.ValidationTestModel'."
), 'admin.E033'
) )
def test_random_marker_not_alone(self): def test_random_marker_not_alone(self):

View File

@ -188,15 +188,23 @@ class QueryTestCase(TestCase):
self.assertEqual(Book.authors.through.objects.using('other').count(), 1) self.assertEqual(Book.authors.through.objects.using('other').count(), 1)
# Check that queries work across m2m joins # Check that queries work across m2m joins
self.assertEqual(list(Book.objects.using('default').filter(authors__name='Marty Alchin').values_list('title', flat=True)), self.assertEqual(
['Pro Django']) list(Book.objects.using('default').filter(authors__name='Marty Alchin').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Marty Alchin').values_list('title', flat=True)), ['Pro Django']
[]) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='Marty Alchin').values_list('title', flat=True)),
[]
)
self.assertEqual(list(Book.objects.using('default').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEqual(
[]) list(Book.objects.using('default').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), []
['Dive into Python']) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
['Dive into Python']
)
# Reget the objects to clear caches # Reget the objects to clear caches
dive = Book.objects.using('other').get(title="Dive into Python") dive = Book.objects.using('other').get(title="Dive into Python")
@ -222,35 +230,53 @@ class QueryTestCase(TestCase):
# Add a second author # Add a second author
john = Person.objects.using('other').create(name="John Smith") john = Person.objects.using('other').create(name="John Smith")
self.assertEqual(list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)), self.assertEqual(
[]) list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)),
[]
)
dive.authors.add(john) dive.authors.add(john)
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEqual(
['Dive into Python']) list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)), ['Dive into Python']
['Dive into Python']) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)),
['Dive into Python']
)
# Remove the second author # Remove the second author
dive.authors.remove(john) dive.authors.remove(john)
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEqual(
['Dive into Python']) list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)), ['Dive into Python']
[]) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)),
[]
)
# Clear all authors # Clear all authors
dive.authors.clear() dive.authors.clear()
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEqual(
[]) list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)), []
[]) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)),
[]
)
# Create an author through the m2m interface # Create an author through the m2m interface
dive.authors.create(name='Jane Brown') dive.authors.create(name='Jane Brown')
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEqual(
[]) list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
self.assertEqual(list(Book.objects.using('other').filter(authors__name='Jane Brown').values_list('title', flat=True)), []
['Dive into Python']) )
self.assertEqual(
list(Book.objects.using('other').filter(authors__name='Jane Brown').values_list('title', flat=True)),
['Dive into Python']
)
def test_m2m_reverse_operations(self): def test_m2m_reverse_operations(self):
"M2M reverse manipulations are all constrained to a single DB" "M2M reverse manipulations are all constrained to a single DB"
@ -269,31 +295,53 @@ class QueryTestCase(TestCase):
# Add a books to the m2m # Add a books to the m2m
mark.book_set.add(grease) mark.book_set.add(grease)
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
['Mark Pilgrim']) list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)), ['Mark Pilgrim']
['Mark Pilgrim']) )
self.assertEqual(
list(
Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)
),
['Mark Pilgrim']
)
# Remove a book from the m2m # Remove a book from the m2m
mark.book_set.remove(grease) mark.book_set.remove(grease)
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
['Mark Pilgrim']) list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)), ['Mark Pilgrim']
[]) )
self.assertEqual(
list(
Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)
),
[]
)
# Clear the books associated with mark # Clear the books associated with mark
mark.book_set.clear() mark.book_set.clear()
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)), []
[]) )
self.assertEqual(
list(
Person.objects.using('other').filter(book__title='Greasemonkey Hacks').values_list('name', flat=True)
),
[]
)
# Create a book through the m2m interface # Create a book through the m2m interface
mark.book_set.create(title="Dive into HTML5", published=datetime.date(2020, 1, 1)) mark.book_set.create(title="Dive into HTML5", published=datetime.date(2020, 1, 1))
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into HTML5').values_list('name', flat=True)), []
['Mark Pilgrim']) )
self.assertEqual(
list(Person.objects.using('other').filter(book__title='Dive into HTML5').values_list('name', flat=True)),
['Mark Pilgrim']
)
def test_m2m_cross_database_protection(self): def test_m2m_cross_database_protection(self):
"Operations that involve sharing M2M objects across databases raise an error" "Operations that involve sharing M2M objects across databases raise an error"
@ -421,15 +469,27 @@ class QueryTestCase(TestCase):
self.assertEqual(dive.editor.name, "Chris Mills") self.assertEqual(dive.editor.name, "Chris Mills")
# Check that queries work across foreign key joins # Check that queries work across foreign key joins
self.assertEqual(list(Person.objects.using('default').filter(edited__title='Pro Django').values_list('name', flat=True)), self.assertEqual(
['George Vilches']) list(Person.objects.using('default').filter(edited__title='Pro Django').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Pro Django').values_list('name', flat=True)), ['George Vilches']
[]) )
self.assertEqual(
list(Person.objects.using('other').filter(edited__title='Pro Django').values_list('name', flat=True)),
[]
)
self.assertEqual(list(Person.objects.using('default').filter(edited__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
[]) list(
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), Person.objects.using('default').filter(edited__title='Dive into Python').values_list('name', flat=True)
['Chris Mills']) ),
[]
)
self.assertEqual(
list(
Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)
),
['Chris Mills']
)
# Reget the objects to clear caches # Reget the objects to clear caches
chris = Person.objects.using('other').get(name="Chris Mills") chris = Person.objects.using('other').get(name="Chris Mills")
@ -452,37 +512,65 @@ class QueryTestCase(TestCase):
# Add a second book edited by chris # Add a second book edited by chris
html5 = Book.objects.using('other').create(title="Dive into HTML5", published=datetime.date(2010, 3, 15)) html5 = Book.objects.using('other').create(title="Dive into HTML5", published=datetime.date(2010, 3, 15))
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)),
[]
)
chris.edited.add(html5) chris.edited.add(html5)
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)), self.assertEqual(
['Chris Mills']) list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), ['Chris Mills']
['Chris Mills']) )
self.assertEqual(
list(
Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)
),
['Chris Mills']
)
# Remove the second editor # Remove the second editor
chris.edited.remove(html5) chris.edited.remove(html5)
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), []
['Chris Mills']) )
self.assertEqual(
list(
Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)
),
['Chris Mills']
)
# Clear all edited books # Clear all edited books
chris.edited.clear() chris.edited.clear()
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), []
[]) )
self.assertEqual(
list(
Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)
),
[]
)
# Create an author through the m2m interface # Create an author through the m2m interface
chris.edited.create(title='Dive into Water', published=datetime.date(2010, 3, 15)) chris.edited.create(title='Dive into Water', published=datetime.date(2010, 3, 15))
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(edited__title='Dive into HTML5').values_list('name', flat=True)),
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Water').values_list('name', flat=True)), []
['Chris Mills']) )
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), self.assertEqual(
[]) list(Person.objects.using('other').filter(edited__title='Dive into Water').values_list('name', flat=True)),
['Chris Mills']
)
self.assertEqual(
list(
Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)
),
[]
)
def test_foreign_key_cross_database_protection(self): def test_foreign_key_cross_database_protection(self):
"Operations that involve sharing FK objects across databases raise an error" "Operations that involve sharing FK objects across databases raise an error"
@ -556,15 +644,35 @@ class QueryTestCase(TestCase):
self.assertEqual(bob.userprofile.flavor, "crunchy frog") self.assertEqual(bob.userprofile.flavor, "crunchy frog")
# Check that queries work across joins # Check that queries work across joins
self.assertEqual(list(User.objects.using('default').filter(userprofile__flavor='chocolate').values_list('username', flat=True)), self.assertEqual(
['alice']) list(
self.assertEqual(list(User.objects.using('other').filter(userprofile__flavor='chocolate').values_list('username', flat=True)), User.objects.using('default')
[]) .filter(userprofile__flavor='chocolate').values_list('username', flat=True)
),
['alice']
)
self.assertEqual(
list(
User.objects.using('other')
.filter(userprofile__flavor='chocolate').values_list('username', flat=True)
),
[]
)
self.assertEqual(list(User.objects.using('default').filter(userprofile__flavor='crunchy frog').values_list('username', flat=True)), self.assertEqual(
[]) list(
self.assertEqual(list(User.objects.using('other').filter(userprofile__flavor='crunchy frog').values_list('username', flat=True)), User.objects.using('default')
['bob']) .filter(userprofile__flavor='crunchy frog').values_list('username', flat=True)
),
[]
)
self.assertEqual(
list(
User.objects.using('other')
.filter(userprofile__flavor='crunchy frog').values_list('username', flat=True)
),
['bob']
)
# Reget the objects to clear caches # Reget the objects to clear caches
alice_profile = UserProfile.objects.using('default').get(flavor='chocolate') alice_profile = UserProfile.objects.using('default').get(flavor='chocolate')
@ -683,38 +791,58 @@ class QueryTestCase(TestCase):
review1 = Review.objects.using('other').create(source="Python Weekly", content_object=dive) review1 = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
review2 = Review.objects.using('other').create(source="Python Monthly", content_object=temp) review2 = Review.objects.using('other').create(source="Python Monthly", content_object=temp)
self.assertEqual(list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEqual(
[]) list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), []
['Python Weekly']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Weekly']
)
# Add a second review # Add a second review
dive.reviews.add(review2) dive.reviews.add(review2)
self.assertEqual(list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEqual(
[]) list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), []
['Python Monthly', 'Python Weekly']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Monthly', 'Python Weekly']
)
# Remove the second author # Remove the second author
dive.reviews.remove(review1) dive.reviews.remove(review1)
self.assertEqual(list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEqual(
[]) list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), []
['Python Monthly']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Monthly']
)
# Clear all reviews # Clear all reviews
dive.reviews.clear() dive.reviews.clear()
self.assertEqual(list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEqual(
[]) list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), []
[]) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
[]
)
# Create an author through the generic interface # Create an author through the generic interface
dive.reviews.create(source='Python Daily') dive.reviews.create(source='Python Daily')
self.assertEqual(list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEqual(
[]) list(Review.objects.using('default').filter(object_id=dive.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), []
['Python Daily']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Daily']
)
def test_generic_key_cross_database_protection(self): def test_generic_key_cross_database_protection(self):
"Operations that involve sharing generic key objects across databases raise an error" "Operations that involve sharing generic key objects across databases raise an error"
@ -750,17 +878,25 @@ class QueryTestCase(TestCase):
review3.content_object = dive review3.content_object = dive
self.assertEqual(review3._state.db, 'other') self.assertEqual(review3._state.db, 'other')
# ... but it isn't saved yet # ... but it isn't saved yet
self.assertEqual(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)), self.assertEqual(
['Python Monthly']) list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), ['Python Monthly']
['Python Weekly']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Weekly']
)
# When saved, John goes to 'other' # When saved, John goes to 'other'
review3.save() review3.save()
self.assertEqual(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)), self.assertEqual(
['Python Monthly']) list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
self.assertEqual(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), ['Python Monthly']
['Python Daily', 'Python Weekly']) )
self.assertEqual(
list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
['Python Daily', 'Python Weekly']
)
def test_generic_key_deletion(self): def test_generic_key_deletion(self):
"Cascaded deletions of Generic Key relations issue queries on the right database" "Cascaded deletions of Generic Key relations issue queries on the right database"
@ -1178,7 +1314,10 @@ class RouterTestCase(TestCase):
self.assertEqual(cheesecake._state.db, 'default') self.assertEqual(cheesecake._state.db, 'default')
# Same goes for get_or_create, regardless of whether getting or creating # Same goes for get_or_create, regardless of whether getting or creating
cheesecake, created = mark.edited.get_or_create(title='Dive into Cheesecake', published=datetime.date(2010, 3, 15)) cheesecake, created = mark.edited.get_or_create(
title='Dive into Cheesecake',
published=datetime.date(2010, 3, 15),
)
self.assertEqual(cheesecake._state.db, 'default') self.assertEqual(cheesecake._state.db, 'default')
puddles, created = mark.edited.get_or_create(title='Dive into Puddles', published=datetime.date(2010, 3, 15)) puddles, created = mark.edited.get_or_create(title='Dive into Puddles', published=datetime.date(2010, 3, 15))
@ -1589,7 +1728,10 @@ class FixtureTestCase(TestCase):
@override_settings(DATABASE_ROUTERS=[AntiPetRouter()]) @override_settings(DATABASE_ROUTERS=[AntiPetRouter()])
def test_pseudo_empty_fixtures(self): def test_pseudo_empty_fixtures(self):
"A fixture can contain entries, but lead to nothing in the database; this shouldn't raise an error (ref #14068)" """
A fixture can contain entries, but lead to nothing in the database;
this shouldn't raise an error (#14068).
"""
new_io = StringIO() new_io = StringIO()
management.call_command('loaddata', 'pets', stdout=new_io, stderr=new_io) management.call_command('loaddata', 'pets', stdout=new_io, stderr=new_io)
command_output = new_io.getvalue().strip() command_output = new_io.getvalue().strip()

View File

@ -140,7 +140,10 @@ class DeeplyNestedForeignKeysTests(TestCase):
self.assertEqual(len(Event.objects.values()), 2) self.assertEqual(len(Event.objects.values()), 2)
self.assertEqual(len(Event.objects.values('screening__movie__director__pk')), 2) self.assertEqual(len(Event.objects.values('screening__movie__director__pk')), 2)
self.assertEqual(len(Event.objects.values('screening__movie__director__name')), 2) self.assertEqual(len(Event.objects.values('screening__movie__director__name')), 2)
self.assertEqual(len(Event.objects.values('screening__movie__director__pk', 'screening__movie__director__name')), 2) self.assertEqual(
len(Event.objects.values('screening__movie__director__pk', 'screening__movie__director__name')),
2
)
self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2) self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2)
self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2) self.assertEqual(len(Event.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2)
self.assertEqual(len(Event.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2) self.assertEqual(len(Event.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2)
@ -160,7 +163,10 @@ class DeeplyNestedForeignKeysTests(TestCase):
self.assertEqual(len(Package.objects.values()), 2) self.assertEqual(len(Package.objects.values()), 2)
self.assertEqual(len(Package.objects.values('screening__movie__director__pk')), 2) self.assertEqual(len(Package.objects.values('screening__movie__director__pk')), 2)
self.assertEqual(len(Package.objects.values('screening__movie__director__name')), 2) self.assertEqual(len(Package.objects.values('screening__movie__director__name')), 2)
self.assertEqual(len(Package.objects.values('screening__movie__director__pk', 'screening__movie__director__name')), 2) self.assertEqual(
len(Package.objects.values('screening__movie__director__pk', 'screening__movie__director__name')),
2
)
self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2) self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__pk')), 2)
self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2) self.assertEqual(len(Package.objects.values('screening__movie__pk', 'screening__movie__director__name')), 2)
self.assertEqual(len(Package.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2) self.assertEqual(len(Package.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2)

View File

@ -24,7 +24,10 @@ class OrLookupsTests(TestCase):
def test_filter_or(self): def test_filter_or(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
Article.objects.filter(headline__startswith='Hello') | Article.objects.filter(headline__startswith='Goodbye'), [ (
Article.objects.filter(headline__startswith='Hello')
| Article.objects.filter(headline__startswith='Goodbye')
), [
'Hello', 'Hello',
'Goodbye', 'Goodbye',
'Hello and goodbye' 'Hello and goodbye'

View File

@ -15,7 +15,9 @@ class Migration(migrations.Migration):
name='CharTextArrayIndexModel', name='CharTextArrayIndexModel',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('char', django.contrib.postgres.fields.ArrayField(models.CharField(max_length=10), db_index=True, size=100)), ('char', django.contrib.postgres.fields.ArrayField(
models.CharField(max_length=10), db_index=True, size=100)
),
('char2', models.CharField(max_length=11, db_index=True)), ('char2', models.CharField(max_length=11, db_index=True)),
('text', django.contrib.postgres.fields.ArrayField(models.TextField(), db_index=True)), ('text', django.contrib.postgres.fields.ArrayField(models.TextField(), db_index=True)),
], ],

View File

@ -341,7 +341,9 @@ class TestMigrations(TransactionTestCase):
class TestSerialization(PostgreSQLTestCase): class TestSerialization(PostgreSQLTestCase):
test_data = '[{"fields": {"field": "[\\"1\\", \\"2\\"]"}, "model": "postgres_tests.integerarraymodel", "pk": null}]' test_data = (
'[{"fields": {"field": "[\\"1\\", \\"2\\"]"}, "model": "postgres_tests.integerarraymodel", "pk": null}]'
)
def test_dumping(self): def test_dumping(self):
instance = IntegerArrayModel(field=[1, 2]) instance = IntegerArrayModel(field=[1, 2])
@ -360,7 +362,10 @@ class TestValidation(PostgreSQLTestCase):
with self.assertRaises(exceptions.ValidationError) as cm: with self.assertRaises(exceptions.ValidationError) as cm:
field.clean([1, None], None) field.clean([1, None], None)
self.assertEqual(cm.exception.code, 'item_invalid') self.assertEqual(cm.exception.code, 'item_invalid')
self.assertEqual(cm.exception.message % cm.exception.params, 'Item 1 in the array did not validate: This field cannot be null.') self.assertEqual(
cm.exception.message % cm.exception.params,
'Item 1 in the array did not validate: This field cannot be null.'
)
def test_blank_true(self): def test_blank_true(self):
field = ArrayField(models.IntegerField(blank=True, null=True)) field = ArrayField(models.IntegerField(blank=True, null=True))
@ -388,7 +393,10 @@ class TestValidation(PostgreSQLTestCase):
with self.assertRaises(exceptions.ValidationError) as cm: with self.assertRaises(exceptions.ValidationError) as cm:
field.clean([0], None) field.clean([0], None)
self.assertEqual(cm.exception.code, 'item_invalid') self.assertEqual(cm.exception.code, 'item_invalid')
self.assertEqual(cm.exception.messages[0], 'Item 0 in the array did not validate: Ensure this value is greater than or equal to 1.') self.assertEqual(
cm.exception.messages[0],
'Item 0 in the array did not validate: Ensure this value is greater than or equal to 1.'
)
class TestSimpleFormField(PostgreSQLTestCase): class TestSimpleFormField(PostgreSQLTestCase):

View File

@ -627,5 +627,6 @@ class TestWidget(PostgreSQLTestCase):
) )
self.assertHTMLEqual( self.assertHTMLEqual(
f.widget.render('datetimerange', dt_range), f.widget.render('datetimerange', dt_range),
'<input type="text" name="datetimerange_0" value="2006-01-10 07:30:00" /><input type="text" name="datetimerange_1" value="2006-02-12 09:50:00" />' '<input type="text" name="datetimerange_0" value="2006-01-10 07:30:00" />'
'<input type="text" name="datetimerange_1" value="2006-02-12 09:50:00" />'
) )

View File

@ -313,7 +313,10 @@ class CustomPrefetchTests(TestCase):
# Ambiguous: Lookup houses_lst doesn't yet exist when performing houses_lst__rooms. # Ambiguous: Lookup houses_lst doesn't yet exist when performing houses_lst__rooms.
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
self.traverse_qs( self.traverse_qs(
Person.objects.prefetch_related('houses_lst__rooms', Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst')), Person.objects.prefetch_related(
'houses_lst__rooms',
Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst')
),
[['houses', 'rooms']] [['houses', 'rooms']]
) )
@ -324,7 +327,10 @@ class CustomPrefetchTests(TestCase):
) )
self.traverse_qs( self.traverse_qs(
Person.objects.prefetch_related('houses__rooms', Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst')), Person.objects.prefetch_related(
'houses__rooms',
Prefetch('houses', queryset=House.objects.all(), to_attr='houses_lst')
),
[['houses', 'rooms']] [['houses', 'rooms']]
) )
@ -537,8 +543,15 @@ class CustomPrefetchTests(TestCase):
# Test queryset filtering. # Test queryset filtering.
with self.assertNumQueries(2): with self.assertNumQueries(2):
lst2 = list(Person.objects.prefetch_related( lst2 = list(
Prefetch('houses', queryset=House.objects.filter(pk__in=[self.house1.pk, self.house3.pk]), to_attr='houses_lst'))) Person.objects.prefetch_related(
Prefetch(
'houses',
queryset=House.objects.filter(pk__in=[self.house1.pk, self.house3.pk]),
to_attr='houses_lst',
)
)
)
self.assertEqual(len(lst2[0].houses_lst), 1) self.assertEqual(len(lst2[0].houses_lst), 1)
self.assertEqual(lst2[0].houses_lst[0], self.house1) self.assertEqual(lst2[0].houses_lst[0], self.house1)
self.assertEqual(len(lst2[1].houses_lst), 1) self.assertEqual(len(lst2[1].houses_lst), 1)
@ -596,10 +609,14 @@ class CustomPrefetchTests(TestCase):
rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.all(), to_attr='house_attr')) rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.all(), to_attr='house_attr'))
lst2 = self.traverse_qs(rooms, [['house_attr', 'owner']]) lst2 = self.traverse_qs(rooms, [['house_attr', 'owner']])
self.assertEqual(lst1, lst2) self.assertEqual(lst1, lst2)
room = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.filter(address='DoesNotExist'))).first() room = Room.objects.all().prefetch_related(
Prefetch('house', queryset=houses.filter(address='DoesNotExist'))
).first()
with self.assertRaises(ObjectDoesNotExist): with self.assertRaises(ObjectDoesNotExist):
getattr(room, 'house') getattr(room, 'house')
room = Room.objects.all().prefetch_related(Prefetch('house', queryset=houses.filter(address='DoesNotExist'), to_attr='house_attr')).first() room = Room.objects.all().prefetch_related(
Prefetch('house', queryset=houses.filter(address='DoesNotExist'), to_attr='house_attr')
).first()
self.assertIsNone(room.house_attr) self.assertIsNone(room.house_attr)
rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=House.objects.only('name'))) rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=House.objects.only('name')))
with self.assertNumQueries(2): with self.assertNumQueries(2):
@ -617,13 +634,21 @@ class CustomPrefetchTests(TestCase):
lst2 = self.traverse_qs(rooms, [['main_room_of', 'owner']]) lst2 = self.traverse_qs(rooms, [['main_room_of', 'owner']])
self.assertEqual(lst1, lst2) self.assertEqual(lst1, lst2)
with self.assertNumQueries(2): with self.assertNumQueries(2):
rooms = list(Room.objects.all().prefetch_related(Prefetch('main_room_of', queryset=houses.all(), to_attr='main_room_of_attr'))) rooms = list(
Room.objects.all().prefetch_related(
Prefetch('main_room_of', queryset=houses.all(), to_attr='main_room_of_attr')
)
)
lst2 = self.traverse_qs(rooms, [['main_room_of_attr', 'owner']]) lst2 = self.traverse_qs(rooms, [['main_room_of_attr', 'owner']])
self.assertEqual(lst1, lst2) self.assertEqual(lst1, lst2)
room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'))).first() room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(
Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'))
).first()
with self.assertRaises(ObjectDoesNotExist): with self.assertRaises(ObjectDoesNotExist):
getattr(room, 'main_room_of') getattr(room, 'main_room_of')
room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'), to_attr='main_room_of_attr')).first() room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(
Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'), to_attr='main_room_of_attr')
).first()
self.assertIsNone(room.main_room_of_attr) self.assertIsNone(room.main_room_of_attr)
def test_nested_prefetch_related_are_not_overwritten(self): def test_nested_prefetch_related_are_not_overwritten(self):

View File

@ -227,11 +227,25 @@ class Queries1Tests(BaseQuerysetTest):
4 4
) )
self.assertEqual( self.assertEqual(
Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name', 'foo').distinct().count(), (
Item.objects
.exclude(name='two')
.extra(select={'foo': '%s'}, select_params=(1,))
.values('creator', 'name', 'foo')
.distinct()
.count()
),
4 4
) )
self.assertEqual( self.assertEqual(
Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name').distinct().count(), (
Item.objects
.exclude(name='two')
.extra(select={'foo': '%s'}, select_params=(1,))
.values('creator', 'name')
.distinct()
.count()
),
4 4
) )
xx.delete() xx.delete()
@ -355,7 +369,10 @@ class Queries1Tests(BaseQuerysetTest):
# involve one "left outer" join (Author -> Item is 0-to-many). # involve one "left outer" join (Author -> Item is 0-to-many).
qs = Author.objects.filter(id=self.a1.id).filter(Q(extra__note=self.n1) | Q(item__note=self.n3)) qs = Author.objects.filter(id=self.a1.id).filter(Q(extra__note=self.n1) | Q(item__note=self.n3))
self.assertEqual( self.assertEqual(
len([x for x in qs.query.alias_map.values() if x.join_type == LOUTER and qs.query.alias_refcount[x.table_alias]]), len([
x for x in qs.query.alias_map.values()
if x.join_type == LOUTER and qs.query.alias_refcount[x.table_alias]
]),
1 1
) )
@ -568,7 +585,13 @@ class Queries1Tests(BaseQuerysetTest):
self.assertEqual(d, {'a': 'one', 'b': 'two'}) self.assertEqual(d, {'a': 'one', 'b': 'two'})
# Order by the number of tags attached to an item. # Order by the number of tags attached to an item.
l = Item.objects.extra(select={'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'}).order_by('-count') l = (
Item.objects
.extra(select={
'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'
})
.order_by('-count')
)
self.assertEqual([o.count for o in l], [2, 2, 1, 0]) self.assertEqual([o.count for o in l], [2, 2, 1, 0])
def test_ticket6154(self): def test_ticket6154(self):
@ -704,7 +727,9 @@ class Queries1Tests(BaseQuerysetTest):
def test_ticket7277(self): def test_ticket7277(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
self.n1.annotation_set.filter(Q(tag=self.t5) | Q(tag__children=self.t5) | Q(tag__children__children=self.t5)), self.n1.annotation_set.filter(
Q(tag=self.t5) | Q(tag__children=self.t5) | Q(tag__children__children=self.t5)
),
['<Annotation: a1>'] ['<Annotation: a1>']
) )
@ -1376,12 +1401,19 @@ class Queries4Tests(BaseQuerysetTest):
self.assertEqual(str(q1.query), str(q2.query)) self.assertEqual(str(q1.query), str(q2.query))
q1 = Item.objects.filter(Q(creator=self.a1) | Q(creator__report__name='r1')).order_by() q1 = Item.objects.filter(Q(creator=self.a1) | Q(creator__report__name='r1')).order_by()
q2 = Item.objects.filter(Q(creator=self.a1)).order_by() | Item.objects.filter(Q(creator__report__name='r1')).order_by() q2 = (
Item.objects
.filter(Q(creator=self.a1)).order_by() | Item.objects.filter(Q(creator__report__name='r1'))
.order_by()
)
self.assertQuerysetEqual(q1, ["<Item: i1>"]) self.assertQuerysetEqual(q1, ["<Item: i1>"])
self.assertEqual(str(q1.query), str(q2.query)) self.assertEqual(str(q1.query), str(q2.query))
q1 = Item.objects.filter(Q(creator__report__name='e1') | Q(creator=self.a1)).order_by() q1 = Item.objects.filter(Q(creator__report__name='e1') | Q(creator=self.a1)).order_by()
q2 = Item.objects.filter(Q(creator__report__name='e1')).order_by() | Item.objects.filter(Q(creator=self.a1)).order_by() q2 = (
Item.objects.filter(Q(creator__report__name='e1')).order_by()
| Item.objects.filter(Q(creator=self.a1)).order_by()
)
self.assertQuerysetEqual(q1, ["<Item: i1>"]) self.assertQuerysetEqual(q1, ["<Item: i1>"])
self.assertEqual(str(q1.query), str(q2.query)) self.assertEqual(str(q1.query), str(q2.query))
@ -2621,7 +2653,10 @@ class DefaultValuesInsertTest(TestCase):
try: try:
DumbCategory.objects.create() DumbCategory.objects.create()
except TypeError: except TypeError:
self.fail("Creation of an instance of a model with only the PK field shouldn't error out after bulk insert refactoring (#17056)") self.fail(
"Creation of an instance of a model with only the PK field "
"shouldn't error out after bulk insert refactoring (#17056)"
)
class ExcludeTests(TestCase): class ExcludeTests(TestCase):
@ -3524,7 +3559,10 @@ class RelatedLookupTypeTests(TestCase):
# child objects # child objects
self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.coa]), []) self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.coa]), [])
self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.poa, self.coa]).order_by('name'), out_b) self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=[self.poa, self.coa]).order_by('name'), out_b)
self.assertQuerysetEqual(ObjectB.objects.filter(objecta__in=iter([self.poa, self.coa])).order_by('name'), out_b) self.assertQuerysetEqual(
ObjectB.objects.filter(objecta__in=iter([self.poa, self.coa])).order_by('name'),
out_b
)
# parent objects # parent objects
self.assertQuerysetEqual(ObjectC.objects.exclude(childobjecta=self.oa), out_c) self.assertQuerysetEqual(ObjectC.objects.exclude(childobjecta=self.oa), out_c)

View File

@ -16,10 +16,26 @@ class RawQueryTests(TestCase):
cls.a2 = Author.objects.create(first_name='Jill', last_name='Doe', dob=date(1920, 4, 2)) cls.a2 = Author.objects.create(first_name='Jill', last_name='Doe', dob=date(1920, 4, 2))
cls.a3 = Author.objects.create(first_name='Bob', last_name='Smith', dob=date(1986, 1, 25)) cls.a3 = Author.objects.create(first_name='Bob', last_name='Smith', dob=date(1986, 1, 25))
cls.a4 = Author.objects.create(first_name='Bill', last_name='Jones', dob=date(1932, 5, 10)) cls.a4 = Author.objects.create(first_name='Bill', last_name='Jones', dob=date(1932, 5, 10))
cls.b1 = Book.objects.create(title='The awesome book', author=cls.a1, paperback=False, opening_line='It was a bright cold day in April and the clocks were striking thirteen.') cls.b1 = Book.objects.create(
cls.b2 = Book.objects.create(title='The horrible book', author=cls.a1, paperback=True, opening_line='On an evening in the latter part of May a middle-aged man was walking homeward from Shaston to the village of Marlott, in the adjoining Vale of Blakemore, or Blackmoor.') title='The awesome book', author=cls.a1, paperback=False,
cls.b3 = Book.objects.create(title='Another awesome book', author=cls.a1, paperback=False, opening_line='A squat grey building of only thirty-four stories.') opening_line='It was a bright cold day in April and the clocks were striking thirteen.',
cls.b4 = Book.objects.create(title='Some other book', author=cls.a3, paperback=True, opening_line='It was the day my grandmother exploded.') )
cls.b2 = Book.objects.create(
title='The horrible book', author=cls.a1, paperback=True,
opening_line=(
'On an evening in the latter part of May a middle-aged man '
'was walking homeward from Shaston to the village of Marlott, '
'in the adjoining Vale of Blakemore, or Blackmoor.'
),
)
cls.b3 = Book.objects.create(
title='Another awesome book', author=cls.a1, paperback=False,
opening_line='A squat grey building of only thirty-four stories.',
)
cls.b4 = Book.objects.create(
title='Some other book', author=cls.a3, paperback=True,
opening_line='It was the day my grandmother exploded.',
)
cls.c1 = Coffee.objects.create(brand='dunkin doughnuts') cls.c1 = Coffee.objects.create(brand='dunkin doughnuts')
cls.c2 = Coffee.objects.create(brand='starbucks') cls.c2 = Coffee.objects.create(brand='starbucks')
cls.r1 = Reviewer.objects.create() cls.r1 = Reviewer.objects.create()
@ -211,7 +227,12 @@ class RawQueryTests(TestCase):
pass pass
def test_annotations(self): def test_annotations(self):
query = "SELECT a.*, count(b.id) as book_count FROM raw_query_author a LEFT JOIN raw_query_book b ON a.id = b.author_id GROUP BY a.id, a.first_name, a.last_name, a.dob ORDER BY a.id" query = (
"SELECT a.*, count(b.id) as book_count "
"FROM raw_query_author a "
"LEFT JOIN raw_query_book b ON a.id = b.author_id "
"GROUP BY a.id, a.first_name, a.last_name, a.dob ORDER BY a.id"
)
expected_annotations = ( expected_annotations = (
('book_count', 3), ('book_count', 3),
('book_count', 0), ('book_count', 0),

View File

@ -88,10 +88,20 @@ class RequestsTests(SimpleTestCase):
Refs #20169. Refs #20169.
""" """
# With trailing slash # With trailing slash
request = WSGIRequest({'PATH_INFO': '/somepath/', 'SCRIPT_NAME': '/PREFIX/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')}) request = WSGIRequest({
'PATH_INFO': '/somepath/',
'SCRIPT_NAME': '/PREFIX/',
'REQUEST_METHOD': 'get',
'wsgi.input': BytesIO(b''),
})
self.assertEqual(request.path, '/PREFIX/somepath/') self.assertEqual(request.path, '/PREFIX/somepath/')
# Without trailing slash # Without trailing slash
request = WSGIRequest({'PATH_INFO': '/somepath/', 'SCRIPT_NAME': '/PREFIX', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')}) request = WSGIRequest({
'PATH_INFO': '/somepath/',
'SCRIPT_NAME': '/PREFIX',
'REQUEST_METHOD': 'get',
'wsgi.input': BytesIO(b''),
})
self.assertEqual(request.path, '/PREFIX/somepath/') self.assertEqual(request.path, '/PREFIX/somepath/')
def test_wsgirequest_with_force_script_name(self): def test_wsgirequest_with_force_script_name(self):
@ -101,7 +111,12 @@ class RequestsTests(SimpleTestCase):
Refs #20169. Refs #20169.
""" """
with override_settings(FORCE_SCRIPT_NAME='/FORCED_PREFIX/'): with override_settings(FORCE_SCRIPT_NAME='/FORCED_PREFIX/'):
request = WSGIRequest({'PATH_INFO': '/somepath/', 'SCRIPT_NAME': '/PREFIX/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')}) request = WSGIRequest({
'PATH_INFO': '/somepath/',
'SCRIPT_NAME': '/PREFIX/',
'REQUEST_METHOD': 'get',
'wsgi.input': BytesIO(b''),
})
self.assertEqual(request.path, '/FORCED_PREFIX/somepath/') self.assertEqual(request.path, '/FORCED_PREFIX/somepath/')
def test_wsgirequest_path_with_force_script_name_trailing_slash(self): def test_wsgirequest_path_with_force_script_name_trailing_slash(self):

View File

@ -336,7 +336,10 @@ class SchemaTests(TransactionTestCase):
columns = self.column_classes(Author) columns = self.column_classes(Author)
# BooleanField are stored as TINYINT(1) on MySQL. # BooleanField are stored as TINYINT(1) on MySQL.
field_type = columns['awesome'][0] field_type = columns['awesome'][0]
self.assertEqual(field_type, connection.features.introspected_boolean_field_type(new_field, created_separately=True)) self.assertEqual(
field_type,
connection.features.introspected_boolean_field_type(new_field, created_separately=True)
)
def test_add_field_default_transform(self): def test_add_field_default_transform(self):
""" """
@ -1097,7 +1100,9 @@ class SchemaTests(TransactionTestCase):
editor.create_model(TagM2MTest) editor.create_model(TagM2MTest)
editor.create_model(UniqueTest) editor.create_model(UniqueTest)
# Ensure the M2M exists and points to TagM2MTest # Ensure the M2M exists and points to TagM2MTest
constraints = self.get_constraints(LocalBookWithM2M._meta.get_field("tags").remote_field.through._meta.db_table) constraints = self.get_constraints(
LocalBookWithM2M._meta.get_field("tags").remote_field.through._meta.db_table
)
if connection.features.supports_foreign_keys: if connection.features.supports_foreign_keys:
for name, details in constraints.items(): for name, details in constraints.items():
if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']: if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']:
@ -1113,7 +1118,10 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.alter_field(LocalBookWithM2M, old_field, new_field) editor.alter_field(LocalBookWithM2M, old_field, new_field)
# Ensure old M2M is gone # Ensure old M2M is gone
self.assertRaises(DatabaseError, self.column_classes, LocalBookWithM2M._meta.get_field("tags").remote_field.through) self.assertRaises(
DatabaseError,
self.column_classes, LocalBookWithM2M._meta.get_field("tags").remote_field.through
)
# Ensure the new M2M exists and points to UniqueTest # Ensure the new M2M exists and points to UniqueTest
constraints = self.get_constraints(new_field.remote_field.through._meta.db_table) constraints = self.get_constraints(new_field.remote_field.through._meta.db_table)
if connection.features.supports_foreign_keys: if connection.features.supports_foreign_keys:

View File

@ -53,7 +53,11 @@ class SelectRelatedTests(TestCase):
extra queries extra queries
""" """
with self.assertNumQueries(1): with self.assertNumQueries(1):
person = Species.objects.select_related('genus__family__order__klass__phylum__kingdom__domain').get(name="sapiens") person = (
Species.objects
.select_related('genus__family__order__klass__phylum__kingdom__domain')
.get(name="sapiens")
)
domain = person.genus.family.order.klass.phylum.kingdom.domain domain = person.genus.family.order.klass.phylum.kingdom.domain
self.assertEqual(domain.name, 'Eukaryota') self.assertEqual(domain.name, 'Eukaryota')

View File

@ -39,7 +39,12 @@ class SelectRelatedRegressTests(TestCase):
self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections], self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections],
[(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')]) [(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')])
connections = Connection.objects.filter(start__device__building=b, end__device__building=b).select_related().order_by('id') connections = (
Connection.objects
.filter(start__device__building=b, end__device__building=b)
.select_related()
.order_by('id')
)
self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections], self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections],
[(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')]) [(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')])

View File

@ -352,7 +352,7 @@ class XmlSerializerTestCase(SerializersTestBase, TestCase):
<field name="categories" rel="ManyToManyRel" to="serializers.category"><object pk="%(first_category_pk)s"></object><object pk="%(second_category_pk)s"></object></field> <field name="categories" rel="ManyToManyRel" to="serializers.category"><object pk="%(first_category_pk)s"></object><object pk="%(second_category_pk)s"></object></field>
<field name="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field> <field name="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field>
</object> </object>
</django-objects>""" </django-objects>""" # NOQA
@staticmethod @staticmethod
def _comparison_value(value): def _comparison_value(value):

View File

@ -36,7 +36,10 @@ class SitesFrameworkTestCase(TestCase):
self.assertEqual(SyndicatedArticle.on_site.all().get(), article) self.assertEqual(SyndicatedArticle.on_site.all().get(), article)
def test_custom_named_field(self): def test_custom_named_field(self):
article = CustomArticle.objects.create(title="Tantalizing News!", places_this_article_should_appear_id=settings.SITE_ID) article = CustomArticle.objects.create(
title="Tantalizing News!",
places_this_article_should_appear_id=settings.SITE_ID,
)
self.assertEqual(CustomArticle.on_site.all().get(), article) self.assertEqual(CustomArticle.on_site.all().get(), article)
def test_invalid_name(self): def test_invalid_name(self):

View File

@ -58,7 +58,10 @@ class FeedTestCase(TestCase):
elem.getElementsByTagName(k)[0].firstChild.wholeText, v) elem.getElementsByTagName(k)[0].firstChild.wholeText, v)
def assertCategories(self, elem, expected): def assertCategories(self, elem, expected):
self.assertEqual(set(i.firstChild.wholeText for i in elem.childNodes if i.nodeName == 'category'), set(expected)) self.assertEqual(
set(i.firstChild.wholeText for i in elem.childNodes if i.nodeName == 'category'),
set(expected)
)
###################################### ######################################
# Feed view # Feed view
@ -101,7 +104,12 @@ class SyndicationFeedTest(FeedTestCase):
d = Entry.objects.latest('published').published d = Entry.objects.latest('published').published
last_build_date = rfc2822_date(timezone.make_aware(d, TZ)) last_build_date = rfc2822_date(timezone.make_aware(d, TZ))
self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) self.assertChildNodes(
chan, [
'title', 'link', 'description', 'language', 'lastBuildDate',
'item', 'atom:link', 'ttl', 'copyright', 'category',
]
)
self.assertChildNodeContent(chan, { self.assertChildNodeContent(chan, {
'title': 'My blog', 'title': 'My blog',
'description': 'A more thorough description of my blog.', 'description': 'A more thorough description of my blog.',
@ -197,7 +205,12 @@ class SyndicationFeedTest(FeedTestCase):
chan_elem = feed.getElementsByTagName('channel') chan_elem = feed.getElementsByTagName('channel')
self.assertEqual(len(chan_elem), 1) self.assertEqual(len(chan_elem), 1)
chan = chan_elem[0] chan = chan_elem[0]
self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category']) self.assertChildNodes(
chan, [
'title', 'link', 'description', 'language', 'lastBuildDate',
'item', 'atom:link', 'ttl', 'copyright', 'category',
]
)
# Ensure the content of the channel is correct # Ensure the content of the channel is correct
self.assertChildNodeContent(chan, { self.assertChildNodeContent(chan, {
@ -232,7 +245,10 @@ class SyndicationFeedTest(FeedTestCase):
self.assertEqual(feed.nodeName, 'feed') self.assertEqual(feed.nodeName, 'feed')
self.assertEqual(feed.getAttribute('xmlns'), 'http://www.w3.org/2005/Atom') self.assertEqual(feed.getAttribute('xmlns'), 'http://www.w3.org/2005/Atom')
self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'rights', 'category', 'author']) self.assertChildNodes(
feed,
['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'rights', 'category', 'author']
)
for link in feed.getElementsByTagName('link'): for link in feed.getElementsByTagName('link'):
if link.getAttribute('rel') == 'self': if link.getAttribute('rel') == 'self':
self.assertEqual(link.getAttribute('href'), 'http://example.com/syndication/atom/') self.assertEqual(link.getAttribute('href'), 'http://example.com/syndication/atom/')
@ -299,7 +315,10 @@ class SyndicationFeedTest(FeedTestCase):
self.assertEqual(feed.nodeName, 'feed') self.assertEqual(feed.nodeName, 'feed')
self.assertEqual(feed.getAttribute('django'), 'rocks') self.assertEqual(feed.getAttribute('django'), 'rocks')
self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'spam', 'rights', 'category', 'author']) self.assertChildNodes(
feed,
['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'spam', 'rights', 'category', 'author']
)
entries = feed.getElementsByTagName('entry') entries = feed.getElementsByTagName('entry')
self.assertEqual(len(entries), Entry.objects.count()) self.assertEqual(len(entries), Entry.objects.count())

View File

@ -42,7 +42,9 @@ class DateTests(TimezoneTestCase):
# Timezone name # Timezone name
@setup({'date06': '{{ d|date:"e" }}'}) @setup({'date06': '{{ d|date:"e" }}'})
def test_date06(self): def test_date06(self):
output = self.engine.render_to_string('date06', {'d': datetime(2009, 3, 12, tzinfo=timezone.get_fixed_timezone(30))}) output = self.engine.render_to_string(
'date06', {'d': datetime(2009, 3, 12, tzinfo=timezone.get_fixed_timezone(30))}
)
self.assertEqual(output, '+0030') self.assertEqual(output, '+0030')
@setup({'date07': '{{ d|date:"e" }}'}) @setup({'date07': '{{ d|date:"e" }}'})

View File

@ -8,10 +8,14 @@ class RandomTests(SimpleTestCase):
@setup({'random01': '{{ a|random }} {{ b|random }}'}) @setup({'random01': '{{ a|random }} {{ b|random }}'})
def test_random01(self): def test_random01(self):
output = self.engine.render_to_string('random01', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]}) output = self.engine.render_to_string(
'random01', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]}
)
self.assertEqual(output, 'a&amp;b a&b') self.assertEqual(output, 'a&amp;b a&b')
@setup({'random02': '{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}'}) @setup({'random02': '{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}'})
def test_random02(self): def test_random02(self):
output = self.engine.render_to_string('random02', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]}) output = self.engine.render_to_string(
'random02', {'a': ['a&b', 'a&b'], 'b': [mark_safe('a&b'), mark_safe('a&b')]}
)
self.assertEqual(output, 'a&b a&b') self.assertEqual(output, 'a&b a&b')

Some files were not shown because too many files have changed in this diff Show More