Fixed #23395 -- Limited line lengths to 119 characters.
This commit is contained in:
parent
84b0a8d2aa
commit
b1e33ceced
|
@ -83,7 +83,11 @@ class UserAdmin(admin.ModelAdmin):
|
|||
|
||||
def get_urls(self):
|
||||
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()
|
||||
|
||||
def lookup_allowed(self, lookup, value):
|
||||
|
|
|
@ -58,16 +58,42 @@ class Migration(migrations.Migration):
|
|||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('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')),
|
||||
('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')])),
|
||||
('is_superuser', models.BooleanField(
|
||||
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)),
|
||||
('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)),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('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')),
|
||||
('is_staff', models.BooleanField(
|
||||
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')),
|
||||
('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')),
|
||||
('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')),
|
||||
('groups', models.ManyToManyField(
|
||||
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={
|
||||
'swappable': 'AUTH_USER_MODEL',
|
||||
|
|
|
@ -16,6 +16,15 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='user',
|
||||
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'
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -19,8 +19,16 @@ class Migration(migrations.Migration):
|
|||
('title', models.CharField(max_length=200, verbose_name='title')),
|
||||
('content', models.TextField(verbose_name='content', blank=True)),
|
||||
('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)),
|
||||
('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')),
|
||||
('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
|
||||
)),
|
||||
('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')),
|
||||
],
|
||||
options={
|
||||
|
|
|
@ -21,8 +21,15 @@ class Migration(migrations.Migration):
|
|||
on_delete=models.CASCADE,
|
||||
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)),
|
||||
('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)),
|
||||
('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
|
||||
)),
|
||||
('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={
|
||||
'ordering': ('old_path',),
|
||||
|
|
|
@ -14,7 +14,9 @@ class Migration(migrations.Migration):
|
|||
migrations.CreateModel(
|
||||
name='Session',
|
||||
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')),
|
||||
('expire_date', models.DateTimeField(verbose_name='expire date', db_index=True)),
|
||||
],
|
||||
|
|
|
@ -15,7 +15,9 @@ class Migration(migrations.Migration):
|
|||
name='Site',
|
||||
fields=[
|
||||
('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')),
|
||||
],
|
||||
options={
|
||||
|
|
|
@ -15,6 +15,9 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='site',
|
||||
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'
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -92,7 +92,10 @@ class Command(BaseCommand):
|
|||
extra_params['unique'] = True
|
||||
|
||||
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:
|
||||
field_type = 'ForeignKey(%s' % rel_to
|
||||
else:
|
||||
|
|
|
@ -124,14 +124,15 @@ def Deserializer(object_list, **options):
|
|||
|
||||
# Handle M2M relations
|
||||
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):
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
m2m_data[field.name] = []
|
||||
|
@ -142,21 +143,24 @@ def Deserializer(object_list, **options):
|
|||
|
||||
# Handle FK fields
|
||||
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
|
||||
model = field.remote_field.model
|
||||
if field_value is not None:
|
||||
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):
|
||||
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)
|
||||
# If this is a natural foreign key to an object that
|
||||
# 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
|
||||
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
|
||||
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:
|
||||
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
|
||||
else:
|
||||
|
|
|
@ -236,12 +236,13 @@ class Deserializer(base.Deserializer):
|
|||
if node.getElementsByTagName('None'):
|
||||
return None
|
||||
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')
|
||||
if keys:
|
||||
# If there are 'natural' subelements, it must be a natural key
|
||||
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)
|
||||
# If this is a natural foreign key to an object that
|
||||
# has a FK/O2O as the foreign key, use the FK value
|
||||
|
@ -250,29 +251,31 @@ class Deserializer(base.Deserializer):
|
|||
else:
|
||||
# Otherwise, treat like a normal PK
|
||||
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
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
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):
|
||||
keys = n.getElementsByTagName('natural')
|
||||
if keys:
|
||||
# If there are 'natural' subelements, it must be a natural key
|
||||
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:
|
||||
# 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
|
||||
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")]
|
||||
|
||||
def _get_model_from_node(self, node, attr):
|
||||
|
|
|
@ -468,7 +468,11 @@ class MigrationAutodetector(object):
|
|||
)
|
||||
)
|
||||
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.append((app_label, model_name))
|
||||
break
|
||||
|
@ -505,7 +509,8 @@ class MigrationAutodetector(object):
|
|||
related_fields[field.name] = field
|
||||
# through will be none on M2Ms on swapped-out models;
|
||||
# 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
|
||||
for field in model_opts.local_many_to_many:
|
||||
if field.remote_field.model:
|
||||
|
@ -681,7 +686,8 @@ class MigrationAutodetector(object):
|
|||
related_fields[field.name] = field
|
||||
# through will be none on M2Ms on swapped-out models;
|
||||
# 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
|
||||
for field in model._meta.local_many_to_many:
|
||||
if field.remote_field.model:
|
||||
|
|
|
@ -119,7 +119,10 @@ class MigrationLoader(object):
|
|||
if hasattr(migration_module.Migration, "forwards"):
|
||||
south_style_migrations = True
|
||||
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:
|
||||
self.unmigrated_apps.add(app_config.label)
|
||||
|
||||
|
|
|
@ -346,7 +346,10 @@ class RelatedField(Field):
|
|||
return None
|
||||
|
||||
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:
|
||||
self.verbose_name = self.remote_field.model._meta.verbose_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:
|
||||
old_ids.add(obj.pk)
|
||||
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)
|
||||
remove.alters_data = True
|
||||
|
||||
|
@ -955,7 +960,8 @@ def create_many_related_manager(superclass, rel, reverse):
|
|||
|
||||
self.core_filters = {}
|
||||
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)
|
||||
if None in self.related_val:
|
||||
|
@ -1688,7 +1694,10 @@ class ForeignObject(RelatedField):
|
|||
if isinstance(self.remote_field.model, six.string_types):
|
||||
kwargs['to'] = self.remote_field.model
|
||||
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
|
||||
# of a swap.
|
||||
swappable_setting = self.swappable_setting
|
||||
|
@ -1999,7 +2008,8 @@ class ForeignKey(ForeignObject):
|
|||
kwargs['db_constraint'] = self.db_constraint
|
||||
# Rel needs more work.
|
||||
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
|
||||
return name, path, args, kwargs
|
||||
|
||||
|
|
|
@ -788,8 +788,12 @@ class BaseModelFormSet(BaseFormSet):
|
|||
# True, so check for that as well.
|
||||
|
||||
def pk_is_not_editable(pk):
|
||||
return ((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)))
|
||||
return (
|
||||
(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 form.is_bound:
|
||||
# If we're adding the related instance, ignore its primary key
|
||||
|
|
|
@ -655,7 +655,10 @@ class Client(RequestFactory):
|
|||
|
||||
def _parse_json(self, response, **extra):
|
||||
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)
|
||||
|
||||
def _handle_redirects(self, response, **extra):
|
||||
|
|
|
@ -862,12 +862,12 @@ Installed Middleware:
|
|||
{% if postmortem %}Django tried loading these templates, in this order:
|
||||
{% for entry in postmortem %}
|
||||
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.
|
||||
{% endif %}{% endfor %}
|
||||
{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
|
||||
{% endif %}
|
||||
{% endif %}{% if template_info %}
|
||||
{% endif %}{% endif %}{% if template_info %}
|
||||
Template error:
|
||||
In template {{ template_info.name }}, error at line {{ template_info.line }}
|
||||
{{ template_info.message }}"""
|
||||
|
@ -1044,7 +1044,8 @@ Exception Value: {{ exception_value|force_escape }}
|
|||
</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' %}
|
||||
{% if request %}
|
||||
Request Method: {{ request.META.REQUEST_METHOD }}
|
||||
|
@ -1062,7 +1063,8 @@ Installed Middleware:
|
|||
{% if postmortem %}Django tried loading these templates, in this order:
|
||||
{% for entry in postmortem %}
|
||||
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.
|
||||
{% endif %}{% endfor %}
|
||||
{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
|
||||
|
|
10
docs/conf.py
10
docs/conf.py
|
@ -272,9 +272,13 @@ latex_documents = [
|
|||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('ref/django-admin', 'django-admin', 'Utility script for the Django Web framework', ['Django Software Foundation'], 1),
|
||||
]
|
||||
man_pages = [(
|
||||
'ref/django-admin',
|
||||
'django-admin',
|
||||
'Utility script for the Django Web framework',
|
||||
['Django Software Foundation'],
|
||||
1
|
||||
), ]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
|
|
@ -4,7 +4,7 @@ install-script = scripts/rpm-install.sh
|
|||
|
||||
[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
|
||||
ignore = E123,E128,E402,E501,W503,E731,W601
|
||||
ignore = E123,E128,E402,W503,E731,W601
|
||||
max-line-length = 119
|
||||
|
||||
[isort]
|
||||
|
|
|
@ -227,12 +227,23 @@ class ChangeListTests(TestCase):
|
|||
context = Context({'cl': cl})
|
||||
table_output = template.render(context)
|
||||
# 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')
|
||||
|
||||
# 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" />'
|
||||
self.assertInHTML('<td class="field-name">%s</td>' % editable_name_field, table_output, msg_prefix='Failed to find "name" list_editable field')
|
||||
editable_name_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):
|
||||
"""
|
||||
|
|
|
@ -340,7 +340,10 @@ class SystemChecksTestCase(SimpleTestCase):
|
|||
self.assertEqual(errors, expected)
|
||||
|
||||
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):
|
||||
model = Influence
|
||||
ct_field = 'name'
|
||||
|
@ -351,7 +354,8 @@ class SystemChecksTestCase(SimpleTestCase):
|
|||
errors = SongAdmin(Song, AdminSite()).check()
|
||||
expected = [
|
||||
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,
|
||||
obj=InfluenceInline,
|
||||
id='admin.E304',
|
||||
|
@ -360,7 +364,10 @@ class SystemChecksTestCase(SimpleTestCase):
|
|||
self.assertEqual(errors, expected)
|
||||
|
||||
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):
|
||||
model = Influence
|
||||
ct_fk_field = 'name'
|
||||
|
@ -371,7 +378,8 @@ class SystemChecksTestCase(SimpleTestCase):
|
|||
errors = SongAdmin(Song, AdminSite()).check()
|
||||
expected = [
|
||||
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,
|
||||
obj=InfluenceInline,
|
||||
id='admin.E304',
|
||||
|
@ -389,8 +397,8 @@ class SystemChecksTestCase(SimpleTestCase):
|
|||
errors = RawIdNonexistingAdmin(Album, AdminSite()).check()
|
||||
expected = [
|
||||
checks.Error(
|
||||
("The value of 'raw_id_fields[0]' refers to 'nonexisting', which is "
|
||||
"not an attribute of 'admin_checks.Album'."),
|
||||
"The value of 'raw_id_fields[0]' refers to 'nonexisting', "
|
||||
"which is not an attribute of 'admin_checks.Album'.",
|
||||
hint=None,
|
||||
obj=RawIdNonexistingAdmin,
|
||||
id='admin.E002',
|
||||
|
|
|
@ -20,10 +20,16 @@ class Book(models.Model):
|
|||
related_name='books_authored',
|
||||
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)
|
||||
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):
|
||||
return self.title
|
||||
|
|
|
@ -129,11 +129,25 @@ class BookAdmin(ModelAdmin):
|
|||
|
||||
|
||||
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):
|
||||
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):
|
||||
|
@ -231,10 +245,22 @@ class ListFiltersTests(TestCase):
|
|||
self.lisa = User.objects.create_user('lisa', 'lisa@example.com')
|
||||
|
||||
# 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.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.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.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.save()
|
||||
|
||||
|
@ -247,9 +273,13 @@ class ListFiltersTests(TestCase):
|
|||
self.jack = Employee.objects.create(name='Jack Red', department=self.design)
|
||||
|
||||
def get_changelist(self, request, model, modeladmin):
|
||||
return ChangeList(request, model, modeladmin.list_display, 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)
|
||||
return ChangeList(
|
||||
request, model, modeladmin.list_display,
|
||||
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):
|
||||
modeladmin = BookAdmin(Book, site)
|
||||
|
@ -730,7 +760,10 @@ class ListFiltersTests(TestCase):
|
|||
choices = list(filterspec.choices(changelist))
|
||||
self.assertEqual(choices[3]['display'], 'the 2000\'s')
|
||||
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]
|
||||
self.assertEqual(force_text(filterspec.title), 'Verbose Author')
|
||||
|
|
|
@ -114,7 +114,11 @@ class TestInline(TestDataMixin, TestCase):
|
|||
}
|
||||
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.
|
||||
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):
|
||||
"""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'))
|
||||
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
|
||||
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):
|
||||
"""#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):
|
||||
bt_head = BinaryTree.objects.create(name="Tree Head")
|
||||
BinaryTree.objects.create(name="First Child", parent=bt_head)
|
||||
|
||||
# The maximum number of forms should respect 'get_max_num' on the
|
||||
# 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
|
||||
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'))
|
||||
self.assertContains(response, max_forms_input % 3)
|
||||
self.assertContains(response, total_forms_hidden)
|
||||
|
@ -254,10 +276,14 @@ class TestInline(TestDataMixin, TestCase):
|
|||
|
||||
modeladmin = ModelAdmin(BinaryTree, admin_site)
|
||||
modeladmin.inlines = [MinNumInline]
|
||||
|
||||
min_forms = '<input id="id_binarytree_set-MIN_NUM_FORMS" 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" />'
|
||||
|
||||
min_forms = (
|
||||
'<input id="id_binarytree_set-MIN_NUM_FORMS" '
|
||||
'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.user = User(username='super', is_superuser=True)
|
||||
response = modeladmin.changeform_view(request)
|
||||
|
@ -282,10 +308,14 @@ class TestInline(TestDataMixin, TestCase):
|
|||
|
||||
modeladmin = ModelAdmin(BinaryTree, admin_site)
|
||||
modeladmin.inlines = [MinNumInline]
|
||||
|
||||
min_forms = '<input id="id_binarytree_set-MIN_NUM_FORMS" 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" />'
|
||||
|
||||
min_forms = (
|
||||
'<input id="id_binarytree_set-MIN_NUM_FORMS" '
|
||||
'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.user = User(username='super', is_superuser=True)
|
||||
response = modeladmin.changeform_view(request)
|
||||
|
@ -300,21 +330,33 @@ class TestInline(TestDataMixin, TestCase):
|
|||
|
||||
def test_inline_nonauto_noneditable_pk(self):
|
||||
response = self.client.get(reverse('admin:admin_inlines_author_add'))
|
||||
self.assertContains(response,
|
||||
'<input id="id_nonautopkbook_set-0-rand_pk" name="nonautopkbook_set-0-rand_pk" type="hidden" />',
|
||||
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)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<input id="id_nonautopkbook_set-0-rand_pk" '
|
||||
'name="nonautopkbook_set-0-rand_pk" type="hidden" />',
|
||||
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):
|
||||
response = self.client.get(reverse('admin:admin_inlines_author_add'))
|
||||
self.assertContains(response,
|
||||
'<input class="vIntegerField" id="id_editablepkbook_set-0-manual_pk" name="editablepkbook_set-0-manual_pk" type="text" />',
|
||||
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)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<input class="vIntegerField" id="id_editablepkbook_set-0-manual_pk" '
|
||||
'name="editablepkbook_set-0-manual_pk" type="text" />',
|
||||
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):
|
||||
holder = Holder.objects.create(dummy=1)
|
||||
|
@ -585,8 +627,12 @@ class TestInlinePermissions(TestCase):
|
|||
self.assertContains(response, 'Add another Author\\u002Dbook relationship')
|
||||
self.assertContains(response, '<input type="hidden" id="id_Author_books-TOTAL_FORMS" '
|
||||
'value="4" name="Author_books-TOTAL_FORMS" />', html=True)
|
||||
self.assertContains(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,
|
||||
'<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"')
|
||||
|
||||
def test_inline_change_fk_add_perm(self):
|
||||
|
@ -597,8 +643,12 @@ class TestInlinePermissions(TestCase):
|
|||
self.assertContains(response, '<h2>Inner2s</h2>')
|
||||
self.assertContains(response, 'Add another Inner2')
|
||||
# 3 extra forms only, not the existing instance form
|
||||
self.assertContains(response, '<input type="hidden" id="id_inner2_set-TOTAL_FORMS" '
|
||||
'value="3" name="inner2_set-TOTAL_FORMS" />', html=True)
|
||||
self.assertContains(
|
||||
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" '
|
||||
'value="%i" name="inner2_set-0-id" />' % self.inner2_id, html=True)
|
||||
|
||||
|
|
|
@ -964,21 +964,36 @@ class ManageAlternateSettings(AdminScriptTestCase):
|
|||
"alternate: manage.py can execute user commands if settings are provided as argument"
|
||||
args = ['noargs_command', '--settings=alternate_settings']
|
||||
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)
|
||||
|
||||
def test_custom_command_with_environment(self):
|
||||
"alternate: manage.py can execute user commands if settings are provided in environment"
|
||||
args = ['noargs_command']
|
||||
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)
|
||||
|
||||
def test_custom_command_output_color(self):
|
||||
"alternate: manage.py output syntax color can be deactivated with the `--no-color` option"
|
||||
args = ['noargs_command', '--no-color', '--settings=alternate_settings']
|
||||
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)
|
||||
|
||||
|
||||
|
@ -1660,7 +1675,12 @@ class CommandTypes(AdminScriptTestCase):
|
|||
args = ['noargs_command']
|
||||
out, err = self.run_manage(args)
|
||||
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):
|
||||
"NoArg Commands raise an error if an argument is provided"
|
||||
|
@ -1674,7 +1694,11 @@ class CommandTypes(AdminScriptTestCase):
|
|||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
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):
|
||||
"User AppCommands raise an error when no app name is provided"
|
||||
|
@ -1688,9 +1712,17 @@ class CommandTypes(AdminScriptTestCase):
|
|||
out, err = self.run_manage(args)
|
||||
self.assertNoOutput(err)
|
||||
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, ", 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):
|
||||
"User AppCommands can execute when a single app name is provided"
|
||||
|
@ -1709,7 +1741,11 @@ class CommandTypes(AdminScriptTestCase):
|
|||
args = ['label_command', 'testlabel']
|
||||
out, err = self.run_manage(args)
|
||||
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):
|
||||
"User LabelCommands raise an error if no label is provided"
|
||||
|
@ -1722,8 +1758,16 @@ class CommandTypes(AdminScriptTestCase):
|
|||
args = ['label_command', 'testlabel', 'anotherlabel']
|
||||
out, err = self.run_manage(args)
|
||||
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=anotherlabel, 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)]"
|
||||
)
|
||||
self.assertOutput(
|
||||
out,
|
||||
"EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), "
|
||||
"('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]"
|
||||
)
|
||||
|
||||
|
||||
class Discovery(SimpleTestCase):
|
||||
|
@ -1794,7 +1838,13 @@ class ArgumentOrder(AdminScriptTestCase):
|
|||
def _test(self, args, option_b="'2'"):
|
||||
out, err = self.run_manage(args)
|
||||
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')
|
||||
|
@ -1907,7 +1957,10 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
|||
self.assertTrue(os.path.exists(os.path.join(testproject_dir, 'run.py')))
|
||||
|
||||
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
|
||||
|
||||
args = ['startproject', '--template', template_url, 'urltestproject']
|
||||
|
@ -1971,7 +2024,11 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
|||
self.write_settings('alternate_settings.py')
|
||||
self.addCleanup(self.remove_settings, 'alternate_settings.py')
|
||||
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')
|
||||
os.mkdir(testproject_dir)
|
||||
self.addCleanup(shutil.rmtree, testproject_dir)
|
||||
|
@ -1996,7 +2053,10 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
|||
self.assertFalse(os.path.exists(testproject_dir))
|
||||
|
||||
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')
|
||||
args = ['startproject', '--template', template_path, '--extension=txt', 'customtestproject']
|
||||
testproject_dir = os.path.join(self.test_dir, 'customtestproject')
|
||||
|
|
|
@ -587,7 +587,9 @@ class PluggableSearchPersonAdmin(admin.ModelAdmin):
|
|||
search_fields = ('name',)
|
||||
|
||||
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:
|
||||
search_term_as_int = int(search_term)
|
||||
queryset |= self.model.objects.filter(age=search_term_as_int)
|
||||
|
|
|
@ -300,7 +300,8 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
|||
"""
|
||||
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
|
||||
|
||||
def test_edit_save_as(self):
|
||||
|
@ -600,7 +601,10 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
|||
link1 = reverse('admin:admin_views_fabric_change', args=(self.fab1.pk,))
|
||||
link2 = reverse('admin:admin_views_fabric_change', args=(self.fab2.pk,))
|
||||
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">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.
|
||||
"""
|
||||
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,
|
||||
'<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):
|
||||
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(len(calls), 1)
|
||||
|
||||
|
@ -726,12 +734,14 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
|||
|
||||
section = Section.objects.create()
|
||||
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(len(calls), 1)
|
||||
|
||||
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(len(calls), 1)
|
||||
|
||||
|
@ -742,7 +752,8 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
|||
can break.
|
||||
"""
|
||||
# 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)
|
||||
|
||||
def test_popup_dismiss_related(self):
|
||||
|
@ -1787,24 +1798,24 @@ class AdminViewPermissionsTest(TestCase):
|
|||
rl2 = RowLevelChangePermissionModel.objects.create(name="even id")
|
||||
for login_dict in [self.super_login, self.changeuser_login, self.adduser_login, self.deleteuser_login]:
|
||||
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)
|
||||
|
||||
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.client.get(reverse('admin:logout'))
|
||||
|
||||
for login_dict in [self.joepublic_login, self.no_username_login]:
|
||||
self.client.post(login_url, login_dict)
|
||||
response = self.client.get(
|
||||
reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,)), follow=True
|
||||
)
|
||||
url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl1.pk,))
|
||||
response = self.client.get(url, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'login-form')
|
||||
response = self.client.get(
|
||||
reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,)), follow=True
|
||||
)
|
||||
url = reverse('admin:admin_views_rowlevelchangepermissionmodel_history', args=(rl2.pk,))
|
||||
response = self.client.get(url, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'login-form')
|
||||
|
||||
|
@ -2118,11 +2129,15 @@ class AdminViewDeletedObjectsTest(TestCase):
|
|||
Objects should be nested to display the relationships that
|
||||
cause them to be scheduled for deletion.
|
||||
"""
|
||||
pattern = re.compile(force_bytes(
|
||||
r'<li>Plot: <a href="%s">World Domination</a>\s*<ul>\s*<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,)))
|
||||
))
|
||||
pattern = re.compile(
|
||||
force_bytes(
|
||||
r'<li>Plot: <a href="%s">World Domination</a>\s*<ul>\s*'
|
||||
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,)))
|
||||
six.assertRegex(self, response.content, pattern)
|
||||
|
||||
|
@ -2210,7 +2225,9 @@ class AdminViewDeletedObjectsTest(TestCase):
|
|||
"""
|
||||
should_contain = [
|
||||
'<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>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
|
||||
)
|
||||
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)
|
||||
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')
|
||||
|
@ -2389,7 +2409,10 @@ class AdminViewStringPrimaryKeyTest(TestCase):
|
|||
counted_presence_after)
|
||||
|
||||
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
|
||||
logentry = LogEntry.objects.get(content_type__model__iexact=log_entry_model)
|
||||
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):
|
||||
"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
|
||||
change_url = reverse(
|
||||
'admin:admin_views_modelwithstringprimarykey_change', args=('__fk__',)
|
||||
|
@ -3028,11 +3052,22 @@ class AdminViewListEditable(TestCase):
|
|||
Refs #12475.
|
||||
"""
|
||||
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'))
|
||||
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, '<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>' % story2.id, 1)
|
||||
|
||||
|
@ -3041,14 +3076,28 @@ class AdminViewListEditable(TestCase):
|
|||
referenced in list_display_links.
|
||||
Refs #12475.
|
||||
"""
|
||||
story1 = OtherStory.objects.create(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...')
|
||||
story1 = OtherStory.objects.create(
|
||||
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,))
|
||||
link2 = reverse('admin:admin_views_otherstory_change', args=(story2.pk,))
|
||||
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, '<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>' % (link2, story2.id), 1)
|
||||
|
||||
|
@ -3850,9 +3899,11 @@ class AdminCustomQuerysetTest(TestCase):
|
|||
# Message should contain non-ugly model verbose name. The ugly(!)
|
||||
# instance representation is set by six.text_type()
|
||||
self.assertContains(
|
||||
response,
|
||||
'<li class="success">The short message "ShortMessage_Deferred_timestamp object" was changed successfully.</li>',
|
||||
html=True
|
||||
response, (
|
||||
'<li class="success">The short message '
|
||||
'"ShortMessage_Deferred_timestamp object" was '
|
||||
'changed successfully.</li>'
|
||||
), html=True
|
||||
)
|
||||
|
||||
def test_edit_model_modeladmin_only_qs(self):
|
||||
|
@ -4462,9 +4513,15 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
|
|||
# Initial inline
|
||||
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.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-0-name').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.selenium.find_element_by_css_selector(
|
||||
'#id_relatedprepopulated_set-0-name'
|
||||
).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(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_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.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... ')
|
||||
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')
|
||||
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
|
||||
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... '
|
||||
)
|
||||
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 ----------------------------------------------------
|
||||
# Initial inline
|
||||
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.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-0-name').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.selenium.find_element_by_css_selector(
|
||||
'#id_relatedprepopulated_set-2-0-name'
|
||||
).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(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_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.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-name').send_keys('a tÃbűlaŘ inline with ignored ;"&*^\%$#@-/`~ characters')
|
||||
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.selenium.find_element_by_css_selector('#id_relatedprepopulated_set-2-1-name').send_keys(
|
||||
'a tÃbűlaŘ inline with ignored ;"&*^\%$#@-/`~ characters'
|
||||
)
|
||||
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(slug2, 'option-one-tabular-inline-ignored-characters')
|
||||
|
||||
|
@ -4518,7 +4596,8 @@ class SeleniumAdminViewsFirefoxTests(AdminSeleniumWebDriverTestCase):
|
|||
slug2='option-one-here-stacked-inline',
|
||||
)
|
||||
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',
|
||||
status='option two',
|
||||
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">')
|
||||
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(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)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<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")
|
||||
response = self.client.get(reverse('admin:admin_views_post_change', args=(p.pk,)))
|
||||
|
@ -5741,20 +5832,30 @@ class AdminKeepChangeListFiltersTests(TestCase):
|
|||
# Test equality.
|
||||
change_user_url = reverse('admin:auth_user_change', args=(self.u5.pk,))
|
||||
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)
|
||||
'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
|
||||
)
|
||||
)
|
||||
|
||||
# Test inequality.
|
||||
with self.assertRaises(AssertionError):
|
||||
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%3D1%26is_superuser__exact%3D1'.format(change_user_url)
|
||||
'http://testserver{}?_changelist_filters=is_staff__exact%3D0%26is_superuser__exact%3D0'.format(
|
||||
change_user_url
|
||||
),
|
||||
'http://testserver{}?_changelist_filters=is_staff__exact%3D1%26is_superuser__exact%3D1'.format(
|
||||
change_user_url
|
||||
)
|
||||
)
|
||||
|
||||
# Ignore scheme and host.
|
||||
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)
|
||||
)
|
||||
|
||||
|
|
|
@ -189,7 +189,10 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase):
|
|||
filter_vertical=['companies'])
|
||||
ma = AdvisorAdmin(models.Advisor, admin.site)
|
||||
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'],
|
||||
|
@ -327,7 +330,11 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase):
|
|||
w = widgets.AdminSplitDateTime()
|
||||
self.assertHTMLEqual(
|
||||
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):
|
||||
|
@ -337,7 +344,11 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase):
|
|||
w.is_localized = True
|
||||
self.assertHTMLEqual(
|
||||
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(
|
||||
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):
|
||||
w = widgets.AdminURLFieldWidget()
|
||||
self.assertHTMLEqual(
|
||||
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):
|
||||
|
@ -366,15 +383,29 @@ class AdminURLWidgetTest(SimpleTestCase):
|
|||
w = widgets.AdminURLFieldWidget()
|
||||
self.assertEqual(
|
||||
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/<sometag>some text</sometag></a><br />Change: <input class="vURLField" name="test" type="url" value="http://example.com/<sometag>some text</sometag>" /></p>'
|
||||
'<p class="url">Currently: '
|
||||
'<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">'
|
||||
'http://example.com/<sometag>some text</sometag></a><br />'
|
||||
'Change: <input class="vURLField" name="test" type="url" '
|
||||
'value="http://example.com/<sometag>some text</sometag>" /></p>'
|
||||
)
|
||||
self.assertEqual(
|
||||
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/<sometag>some text</sometag></a><br />Change: <input class="vURLField" name="test" type="url" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
|
||||
'<p class="url">Currently: '
|
||||
'<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">'
|
||||
'http://example-äüö.com/<sometag>some text</sometag></a><br />'
|
||||
'Change: <input class="vURLField" name="test" type="url" '
|
||||
'value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
|
||||
)
|
||||
self.assertEqual(
|
||||
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"><script>alert("XSS!")</script>"</a><br />Change: <input class="vURLField" name="test" type="url" value="http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"" /></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"><script>'
|
||||
'alert("XSS!")</script>"</a><br />'
|
||||
'Change: <input class="vURLField" name="test" type="url" '
|
||||
'value="http://www.example.com/%C3%A4"><script>'
|
||||
'alert("XSS!")</script>"" /></p>'
|
||||
)
|
||||
|
||||
|
||||
|
@ -447,11 +478,12 @@ class ForeignKeyRawIdWidgetTest(TestCase):
|
|||
|
||||
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
||||
self.assertHTMLEqual(
|
||||
w.render('test', band.pk, attrs={}), (
|
||||
'<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" />'
|
||||
'<a href="/admin_widgets/band/?_to_field=id" class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
|
||||
' <strong>Linkin Park</strong>'
|
||||
) % {'bandpk': band.pk}
|
||||
w.render('test', band.pk, attrs={}),
|
||||
'<input type="text" name="test" value="%(bandpk)s" '
|
||||
'class="vForeignKeyRawIdAdminField" />'
|
||||
'<a href="/admin_widgets/band/?_to_field=id" class="related-lookup" '
|
||||
'id="lookup_id_test" title="Lookup"></a> <strong>Linkin Park</strong>'
|
||||
% {'bandpk': band.pk}
|
||||
)
|
||||
|
||||
def test_relations_to_non_primary_key(self):
|
||||
|
@ -465,11 +497,12 @@ class ForeignKeyRawIdWidgetTest(TestCase):
|
|||
rel = models.Inventory._meta.get_field('parent').remote_field
|
||||
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
||||
self.assertHTMLEqual(
|
||||
w.render('test', core.parent_id, attrs={}), (
|
||||
'<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" />'
|
||||
'<a href="/admin_widgets/inventory/?_to_field=barcode" class="related-lookup" id="lookup_id_test" title="Lookup">'
|
||||
'</a> <strong>Apple</strong>'
|
||||
)
|
||||
w.render('test', core.parent_id, attrs={}),
|
||||
'<input type="text" name="test" value="86" '
|
||||
'class="vForeignKeyRawIdAdminField" />'
|
||||
'<a href="/admin_widgets/inventory/?_to_field=barcode" '
|
||||
'class="related-lookup" id="lookup_id_test" title="Lookup"></a>'
|
||||
' <strong>Apple</strong>'
|
||||
)
|
||||
|
||||
def test_fk_related_model_not_in_admin(self):
|
||||
|
@ -482,7 +515,9 @@ class ForeignKeyRawIdWidgetTest(TestCase):
|
|||
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
||||
self.assertHTMLEqual(
|
||||
w.render('honeycomb_widget', big_honeycomb.pk, attrs={}),
|
||||
'<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong>Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk}
|
||||
'<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />'
|
||||
' <strong>Honeycomb object</strong>'
|
||||
% {'hcombpk': big_honeycomb.pk}
|
||||
)
|
||||
|
||||
def test_fk_to_self_model_not_in_admin(self):
|
||||
|
@ -495,7 +530,9 @@ class ForeignKeyRawIdWidgetTest(TestCase):
|
|||
w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
|
||||
self.assertHTMLEqual(
|
||||
w.render('individual_widget', subject1.pk, attrs={}),
|
||||
'<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong>Individual object</strong>' % {'subj1pk': subject1.pk}
|
||||
'<input type="text" name="individual_widget" value="%(subj1pk)s" />'
|
||||
' <strong>Individual object</strong>'
|
||||
% {'subj1pk': subject1.pk}
|
||||
)
|
||||
|
||||
def test_proper_manager_for_label_lookup(self):
|
||||
|
@ -510,11 +547,11 @@ class ForeignKeyRawIdWidgetTest(TestCase):
|
|||
barcode=94, name='Child of hidden', parent=hidden
|
||||
)
|
||||
self.assertHTMLEqual(
|
||||
w.render('test', child_of_hidden.parent_id, attrs={}), (
|
||||
'<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> <strong>Hidden</strong>'
|
||||
)
|
||||
w.render('test', child_of_hidden.parent_id, attrs={}),
|
||||
'<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>'
|
||||
' <strong>Hidden</strong>'
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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(
|
||||
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(
|
||||
list(books), [
|
||||
{
|
||||
|
@ -561,7 +571,12 @@ class AggregateTestCase(TestCase):
|
|||
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(
|
||||
publishers, [
|
||||
"Apress",
|
||||
|
@ -571,7 +586,13 @@ class AggregateTestCase(TestCase):
|
|||
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(
|
||||
publishers, [
|
||||
"Apress",
|
||||
|
@ -628,7 +649,12 @@ class AggregateTestCase(TestCase):
|
|||
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(
|
||||
authors, [
|
||||
"Brad Dayley",
|
||||
|
@ -645,7 +671,12 @@ class AggregateTestCase(TestCase):
|
|||
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(
|
||||
publishers, [
|
||||
"Apress",
|
||||
|
@ -653,7 +684,11 @@ class AggregateTestCase(TestCase):
|
|||
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(
|
||||
books, [
|
||||
"Artificial Intelligence: A Modern Approach",
|
||||
|
@ -667,7 +702,12 @@ class AggregateTestCase(TestCase):
|
|||
b.authors.add(a)
|
||||
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})
|
||||
|
||||
def test_even_more_aggregate(self):
|
||||
|
@ -718,7 +758,12 @@ class AggregateTestCase(TestCase):
|
|||
)
|
||||
|
||||
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(
|
||||
list(books), [
|
||||
(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])
|
||||
|
||||
books = Book.objects.values_list("price").annotate(count=Count("price")).order_by("-count", "price")
|
||||
|
|
|
@ -319,7 +319,13 @@ class AggregationTests(TestCase):
|
|||
)
|
||||
|
||||
# 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(
|
||||
qs, [
|
||||
{'price': Decimal("30"), 'oldest': 35, 'publisher__num_awards__max': 3},
|
||||
|
@ -334,7 +340,12 @@ class AggregationTests(TestCase):
|
|||
def test_aggrate_annotation(self):
|
||||
# Aggregates can be composed over annotations.
|
||||
# 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, {
|
||||
'num_authors__sum': 10,
|
||||
'num_authors__avg': Approximate(1.666, places=2),
|
||||
|
@ -441,18 +452,34 @@ class AggregationTests(TestCase):
|
|||
)
|
||||
|
||||
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
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
def test_aggregate_fexpr(self):
|
||||
# Aggregates can be used with F() expressions
|
||||
# ... 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(
|
||||
qs, [
|
||||
{'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9},
|
||||
|
@ -461,7 +488,13 @@ class AggregationTests(TestCase):
|
|||
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(
|
||||
qs, [
|
||||
{'num_books': 2, 'name': 'Apress', 'num_awards': 3},
|
||||
|
@ -472,7 +505,13 @@ class AggregationTests(TestCase):
|
|||
)
|
||||
|
||||
# ... 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(
|
||||
qs, [
|
||||
{'num_books': 1, 'name': 'Morgan Kaufmann', 'num_awards': 9},
|
||||
|
@ -481,7 +520,13 @@ class AggregationTests(TestCase):
|
|||
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(
|
||||
qs, [
|
||||
{'num_books': 2, 'name': 'Apress', 'num_awards': 3},
|
||||
|
@ -493,7 +538,11 @@ class AggregationTests(TestCase):
|
|||
|
||||
def test_db_col_table(self):
|
||||
# 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, [])
|
||||
|
||||
qs = Entries.objects.annotate(clue_count=Count('clues__ID'))
|
||||
|
@ -518,17 +567,45 @@ class AggregationTests(TestCase):
|
|||
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(
|
||||
vals,
|
||||
{'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(
|
||||
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}
|
||||
],
|
||||
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,
|
||||
}],
|
||||
lambda p: p
|
||||
)
|
||||
|
||||
|
@ -551,10 +628,16 @@ class AggregationTests(TestCase):
|
|||
# Regression for #10127 - Empty select_related() works with annotate
|
||||
qs = Book.objects.filter(rating__lt=4.5).select_related().annotate(Avg('authors__age'))
|
||||
self.assertQuerysetEqual(
|
||||
qs, [
|
||||
qs,
|
||||
[
|
||||
('Artificial Intelligence: A Modern Approach', 51.5, 'Prentice Hall', 'Peter Norvig'),
|
||||
('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')
|
||||
],
|
||||
lambda b: (b.name, b.authors__age__avg, b.publisher.name, b.contact.name)
|
||||
|
@ -573,7 +656,13 @@ class AggregationTests(TestCase):
|
|||
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(
|
||||
qs, [
|
||||
{'pub': self.p1.id, 'id__count': 2},
|
||||
|
@ -586,7 +675,13 @@ class AggregationTests(TestCase):
|
|||
|
||||
# Regression for #10182 - Queries with aggregate calls are correctly
|
||||
# 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(
|
||||
Book.objects.filter(id__in=ids), [
|
||||
"Python Web Development with Django",
|
||||
|
@ -603,14 +698,20 @@ class AggregationTests(TestCase):
|
|||
|
||||
def test_duplicate_alias(self):
|
||||
# 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):
|
||||
# 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'))
|
||||
|
||||
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'))
|
||||
|
||||
def test_values_queryset_non_conflict(self):
|
||||
|
@ -636,7 +737,8 @@ class AggregationTests(TestCase):
|
|||
self.assertEqual(results[0]['friends'], 2)
|
||||
|
||||
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'))
|
||||
|
||||
def test_pickle(self):
|
||||
|
@ -682,7 +784,13 @@ class AggregationTests(TestCase):
|
|||
|
||||
# Regression for #10290 - extra selects with parameters can be used for
|
||||
# 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(
|
||||
qs, [
|
||||
150,
|
||||
|
@ -766,18 +874,26 @@ class AggregationTests(TestCase):
|
|||
|
||||
qs = HardbackBook.objects.annotate(n_authors=Count('book_ptr__authors')).values('name', 'n_authors')
|
||||
self.assertQuerysetEqual(
|
||||
qs, [
|
||||
qs,
|
||||
[
|
||||
{'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
|
||||
)
|
||||
|
||||
qs = HardbackBook.objects.annotate(n_authors=Count('authors')).values('name', 'n_authors')
|
||||
self.assertQuerysetEqual(
|
||||
qs, [
|
||||
qs,
|
||||
[
|
||||
{'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,
|
||||
)
|
||||
|
@ -871,11 +987,17 @@ class AggregationTests(TestCase):
|
|||
attrgetter("name")
|
||||
)
|
||||
|
||||
qs = 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))
|
||||
qs = (
|
||||
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(
|
||||
qs, [
|
||||
qs,
|
||||
[
|
||||
"The Definitive Guide to Django: Web Development Done Right",
|
||||
],
|
||||
attrgetter("name")
|
||||
|
|
|
@ -38,7 +38,8 @@ class TestSessionAuthenticationMiddleware(TestCase):
|
|||
self.assertEqual(session_key, self.request.session.session_key)
|
||||
|
||||
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
|
||||
self.user.set_password('new_password')
|
||||
self.user.save()
|
||||
|
|
|
@ -157,7 +157,11 @@ class PostgreSQLTests(TestCase):
|
|||
self.assert_parses("EnterpriseDB 9.3", 90300)
|
||||
self.assert_parses("PostgreSQL 9.3.6", 90306)
|
||||
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):
|
||||
"""
|
||||
|
@ -419,13 +423,19 @@ class LongNameTest(TransactionTestCase):
|
|||
models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
|
||||
|
||||
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()
|
||||
rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt')
|
||||
obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj)
|
||||
|
||||
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
|
||||
# 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):
|
||||
"""
|
||||
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():
|
||||
# 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
|
||||
a = models.Article.objects.get(headline="Test article")
|
||||
a.reporter_id = 30
|
||||
|
@ -852,11 +867,16 @@ class FkConstraintsTests(TransactionTestCase):
|
|||
|
||||
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():
|
||||
# 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
|
||||
a = models.Article.objects.get(headline="Test article")
|
||||
a.reporter_id = 30
|
||||
|
@ -873,7 +893,11 @@ class FkConstraintsTests(TransactionTestCase):
|
|||
"""
|
||||
with transaction.atomic():
|
||||
# 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
|
||||
a = models.Article.objects.get(headline="Test article")
|
||||
a.reporter_id = 30
|
||||
|
|
|
@ -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.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:
|
||||
as_view_decorator_with_custom = CacheMiddleware(cache_timeout=60, cache_alias='other', key_prefix='foo')
|
||||
|
|
|
@ -164,7 +164,10 @@ class GenericForeignKeyTests(IsolatedModelsTestCase):
|
|||
expected = [
|
||||
checks.Error(
|
||||
"'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,
|
||||
id='contenttypes.E003',
|
||||
)
|
||||
|
@ -182,7 +185,10 @@ class GenericForeignKeyTests(IsolatedModelsTestCase):
|
|||
expected = [
|
||||
checks.Error(
|
||||
"'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,
|
||||
id='contenttypes.E004',
|
||||
)
|
||||
|
|
|
@ -24,7 +24,10 @@ class MultiDBChangepasswordManagementCommandTestCase(TestCase):
|
|||
command.execute(username="joe", database='other', stdout=out)
|
||||
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"))
|
||||
|
||||
|
||||
|
|
|
@ -95,7 +95,8 @@ class CustomColumnsTests(TestCase):
|
|||
def test_filter_on_nonexistent_field(self):
|
||||
self.assertRaisesMessage(
|
||||
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,
|
||||
firstname__exact='John'
|
||||
)
|
||||
|
|
|
@ -53,4 +53,8 @@ class DBTypeCasts(unittest.TestCase):
|
|||
for k, v in six.iteritems(TEST_CASES):
|
||||
for inpt, expected in v:
|
||||
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)
|
||||
)
|
||||
|
|
|
@ -689,7 +689,15 @@ class CaseExpressionTests(TestCase):
|
|||
)
|
||||
self.assertQuerysetEqual(
|
||||
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')
|
||||
)
|
||||
|
||||
|
@ -934,8 +942,13 @@ class CaseExpressionTests(TestCase):
|
|||
self.assertQuerysetEqual(
|
||||
CaseTestModel.objects.all().order_by('pk'),
|
||||
[
|
||||
(1, UUID('11111111111111111111111111111111')), (2, UUID('22222222222222222222222222222222')), (3, None),
|
||||
(2, UUID('22222222222222222222222222222222')), (3, None), (3, None), (4, None)
|
||||
(1, UUID('11111111111111111111111111111111')),
|
||||
(2, UUID('22222222222222222222222222222222')),
|
||||
(3, None),
|
||||
(2, UUID('22222222222222222222222222222222')),
|
||||
(3, None),
|
||||
(3, None),
|
||||
(4, None),
|
||||
],
|
||||
transform=attrgetter('integer', 'uuid')
|
||||
)
|
||||
|
|
|
@ -185,100 +185,174 @@ class ExtraRegressTests(TestCase):
|
|||
obj.save()
|
||||
|
||||
self.assertEqual(
|
||||
list(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'}]
|
||||
list(
|
||||
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
|
||||
self.assertEqual(
|
||||
list(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'}]
|
||||
list(
|
||||
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
|
||||
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'}]
|
||||
)
|
||||
|
||||
# Extra columns after a non-empty values() clause are ignored
|
||||
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'}]
|
||||
)
|
||||
|
||||
# Extra columns can be partially returned
|
||||
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'}]
|
||||
)
|
||||
|
||||
# Also works if only extra columns are included
|
||||
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'}]
|
||||
)
|
||||
|
||||
# Values list works the same way
|
||||
# All columns are returned for an empty values_list()
|
||||
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')]
|
||||
)
|
||||
|
||||
# Extra columns after an empty values_list() are still included
|
||||
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')]
|
||||
)
|
||||
|
||||
# Extra columns ignored completely if not mentioned in values_list()
|
||||
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')]
|
||||
)
|
||||
|
||||
# Extra columns after a non-empty values_list() clause are ignored completely
|
||||
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')]
|
||||
)
|
||||
|
||||
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']
|
||||
)
|
||||
|
||||
# Only the extra columns specified in the values_list() are returned
|
||||
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')]
|
||||
)
|
||||
|
||||
# ...also works if only extra columns are included
|
||||
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')]
|
||||
)
|
||||
|
||||
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']
|
||||
)
|
||||
|
||||
# ... and values are returned in the order they are specified
|
||||
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')]
|
||||
)
|
||||
|
||||
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)]
|
||||
)
|
||||
|
||||
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)]
|
||||
)
|
||||
|
||||
|
|
|
@ -156,14 +156,18 @@ class FileUploadTests(TestCase):
|
|||
(#22971).
|
||||
"""
|
||||
payload = client.FakePayload()
|
||||
payload.write('\r\n'.join([
|
||||
'--' + client.BOUNDARY,
|
||||
'Content-Disposition: form-data; name*=UTF-8\'\'file_unicode; filename*=UTF-8\'\'%s' % urlquote(UNICODE_FILENAME),
|
||||
'Content-Type: application/octet-stream',
|
||||
'',
|
||||
'You got pwnd.\r\n',
|
||||
'\r\n--' + client.BOUNDARY + '--\r\n'
|
||||
]))
|
||||
payload.write(
|
||||
'\r\n'.join([
|
||||
'--' + client.BOUNDARY,
|
||||
'Content-Disposition: form-data; name*=UTF-8\'\'file_unicode; filename*=UTF-8\'\'%s' % urlquote(
|
||||
UNICODE_FILENAME
|
||||
),
|
||||
'Content-Type: application/octet-stream',
|
||||
'',
|
||||
'You got pwnd.\r\n',
|
||||
'\r\n--' + client.BOUNDARY + '--\r\n'
|
||||
])
|
||||
)
|
||||
|
||||
r = {
|
||||
'CONTENT_LENGTH': len(payload),
|
||||
|
|
|
@ -89,32 +89,83 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
])
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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,
|
||||
# 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
|
||||
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.
|
||||
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
|
||||
management.call_command('loaddata', 'fixture2.json', verbosity=0)
|
||||
|
@ -174,20 +225,106 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
])
|
||||
|
||||
# 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
|
||||
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.
|
||||
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
|
||||
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
|
||||
self._dumpdata_assert(['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)
|
||||
self._dumpdata_assert(
|
||||
['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):
|
||||
# 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
|
||||
self._dumpdata_assert(
|
||||
['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"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book'])
|
||||
'[{"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"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book']
|
||||
)
|
||||
|
||||
# Excluding fixtures and fixtures.Article/Book should be a no-op
|
||||
self._dumpdata_assert(
|
||||
['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"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book'])
|
||||
'[{"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"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book']
|
||||
)
|
||||
|
||||
# Excluding sites and fixtures.Article/Book should only leave fixtures.Category
|
||||
self._dumpdata_assert(
|
||||
['sites', 'fixtures'],
|
||||
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book', 'sites'])
|
||||
'[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": '
|
||||
'"News Stories"}}]',
|
||||
exclude_list=['fixtures.Article', 'fixtures.Book', 'sites']
|
||||
)
|
||||
|
||||
# Excluding a bogus app should throw an error
|
||||
with six.assertRaisesRegex(self, management.CommandError,
|
||||
|
@ -239,23 +384,34 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
self.assertQuerysetEqual(Spy.objects.all(),
|
||||
['<Spy: Paul>'])
|
||||
# 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,
|
||||
# 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):
|
||||
management.call_command('loaddata', 'fixture1.json', verbosity=0)
|
||||
management.call_command('loaddata', 'fixture2.json', verbosity=0)
|
||||
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": "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'
|
||||
)
|
||||
|
||||
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": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", '
|
||||
'"pub_date": "2006-06-16T12:00:00"}}]',
|
||||
primary_keys='2'
|
||||
)
|
||||
|
||||
|
@ -263,7 +419,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
"You can only use --pks option with one model"):
|
||||
self._dumpdata_assert(
|
||||
['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'
|
||||
)
|
||||
|
||||
|
@ -271,7 +429,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
"You can only use --pks option with one model"):
|
||||
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'
|
||||
)
|
||||
|
||||
|
@ -279,14 +439,22 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
"You can only use --pks option with one model"):
|
||||
self._dumpdata_assert(
|
||||
['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'
|
||||
)
|
||||
|
||||
def test_dumpdata_with_file_output(self):
|
||||
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"}}]',
|
||||
filename='dumpdata.json')
|
||||
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"}}]',
|
||||
filename='dumpdata.json'
|
||||
)
|
||||
|
||||
def test_dumpdata_progressbar(self):
|
||||
"""
|
||||
|
@ -414,11 +582,42 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
|
|||
], ordered=False)
|
||||
|
||||
# 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
|
||||
self._dumpdata_assert(['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)
|
||||
self._dumpdata_assert(
|
||||
['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):
|
||||
|
@ -476,7 +675,13 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
|
|||
])
|
||||
|
||||
# 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
|
||||
management.call_command('loaddata', 'fixture4', verbosity=0)
|
||||
|
|
|
@ -239,7 +239,10 @@ class TestFixtures(TestCase):
|
|||
)
|
||||
warning = warning_list.pop()
|
||||
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):
|
||||
"""
|
||||
|
@ -256,7 +259,10 @@ class TestFixtures(TestCase):
|
|||
)
|
||||
warning = warning_list.pop()
|
||||
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):
|
||||
"""
|
||||
|
@ -272,7 +278,8 @@ class TestFixtures(TestCase):
|
|||
)
|
||||
warning = warning_list.pop()
|
||||
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):
|
||||
"""
|
||||
|
@ -289,7 +296,10 @@ class TestFixtures(TestCase):
|
|||
)
|
||||
warning = warning_list.pop()
|
||||
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):
|
||||
"""
|
||||
|
@ -394,9 +404,18 @@ class TestFixtures(TestCase):
|
|||
data = re.sub('0{6,}[0-9]', '', data)
|
||||
|
||||
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": animal.pk, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}},
|
||||
{
|
||||
"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": animal.pk, "model": "fixtures_regress.animal",
|
||||
"fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}
|
||||
},
|
||||
], key=lambda x: x["pk"])
|
||||
|
||||
data = sorted(json.loads(data), key=lambda x: x["pk"])
|
||||
|
@ -636,7 +655,13 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
)
|
||||
self.assertJSONEqual(
|
||||
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):
|
||||
|
@ -711,7 +736,8 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
def test_dependency_sorting_tight_circular(self):
|
||||
self.assertRaisesMessage(
|
||||
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,
|
||||
[('fixtures_regress', [Person, Circle2, Circle1, Store, Book])],
|
||||
)
|
||||
|
@ -719,7 +745,8 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
def test_dependency_sorting_tight_circular_2(self):
|
||||
self.assertRaisesMessage(
|
||||
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,
|
||||
[('fixtures_regress', [Circle1, Book, Circle2])],
|
||||
)
|
||||
|
@ -727,7 +754,8 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
def test_dependency_self_referential(self):
|
||||
self.assertRaisesMessage(
|
||||
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,
|
||||
[('fixtures_regress', [Book, Circle3])],
|
||||
)
|
||||
|
@ -735,7 +763,9 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
def test_dependency_sorting_long(self):
|
||||
self.assertRaisesMessage(
|
||||
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,
|
||||
[('fixtures_regress', [Person, Circle2, Circle1, Circle3, Store, Book])],
|
||||
)
|
||||
|
@ -772,7 +802,9 @@ class NaturalKeyFixtureTests(TestCase):
|
|||
books = Book.objects.all()
|
||||
self.assertEqual(
|
||||
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)>]"
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -157,7 +157,11 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin):
|
|||
f = URLField(error_messages=e, max_length=17)
|
||||
self.assertFormErrors(['REQUIRED'], f.clean, '')
|
||||
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):
|
||||
e = {
|
||||
|
@ -226,8 +230,14 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin):
|
|||
|
||||
# This form should print errors the default way.
|
||||
form1 = TestForm({'first_name': 'John'})
|
||||
self.assertHTMLEqual(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>')
|
||||
self.assertHTMLEqual(
|
||||
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.
|
||||
form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList)
|
||||
|
|
|
@ -117,14 +117,18 @@ class FieldsTests(SimpleTestCase):
|
|||
f = CharField(max_length=10, required=False)
|
||||
self.assertEqual('12345', f.clean('12345'))
|
||||
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.min_length, None)
|
||||
|
||||
def test_charfield_4(self):
|
||||
f = CharField(min_length=10, required=False)
|
||||
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('1234567890a', f.clean('1234567890a'))
|
||||
self.assertEqual(f.max_length, None)
|
||||
|
@ -133,7 +137,9 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_charfield_5(self):
|
||||
f = CharField(min_length=10, required=True)
|
||||
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('1234567890a', f.clean('1234567890a'))
|
||||
self.assertEqual(f.max_length, None)
|
||||
|
@ -327,7 +333,10 @@ class FieldsTests(SimpleTestCase):
|
|||
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.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(0.5, f.clean('0.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.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(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.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 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.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('-00.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(ValidationError, "'Ensure that there are no more than 4 digits in total.'", f.clean, '-000.12345')
|
||||
self.assertRaisesMessage(
|
||||
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.assertEqual(f.max_digits, 4)
|
||||
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'))
|
||||
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 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('0.5'), Decimal("0.5"))
|
||||
self.assertEqual(f.clean('.5'), Decimal("0.5"))
|
||||
|
@ -419,7 +449,10 @@ class FieldsTests(SimpleTestCase):
|
|||
|
||||
def test_decimalfield_4(self):
|
||||
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):
|
||||
f = DecimalField(max_digits=3)
|
||||
|
@ -429,13 +462,19 @@ class FieldsTests(SimpleTestCase):
|
|||
self.assertEqual(f.clean('0000000.100'), Decimal("0.100"))
|
||||
# Only leading whole zeros "collapse" to one digit.
|
||||
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"))
|
||||
|
||||
def test_decimalfield_6(self):
|
||||
f = DecimalField(max_digits=2, decimal_places=2)
|
||||
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):
|
||||
f = DecimalField(max_digits=2, decimal_places=2)
|
||||
|
@ -588,8 +627,14 @@ class FieldsTests(SimpleTestCase):
|
|||
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, 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(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, 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.0002'))
|
||||
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'])
|
||||
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, 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, 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.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):
|
||||
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')
|
||||
six.assertRaisesRegex(self, ValidationError, "'Ensure this value has at least 5 characters \(it has 3\)\.', u?'Enter a valid value\.'", f.clean, 'abc')
|
||||
self.assertRaisesMessage(
|
||||
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('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')
|
||||
|
||||
def test_regexfield_6(self):
|
||||
|
@ -769,9 +831,15 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_emailfield_min_max_length(self):
|
||||
f = EmailField(min_length=10, max_length=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.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 ##################################################################
|
||||
|
||||
|
@ -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.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(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.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.assertRaisesMessage(ValidationError, "'No file was submitted. Check the encoding type on the form.'", 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.assertRaisesMessage(
|
||||
ValidationError, "'No file was submitted. Check the encoding type on the form.'",
|
||||
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('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode('utf-8')))))
|
||||
self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content'), 'files/test4.pdf')))
|
||||
self.assertIsInstance(
|
||||
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):
|
||||
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/test2.pdf', f.clean(None, 'files/test2.pdf'))
|
||||
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.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('http://www.example.com/s/http://code.djangoproject.com/ticket/13804', f.clean('www.example.com/s/http://code.djangoproject.com/ticket/13804'))
|
||||
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(
|
||||
'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, 'http://[a')
|
||||
|
||||
|
@ -926,9 +1024,15 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_urlfield_5(self):
|
||||
f = URLField(min_length=15, max_length=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.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):
|
||||
f = URLField(required=False)
|
||||
|
@ -1033,7 +1137,10 @@ class FieldsTests(SimpleTestCase):
|
|||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||
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):
|
||||
f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False)
|
||||
|
@ -1041,22 +1148,36 @@ class FieldsTests(SimpleTestCase):
|
|||
self.assertEqual('', f.clean(None))
|
||||
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):
|
||||
f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')])
|
||||
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):
|
||||
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('3', f.clean(3))
|
||||
self.assertEqual('3', f.clean('3'))
|
||||
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):
|
||||
choices = lambda: [('J', 'John'), ('P', 'Paul')]
|
||||
|
@ -1093,7 +1214,10 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_typedchoicefield_1(self):
|
||||
f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
|
||||
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):
|
||||
# Different coercion, same validation.
|
||||
|
@ -1109,7 +1233,10 @@ class FieldsTests(SimpleTestCase):
|
|||
# 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!
|
||||
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
|
||||
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)
|
||||
self.assertEqual(Decimal('1.2'), f.clean('2'))
|
||||
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, "'This field is required.'",
|
||||
f.clean, ''
|
||||
)
|
||||
self.assertRaisesMessage(
|
||||
ValidationError, "'Select a valid choice. 3 is not one of the available choices.'",
|
||||
f.clean, '3'
|
||||
)
|
||||
|
||||
# NullBooleanField ############################################################
|
||||
|
||||
|
@ -1168,7 +1298,11 @@ class FieldsTests(SimpleTestCase):
|
|||
hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True)
|
||||
hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False)
|
||||
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):
|
||||
class HiddenNullBooleanForm(Form):
|
||||
|
@ -1218,7 +1352,10 @@ class FieldsTests(SimpleTestCase):
|
|||
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, "'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):
|
||||
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.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):
|
||||
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', '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(ValidationError, "'Select a valid choice. 6 is not one of the available choices.'", f.clean, ['1', '6'])
|
||||
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, ['1', '6']
|
||||
)
|
||||
|
||||
def test_multiplechoicefield_changed(self):
|
||||
f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two'), ('3', 'Three')])
|
||||
|
@ -1262,7 +1410,10 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_typedmultiplechoicefield_1(self):
|
||||
f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
|
||||
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):
|
||||
# Different coercion, same validation.
|
||||
|
@ -1277,13 +1428,19 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_typedmultiplechoicefield_4(self):
|
||||
f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int)
|
||||
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):
|
||||
# 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!
|
||||
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
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, [])
|
||||
|
||||
|
@ -1324,7 +1481,10 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_combofield_1(self):
|
||||
f = ComboField(fields=[CharField(max_length=20), EmailField()])
|
||||
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, "'This field is required.'", f.clean, '')
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||
|
@ -1332,7 +1492,10 @@ class FieldsTests(SimpleTestCase):
|
|||
def test_combofield_2(self):
|
||||
f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False)
|
||||
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.assertEqual('', f.clean(''))
|
||||
self.assertEqual('', f.clean(None))
|
||||
|
@ -1362,7 +1525,10 @@ class FieldsTests(SimpleTestCase):
|
|||
for exp, got in zip(expected, fix_os_paths(f.choices)):
|
||||
self.assertEqual(exp[1], got[1])
|
||||
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')
|
||||
|
||||
def test_filepathfield_3(self):
|
||||
|
@ -1437,24 +1603,36 @@ class FieldsTests(SimpleTestCase):
|
|||
from django.forms.widgets import SplitDateTimeWidget
|
||||
f = SplitDateTimeField()
|
||||
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, '')
|
||||
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 date.'", f.clean, ['hello', '07:30'])
|
||||
|
||||
def test_splitdatetimefield_2(self):
|
||||
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.assertIsNone(f.clean(None))
|
||||
self.assertIsNone(f.clean(''))
|
||||
self.assertIsNone(f.clean(['']))
|
||||
self.assertIsNone(f.clean(['', '']))
|
||||
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 date.'", f.clean, ['hello', '07:30'])
|
||||
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.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, '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')
|
||||
|
||||
|
@ -1518,7 +1699,10 @@ class FieldsTests(SimpleTestCase):
|
|||
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, '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')
|
||||
|
||||
|
@ -1535,7 +1719,10 @@ class FieldsTests(SimpleTestCase):
|
|||
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, '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')
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -101,9 +101,15 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
# for adding data. By default, it displays 1 blank form. It can display more,
|
||||
# but we'll look at how to do so later.
|
||||
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>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
|
||||
# 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:
|
||||
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>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.
|
||||
formset = self.make_choiceformset([('Calexico', '100'), ('', '')], initial_forms=1)
|
||||
|
@ -212,7 +221,10 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
# handle that case later.
|
||||
formset = self.make_choiceformset([('', ''), ('', '')], initial_forms=1)
|
||||
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):
|
||||
# Displaying more than 1 blank form ###########################################
|
||||
|
@ -226,12 +238,15 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>Choice: <input type="text" name="choices-1-choice" /></li>
|
||||
<li>Votes: <input type="number" name="choices-1-votes" /></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.
|
||||
# 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.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>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):
|
||||
# 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:
|
||||
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>Choice: <input type="text" name="choices-1-choice" /></li>
|
||||
<li>Votes: <input type="number" name="choices-1-votes" /></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):
|
||||
# We can just fill out one of the forms.
|
||||
|
@ -388,20 +409,26 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>Choice: <input type="text" name="choices-1-choice" /></li>
|
||||
<li>Votes: <input type="number" name="choices-1-votes" /></li>
|
||||
<li>Choice: <input type="text" name="choices-2-choice" /></li>
|
||||
<li>Votes: <input type="number" name="choices-2-votes" /></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
|
||||
|
||||
self.assertTrue(formset.empty_form.empty_permitted)
|
||||
self.assertHTMLEqual(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>""")
|
||||
self.assertHTMLEqual(
|
||||
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):
|
||||
# FormSets with deletion ######################################################
|
||||
|
@ -418,7 +445,9 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>Delete: <input type="checkbox" name="choices-0-DELETE" /></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>Choice: <input type="text" name="choices-2-choice" /></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
|
||||
# 'on'. Let's go ahead and delete Fergie.
|
||||
|
@ -449,8 +479,18 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
|
||||
formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
|
||||
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([form.cleaned_data for form in formset.deleted_forms], [{'votes': 900, 'DELETE': True, 'choice': 'Fergie'}])
|
||||
self.assertEqual(
|
||||
[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
|
||||
# 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:
|
||||
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>Order: <input type="number" name="choices-0-ORDER" value="1" /></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>Choice: <input type="text" name="choices-2-choice" /></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 = {
|
||||
'choices-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -631,7 +674,9 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>Order: <input type="number" name="choices-0-ORDER" value="1" /></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>Votes: <input type="number" name="choices-3-votes" /></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.
|
||||
|
||||
|
@ -684,7 +730,10 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
{'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': 'The Decemberists'},
|
||||
{'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):
|
||||
# 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:
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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.
|
||||
LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0)
|
||||
|
@ -782,8 +837,13 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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.
|
||||
|
||||
|
@ -794,7 +854,11 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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):
|
||||
# max_num with initial data
|
||||
|
@ -813,8 +877,13 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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):
|
||||
# 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:
|
||||
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>
|
||||
<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>""")
|
||||
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="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):
|
||||
# More initial forms than max_num now results in all initial forms
|
||||
|
@ -861,9 +935,15 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
|
||||
for form in formset.forms:
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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
|
||||
# initial form and one extra.
|
||||
|
@ -877,8 +957,13 @@ class FormsFormsetTestCase(SimpleTestCase):
|
|||
for form in formset.forms:
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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):
|
||||
# Regression test for #6926 ##################################################
|
||||
|
@ -1157,21 +1242,39 @@ ChoiceFormSet = formset_factory(Choice)
|
|||
class FormsetAsFooTests(SimpleTestCase):
|
||||
def test_as_table(self):
|
||||
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>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):
|
||||
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>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):
|
||||
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>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 #################################################
|
||||
|
@ -1241,8 +1344,14 @@ class TestEmptyFormSet(SimpleTestCase):
|
|||
def test_empty_formset_is_valid(self):
|
||||
"""Test that an empty formset still calls clean()"""
|
||||
EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate)
|
||||
formset = EmptyFsetWontValidateFormset(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")
|
||||
formset = EmptyFsetWontValidateFormset(
|
||||
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(formset2.is_valid())
|
||||
|
||||
|
|
|
@ -14,12 +14,18 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
|
||||
def test_construction(self):
|
||||
# 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'))
|
||||
self.assertEqual(str(m), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
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'),
|
||||
)
|
||||
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" />
|
||||
<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="https://secure.other.com/path/to/js3"></script>""")
|
||||
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
|
||||
)
|
||||
|
||||
class Foo:
|
||||
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')
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
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')
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
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" />""")
|
||||
|
||||
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="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):
|
||||
# Media objects can be combined. Any given media resource will appear only
|
||||
|
@ -98,20 +115,26 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
w1 = MyWidget1()
|
||||
w2 = MyWidget2()
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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
|
||||
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" />
|
||||
<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="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
|
||||
# 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')
|
||||
|
||||
w4 = MyWidget4()
|
||||
self.assertEqual(str(w4.media), """<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/path/to/js1"></script>""")
|
||||
self.assertEqual(
|
||||
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):
|
||||
###############################################################
|
||||
|
@ -147,10 +173,13 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
media = property(_media)
|
||||
|
||||
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" />
|
||||
<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):
|
||||
# Media properties can reference the media of their parents,
|
||||
|
@ -168,13 +197,16 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
media = property(_media)
|
||||
|
||||
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="/other/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
###############################################################
|
||||
|
@ -193,11 +225,14 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
pass
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
class MyWidget8(MyWidget1):
|
||||
|
@ -208,13 +243,16 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
# 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',)
|
||||
|
||||
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" />
|
||||
<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'
|
||||
class MyWidget10(MyWidget1):
|
||||
|
@ -277,13 +318,16 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
# 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')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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):
|
||||
###############################################################
|
||||
|
@ -325,12 +372,15 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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="/file1" 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/js4"></script>""")
|
||||
<script type="text/javascript" src="/path/to/js4"></script>"""
|
||||
)
|
||||
|
||||
def test_multi_widget(self):
|
||||
###############################################################
|
||||
|
@ -366,13 +416,16 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
super(MyMultiWidget, self).__init__(widgets, attrs)
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
###############################################################
|
||||
|
@ -405,25 +458,31 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
field1 = CharField(max_length=20, widget=MyWidget1())
|
||||
field2 = CharField(max_length=20, widget=MyWidget2())
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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.
|
||||
class AnotherForm(Form):
|
||||
field3 = CharField(max_length=20, widget=MyWidget3())
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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.
|
||||
class FormWithMedia(Form):
|
||||
|
@ -436,7 +495,9 @@ class FormsMediaTestCase(SimpleTestCase):
|
|||
'all': ('/some/form/css',)
|
||||
}
|
||||
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/css3" 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="https://secure.other.com/path/to/js3"></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
|
||||
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="https://secure.other.com/path/to/js3"></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/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):
|
||||
media = Media(css={'all': ['/path/to/css']}, js=['/path/to/js'])
|
||||
|
@ -471,12 +538,18 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
|
||||
def test_construction(self):
|
||||
# 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'))
|
||||
self.assertEqual(str(m), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
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'),
|
||||
)
|
||||
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" />
|
||||
<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="https://secure.other.com/path/to/js3"></script>""")
|
||||
<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>"""
|
||||
)
|
||||
|
||||
class Foo:
|
||||
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')
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
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')
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
self.assertEqual(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['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="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):
|
||||
# Media objects can be combined. Any given media resource will appear only
|
||||
|
@ -555,20 +640,26 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
w1 = MyWidget1()
|
||||
w2 = MyWidget2()
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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
|
||||
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" />
|
||||
<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="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
|
||||
# multiple times in a single Media instance should result in that file
|
||||
|
@ -625,13 +716,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
media = property(_media)
|
||||
|
||||
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="/other/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
###############################################################
|
||||
|
@ -650,11 +744,14 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
pass
|
||||
|
||||
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" />
|
||||
<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="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
|
||||
class MyWidget8(MyWidget1):
|
||||
|
@ -665,13 +762,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
# 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',)
|
||||
|
||||
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" />
|
||||
<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'
|
||||
class MyWidget10(MyWidget1):
|
||||
|
@ -734,13 +837,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
# 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')
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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):
|
||||
###############################################################
|
||||
|
@ -782,12 +891,15 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
js = ('/path/to/js1', '/path/to/js4')
|
||||
|
||||
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="/file1" 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/js4"></script>""")
|
||||
<script type="text/javascript" src="/path/to/js4"></script>"""
|
||||
)
|
||||
|
||||
def test_multi_widget(self):
|
||||
###############################################################
|
||||
|
@ -823,13 +935,16 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
super(MyMultiWidget, self).__init__(widgets, attrs)
|
||||
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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):
|
||||
###############################################################
|
||||
|
@ -862,25 +977,31 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
field1 = CharField(max_length=20, widget=MyWidget1())
|
||||
field2 = CharField(max_length=20, widget=MyWidget2())
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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.
|
||||
class AnotherForm(Form):
|
||||
field3 = CharField(max_length=20, widget=MyWidget3())
|
||||
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/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<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="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.
|
||||
class FormWithMedia(Form):
|
||||
|
@ -893,7 +1014,9 @@ class StaticFormsMediaTestCase(SimpleTestCase):
|
|||
'all': ('/some/form/css',)
|
||||
}
|
||||
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/css3" 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="https://secure.other.com/path/to/js3"></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
|
||||
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="https://secure.other.com/path/to/js3"></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/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" />"""
|
||||
)
|
||||
|
|
|
@ -22,7 +22,11 @@ class FormsRegressionsTestCase(TestCase):
|
|||
f1 = CharField(max_length=10, 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):
|
||||
# Tests for form i18n #
|
||||
|
@ -32,19 +36,35 @@ class FormsRegressionsTestCase(TestCase):
|
|||
username = CharField(max_length=10, label=ugettext_lazy('username'))
|
||||
|
||||
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)
|
||||
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'):
|
||||
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):
|
||||
# There was some problems with form translations in #5216
|
||||
class SomeForm(Form):
|
||||
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()
|
||||
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')
|
||||
|
||||
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.
|
||||
with translation.override('ru'):
|
||||
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)
|
||||
class CopyForm(Form):
|
||||
|
@ -95,8 +141,18 @@ class FormsRegressionsTestCase(TestCase):
|
|||
data = IntegerField(widget=HiddenInput)
|
||||
|
||||
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(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>')
|
||||
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(
|
||||
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):
|
||||
###################################################
|
||||
|
@ -114,13 +170,23 @@ class FormsRegressionsTestCase(TestCase):
|
|||
field = ChoiceField(choices=[('one', 'One')])
|
||||
|
||||
f = SomeForm({'field': '<script>'})
|
||||
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. <script> 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. <script> is not one of the '
|
||||
'available choices.</li></ul></li></ul>'
|
||||
)
|
||||
|
||||
class SomeForm(Form):
|
||||
field = MultipleChoiceField(choices=[('one', 'One')])
|
||||
|
||||
f = SomeForm({'field': ['<script>']})
|
||||
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>Select a valid choice. <script> 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. <script> is not one of the '
|
||||
'available choices.</li></ul></li></ul>'
|
||||
)
|
||||
|
||||
from forms_tests.models import ChoiceModel
|
||||
|
||||
|
@ -128,7 +194,12 @@ class FormsRegressionsTestCase(TestCase):
|
|||
field = ModelMultipleChoiceField(ChoiceModel.objects.all())
|
||||
|
||||
f = SomeForm({'field': ['<script>']})
|
||||
self.assertHTMLEqual(t.render(Context({'form': f})), '<ul class="errorlist"><li>field<ul class="errorlist"><li>"<script>" 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>"<script>" is not a valid value for a '
|
||||
'primary key.</li></ul></li></ul>'
|
||||
)
|
||||
|
||||
def test_regression_14234(self):
|
||||
"""
|
||||
|
|
|
@ -22,9 +22,18 @@ class FormsUtilsTestCase(SimpleTestCase):
|
|||
|
||||
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", 'required': "required"}), ' 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({'class': "news", 'title': "Read this", 'required': "required"}),
|
||||
' 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({}), '')
|
||||
|
||||
def test_flatatt_no_side_effects(self):
|
||||
|
@ -97,19 +106,33 @@ class FormsUtilsTestCase(SimpleTestCase):
|
|||
return "A very bad error."
|
||||
|
||||
# Can take a non-string.
|
||||
self.assertHTMLEqual(str(ErrorList(ValidationError(VeryBadError()).messages)),
|
||||
'<ul class="errorlist"><li>A very bad error.</li></ul>')
|
||||
self.assertHTMLEqual(
|
||||
str(ErrorList(ValidationError(VeryBadError()).messages)),
|
||||
'<ul class="errorlist"><li>A very bad error.</li></ul>'
|
||||
)
|
||||
|
||||
# Escapes non-safe input but not input marked safe.
|
||||
example = 'Example of link: <a href="http://www.example.com/">example</a>'
|
||||
self.assertHTMLEqual(str(ErrorList([example])),
|
||||
'<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>')
|
||||
self.assertHTMLEqual(str(ErrorList([mark_safe(example)])),
|
||||
'<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: <a href="http://www.example.com/">example</a></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>')
|
||||
self.assertHTMLEqual(
|
||||
str(ErrorList([example])),
|
||||
'<ul class="errorlist"><li>Example of link: '
|
||||
'<a href="http://www.example.com/">example</a></li></ul>'
|
||||
)
|
||||
self.assertHTMLEqual(
|
||||
str(ErrorList([mark_safe(example)])),
|
||||
'<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: '
|
||||
'<a href="http://www.example.com/">example</a></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):
|
||||
e = ErrorDict()
|
||||
|
|
|
@ -40,7 +40,11 @@ class UserForm(forms.Form):
|
|||
|
||||
class TestFieldWithValidators(TestCase):
|
||||
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')
|
||||
|
||||
try:
|
||||
|
|
|
@ -34,7 +34,15 @@ class FormsWidgetTests(SimpleTestCase):
|
|||
inp_set1.append(str(inp))
|
||||
inp_set2.append('%s<br />' % inp)
|
||||
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>
|
||||
<label><input type="radio" name="beatle" value="P" /> Paul</label>
|
||||
|
@ -57,7 +65,10 @@ beatle J R Ringo False""")
|
|||
w = RadioSelect()
|
||||
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[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.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'))
|
||||
|
@ -76,30 +87,39 @@ beatle J R Ringo False""")
|
|||
def render(self):
|
||||
return '<br />\n'.join(six.text_type(choice) for choice in self)
|
||||
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 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.
|
||||
class CustomRadioSelect(RadioSelect):
|
||||
renderer = MyRenderer
|
||||
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 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)
|
||||
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>'
|
||||
w = RadioSelect(renderer=MyRenderer)
|
||||
output = w.render('beatle', 'J',
|
||||
choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')),
|
||||
attrs={'id': 'bar'})
|
||||
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_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>
|
||||
|
|
|
@ -101,7 +101,9 @@ class ModelFormCallableModelDefault(TestCase):
|
|||
ChoiceOptionModel.objects.create(id=1, name='default')
|
||||
ChoiceOptionModel.objects.create(id=2, name='option 2')
|
||||
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="2">ChoiceOption 2</option>
|
||||
<option value="3">ChoiceOption 3</option>
|
||||
|
@ -111,28 +113,33 @@ class ModelFormCallableModelDefault(TestCase):
|
|||
<option value="2">ChoiceOption 2</option>
|
||||
<option value="3">ChoiceOption 3</option>
|
||||
</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="2">ChoiceOption 2</option>
|
||||
<option value="3">ChoiceOption 3</option>
|
||||
</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="2">ChoiceOption 2</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):
|
||||
"Initial instances for model fields may also be instances (refs #7287)"
|
||||
ChoiceOptionModel.objects.create(id=1, name='default')
|
||||
obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2')
|
||||
obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3')
|
||||
self.assertHTMLEqual(ChoiceFieldForm(initial={
|
||||
'choice': obj2,
|
||||
'choice_int': obj2,
|
||||
'multi_choice': [obj2, obj3],
|
||||
'multi_choice_int': ChoiceOptionModel.objects.exclude(name="default"),
|
||||
}).as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice">
|
||||
self.assertHTMLEqual(
|
||||
ChoiceFieldForm(initial={
|
||||
'choice': obj2,
|
||||
'choice_int': obj2,
|
||||
'multi_choice': [obj2, obj3],
|
||||
'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="2" selected="selected">ChoiceOption 2</option>
|
||||
<option value="3">ChoiceOption 3</option>
|
||||
|
@ -142,24 +149,28 @@ class ModelFormCallableModelDefault(TestCase):
|
|||
<option value="2" selected="selected">ChoiceOption 2</option>
|
||||
<option value="3">ChoiceOption 3</option>
|
||||
</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="2" selected="selected">ChoiceOption 2</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" />
|
||||
<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="2" selected="selected">ChoiceOption 2</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" />
|
||||
<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):
|
||||
def test_unicode_filename(self):
|
||||
# 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.assertIn('file1', f.cleaned_data)
|
||||
m = FileModel.objects.create(file=f.cleaned_data['file1'])
|
||||
|
@ -287,23 +298,28 @@ class ManyToManyExclusionTestCase(TestCase):
|
|||
class EmptyLabelTestCase(TestCase):
|
||||
def test_empty_field_char(self):
|
||||
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_choice">Choice:</label> <select id="id_choice" name="choice">
|
||||
<option value="" selected="selected">No Preference</option>
|
||||
<option value="f">Foo</option>
|
||||
<option value="b">Bar</option>
|
||||
</select></p>""")
|
||||
</select></p>"""
|
||||
)
|
||||
|
||||
def test_empty_field_char_none(self):
|
||||
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_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="f">Foo</option>
|
||||
<option value="b">Bar</option>
|
||||
</select></p>""")
|
||||
</select></p>"""
|
||||
)
|
||||
|
||||
def test_save_empty_label_forms(self):
|
||||
# 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):
|
||||
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_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="1">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
</select></p>"""
|
||||
)
|
||||
|
||||
def test_get_display_value_on_none(self):
|
||||
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):
|
||||
none_model = ChoiceModel(name='none-test', choice_integer=None)
|
||||
f = EmptyIntegerLabelChoiceForm(instance=none_model)
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<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">
|
||||
self.assertHTMLEqual(
|
||||
f.as_p(),
|
||||
"""<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="1">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
</select></p>"""
|
||||
)
|
||||
|
||||
foo_model = ChoiceModel(name='foo-test', choice_integer=1)
|
||||
f = EmptyIntegerLabelChoiceForm(instance=foo_model)
|
||||
self.assertHTMLEqual(f.as_p(),
|
||||
"""<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">
|
||||
self.assertHTMLEqual(
|
||||
f.as_p(),
|
||||
"""<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="1" selected="selected">Foo</option>
|
||||
<option value="2">Bar</option>
|
||||
</select></p>""")
|
||||
</select></p>"""
|
||||
)
|
||||
|
|
|
@ -110,28 +110,99 @@ class GenericAdminViewTest(TestDataMixin, TestCase):
|
|||
self.assertEqual(response.status_code, 302) # redirect somewhere
|
||||
|
||||
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')
|
||||
|
||||
# Works with no queryset
|
||||
formset = EpisodeMediaFormSet(instance=e)
|
||||
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(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>')
|
||||
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(
|
||||
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
|
||||
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url'))
|
||||
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(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>')
|
||||
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(
|
||||
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
|
||||
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png"))
|
||||
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(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>')
|
||||
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(
|
||||
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):
|
||||
# Regression test for #10522.
|
||||
|
|
|
@ -403,12 +403,30 @@ class GenericRelationsTests(TestCase):
|
|||
def test_generic_inline_formsets(self):
|
||||
GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1)
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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())
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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(
|
||||
common_name="Platypus", latin_name="Ornithorhynchus anatinus"
|
||||
|
@ -419,14 +437,35 @@ class GenericRelationsTests(TestCase):
|
|||
tagged_item_id = TaggedItem.objects.get(
|
||||
tag='shiny', object_id=platypus.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>
|
||||
<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)
|
||||
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>
|
||||
<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")
|
||||
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>
|
||||
<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>""")
|
||||
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>
|
||||
<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):
|
||||
# GenericForeignKey should not use the default manager (which may filter objects) #16048
|
||||
|
|
|
@ -216,8 +216,14 @@ class YearArchiveViewTests(TestDataMixin, TestCase):
|
|||
res = self.client.get('/dates/books/2006/sortedbyname/')
|
||||
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['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.assertEqual(
|
||||
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')
|
||||
|
||||
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))
|
||||
res = self.client.get('/dates/books/2006/sortedbypageandnamedec/')
|
||||
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(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.assertEqual(
|
||||
list(res.context['date_list']),
|
||||
[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')
|
||||
|
||||
def test_year_view_invalid_pattern(self):
|
||||
|
@ -327,8 +342,14 @@ class MonthArchiveViewTests(TestDataMixin, TestCase):
|
|||
def test_month_view_paginated(self):
|
||||
res = self.client.get('/dates/books/2008/oct/paginated/')
|
||||
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(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10)))
|
||||
self.assertEqual(
|
||||
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')
|
||||
|
||||
def test_custom_month_format(self):
|
||||
|
@ -450,8 +471,14 @@ class WeekArchiveViewTests(TestDataMixin, TestCase):
|
|||
week_end = week_start + datetime.timedelta(days=7)
|
||||
res = self.client.get('/dates/books/2008/week/39/')
|
||||
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(list(res.context['object_list']), list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end)))
|
||||
self.assertEqual(
|
||||
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')
|
||||
|
||||
def test_week_view_invalid_pattern(self):
|
||||
|
@ -551,8 +578,14 @@ class DayArchiveViewTests(TestDataMixin, TestCase):
|
|||
def test_day_view_paginated(self):
|
||||
res = self.client.get('/dates/books/2008/oct/1/')
|
||||
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(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2008, pubdate__month=10, pubdate__day=1)))
|
||||
self.assertEqual(
|
||||
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')
|
||||
|
||||
def test_next_prev_context(self):
|
||||
|
|
|
@ -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-]+)/$',
|
||||
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]+)/$',
|
||||
views.BookDetailGetObjectCustomQueryset.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})/'
|
||||
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]+)/$',
|
||||
views.BookSigningDetail.as_view()),
|
||||
|
|
|
@ -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
|
||||
|
||||
'''
|
||||
''' # NOQA
|
||||
|
||||
|
||||
@skipUnlessDBFeature("gis_enabled")
|
||||
|
|
|
@ -180,7 +180,11 @@ class BasicExtractorTests(ExtractorTests):
|
|||
|
||||
# Comments in templates
|
||||
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: Two-line translator comment #1\n#. continued here.', 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: One-line translator comment #4', 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('#. Translators: Two-line translator comment #5 -- with non ASCII characters: áéíóúö\n#. continued here.', po_contents)
|
||||
self.assertIn(
|
||||
'#. 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):
|
||||
os.chdir(self.test_dir)
|
||||
|
@ -212,13 +224,12 @@ class BasicExtractorTests(ExtractorTests):
|
|||
|
||||
def test_extraction_error(self):
|
||||
os.chdir(self.test_dir)
|
||||
self.assertRaises(SyntaxError, management.call_command, 'makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0)
|
||||
with self.assertRaises(SyntaxError) as context_manager:
|
||||
management.call_command('makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0)
|
||||
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\)'
|
||||
msg = (
|
||||
'Translation blocks must not include other block tags: blocktrans '
|
||||
'(file %s, line 3)' % os.path.join('templates', 'template_with_error.tpl')
|
||||
)
|
||||
with self.assertRaisesMessage(SyntaxError, msg):
|
||||
management.call_command('makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0)
|
||||
# Check that the temporary file was cleaned up
|
||||
self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py'))
|
||||
|
||||
|
@ -303,15 +314,21 @@ class BasicExtractorTests(ExtractorTests):
|
|||
self.assertTrue(issubclass(w.category, TranslatorCommentWarning))
|
||||
six.assertRegex(
|
||||
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(
|
||||
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(
|
||||
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
|
||||
self.assertTrue(os.path.exists(self.PO_FILE))
|
||||
|
@ -581,7 +598,11 @@ class NoWrapExtractorTests(ExtractorTests):
|
|||
self.assertTrue(os.path.exists(self.PO_FILE))
|
||||
with open(self.PO_FILE, 'r') as fp:
|
||||
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):
|
||||
os.chdir(self.test_dir)
|
||||
|
@ -589,7 +610,12 @@ class NoWrapExtractorTests(ExtractorTests):
|
|||
self.assertTrue(os.path.exists(self.PO_FILE))
|
||||
with open(self.PO_FILE, 'r') as fp:
|
||||
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):
|
||||
|
|
|
@ -181,11 +181,21 @@ class TranslationTests(SimpleTestCase):
|
|||
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_deferred = ungettext_lazy('Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num')
|
||||
complex_str_nonlazy = ngettext_lazy(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')
|
||||
complex_deferred = ungettext_lazy(
|
||||
'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num'
|
||||
)
|
||||
complex_str_nonlazy = ngettext_lazy(
|
||||
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'):
|
||||
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')
|
||||
|
@ -311,42 +321,76 @@ class TranslationTests(SimpleTestCase):
|
|||
self.assertEqual(rendered, 'Kann')
|
||||
|
||||
# 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())
|
||||
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())
|
||||
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())
|
||||
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())
|
||||
self.assertEqual(rendered, '2 andere Super-Ergebnisse')
|
||||
|
||||
# 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())
|
||||
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())
|
||||
self.assertEqual(rendered, 'Andere: Es gibt 5 Kommentare')
|
||||
|
||||
# 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())
|
||||
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())
|
||||
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())
|
||||
self.assertEqual(rendered, '2 andere Super-Ergebnisse')
|
||||
|
||||
# Mis-uses
|
||||
self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context with month="May" %}{{ month }}{% endblocktrans %}')
|
||||
self.assertRaises(TemplateSyntaxError, Template, '{% load i18n %}{% blocktrans context %}{% 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 with month="May" %}{{ month }}{% 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):
|
||||
"""
|
||||
|
@ -496,8 +540,14 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertEqual('66666', nformat(self.n, decimal_sep='X', decimal_pos=0, grouping=1, thousand_sep='Y'))
|
||||
|
||||
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('6B6B6B6B6A6', nformat(self.n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B'))
|
||||
self.assertEqual(
|
||||
'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.0', nformat(int('-66666'), 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('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 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({
|
||||
'decimal_field': '66666,666',
|
||||
|
@ -562,7 +614,68 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertTrue(form2.is_valid())
|
||||
self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field'])
|
||||
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))
|
||||
)
|
||||
|
||||
|
@ -651,7 +764,10 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertEqual('100000,0', Template('{{ f|floatformat }}').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 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"),
|
||||
Template('{% now "DATE_FORMAT" %}').render(self.ctxt))
|
||||
|
||||
|
@ -680,14 +796,136 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertTrue(form5.is_valid())
|
||||
self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field'])
|
||||
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))
|
||||
)
|
||||
|
||||
# Russian locale (with E as month)
|
||||
with translation.override('ru', deactivate=True):
|
||||
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))
|
||||
)
|
||||
|
||||
|
@ -726,7 +964,10 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').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 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({
|
||||
'decimal_field': '66666.666',
|
||||
|
@ -752,7 +993,68 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertTrue(form6.is_valid())
|
||||
self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field'])
|
||||
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))
|
||||
)
|
||||
|
||||
|
@ -781,13 +1083,23 @@ class FormattingTests(SimpleTestCase):
|
|||
self.assertTrue(form6.is_valid())
|
||||
self.assertHTMLEqual(
|
||||
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(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
|
||||
with self.settings(USE_THOUSAND_SEPARATOR=True):
|
||||
# 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):
|
||||
"""
|
||||
|
@ -864,7 +1176,10 @@ class FormattingTests(SimpleTestCase):
|
|||
Tests the {% localize %} templatetag
|
||||
"""
|
||||
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 }}")
|
||||
template3 = Template('{% load l10n %}{{ value }};{{ value|unlocalize }}')
|
||||
template4 = Template('{% load l10n %}{{ value }};{{ value|localize }}')
|
||||
|
@ -890,7 +1205,9 @@ class FormattingTests(SimpleTestCase):
|
|||
with translation.override('de-at', deactivate=True):
|
||||
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_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({
|
||||
'name': 'acme',
|
||||
'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0),
|
||||
|
@ -902,15 +1219,18 @@ class FormattingTests(SimpleTestCase):
|
|||
|
||||
self.assertHTMLEqual(
|
||||
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(
|
||||
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(
|
||||
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([('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([('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([('de', 1.0)], p('de;q=0.'))
|
||||
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('en,,gb'))
|
||||
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('de;q=2.0'))
|
||||
self.assertEqual([], p('de;q=0.a'))
|
||||
|
@ -1110,7 +1436,11 @@ class MiscTests(SimpleTestCase):
|
|||
@override_settings(LOCALE_PATHS=extended_locale_paths)
|
||||
def test_percent_in_translatable_block(self):
|
||||
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'):
|
||||
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')
|
||||
|
@ -1123,7 +1453,11 @@ class MiscTests(SimpleTestCase):
|
|||
singular or plural
|
||||
"""
|
||||
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'):
|
||||
# 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')
|
||||
|
@ -1265,7 +1599,10 @@ class MultipleLocaleActivationTests(SimpleTestCase):
|
|||
with translation.override('fr'):
|
||||
self.assertEqual(Template("{{ _('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
|
||||
|
||||
|
|
|
@ -234,7 +234,10 @@ class InspectDBTestCase(TestCase):
|
|||
table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'),
|
||||
stdout=out)
|
||||
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',
|
||||
"Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")
|
||||
|
|
|
@ -138,9 +138,13 @@ class IntrospectionTests(TransactionTestCase):
|
|||
def test_get_relations_alt_format(self):
|
||||
"""With SQLite, foreign keys can be added with different syntaxes."""
|
||||
with connection.cursor() as cursor:
|
||||
cursor.fetchone = mock.Mock(return_value=[
|
||||
"CREATE TABLE track(id, art_id INTEGER, FOREIGN KEY(art_id) REFERENCES %s(id));" % Article._meta.db_table
|
||||
])
|
||||
cursor.fetchone = mock.Mock(
|
||||
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')
|
||||
self.assertEqual(relations, {'art_id': ('id', Article._meta.db_table)})
|
||||
|
||||
|
|
|
@ -357,7 +357,10 @@ class RelativeFieldTests(IsolatedModelsTestCase):
|
|||
self.assertEqual(errors, expected)
|
||||
|
||||
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):
|
||||
# Explicit symmetrical=True.
|
||||
friends = models.ManyToManyField('self',
|
||||
|
@ -394,8 +397,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
|
|||
errors = field.check()
|
||||
expected = [
|
||||
Error(
|
||||
("Field defines a relation with model 'AbstractModel', "
|
||||
"which is either not installed, or is abstract."),
|
||||
"Field defines a relation with model 'AbstractModel', "
|
||||
"which is either not installed, or is abstract.",
|
||||
hint=None,
|
||||
obj=field,
|
||||
id='fields.E300',
|
||||
|
@ -415,8 +418,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
|
|||
errors = field.check(from_model=Model)
|
||||
expected = [
|
||||
Error(
|
||||
("Field defines a relation with model 'AbstractModel', "
|
||||
"which is either not installed, or is abstract."),
|
||||
"Field defines a relation with model 'AbstractModel', "
|
||||
"which is either not installed, or is abstract.",
|
||||
hint=None,
|
||||
obj=field,
|
||||
id='fields.E300',
|
||||
|
@ -500,8 +503,8 @@ class RelativeFieldTests(IsolatedModelsTestCase):
|
|||
errors = field.check()
|
||||
expected = [
|
||||
Error(
|
||||
("None of the fields 'country_id', 'city_id' on model 'Person' "
|
||||
"have a unique=True constraint."),
|
||||
"None of the fields 'country_id', 'city_id' on model 'Person' "
|
||||
"have a unique=True constraint.",
|
||||
hint=None,
|
||||
obj=field,
|
||||
id='fields.E310',
|
||||
|
@ -1333,7 +1336,11 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
|
|||
pass
|
||||
|
||||
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):
|
||||
event = models.ForeignKey(Event, models.CASCADE)
|
||||
|
@ -1344,12 +1351,12 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
|
|||
errors = field.check(from_model=Event)
|
||||
expected = [
|
||||
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?",
|
||||
obj=field,
|
||||
id='fields.E338'),
|
||||
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?",
|
||||
obj=field,
|
||||
id='fields.E338'),
|
||||
|
@ -1376,9 +1383,9 @@ class M2mThroughFieldsTests(IsolatedModelsTestCase):
|
|||
errors = field.check(from_model=Event)
|
||||
expected = [
|
||||
Error(
|
||||
("Field specifies 'through_fields' but does not provide the names "
|
||||
"of the two link fields that should be used for the relation "
|
||||
"through model 'invalid_models_tests.Invitation'."),
|
||||
"Field specifies 'through_fields' but does not provide the names "
|
||||
"of the two link fields that should be used for the relation "
|
||||
"through model 'invalid_models_tests.Invitation'.",
|
||||
hint=("Make sure you specify 'through_fields' as "
|
||||
"through_fields=('field1', 'field2')"),
|
||||
obj=field,
|
||||
|
|
|
@ -229,7 +229,11 @@ class LookupTests(TestCase):
|
|||
{'name': self.au2.name, 'article__headline': self.a7.headline},
|
||||
], transform=identity)
|
||||
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.a2.headline, 'article__tag__name': self.t1.name},
|
||||
|
@ -311,7 +315,11 @@ class LookupTests(TestCase):
|
|||
],
|
||||
transform=identity)
|
||||
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.a2.headline, self.t1.name),
|
||||
|
|
|
@ -21,7 +21,11 @@ class Group(models.Model):
|
|||
name = models.CharField(max_length=128)
|
||||
members = models.ManyToManyField(Person, through='Membership')
|
||||
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:
|
||||
ordering = ('name',)
|
||||
|
@ -88,7 +92,11 @@ class Friendship(models.Model):
|
|||
@python_2_unicode_compatible
|
||||
class Event(models.Model):
|
||||
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):
|
||||
return self.title
|
||||
|
@ -104,7 +112,12 @@ class Invitation(models.Model):
|
|||
@python_2_unicode_compatible
|
||||
class Employee(models.Model):
|
||||
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:
|
||||
ordering = ('pk',)
|
||||
|
|
|
@ -105,7 +105,13 @@ class M2MThroughSerializationTestCase(TestCase):
|
|||
|
||||
out = StringIO()
|
||||
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()
|
||||
management.call_command("dumpdata", "m2m_through_regress", format="xml",
|
||||
|
@ -237,7 +243,15 @@ class ThroughLoadDataTestCase(TestCase):
|
|||
fixtures = ["m2m_through"]
|
||||
|
||||
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()
|
||||
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"}}]'
|
||||
)
|
||||
|
|
|
@ -81,16 +81,28 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
self.assertEqual(email.recipients(), ['to@example.com', 'cc@example.com'])
|
||||
|
||||
# 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()
|
||||
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
|
||||
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()
|
||||
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):
|
||||
email = EmailMessage(
|
||||
|
@ -108,10 +120,16 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
self.assertEqual(message['Reply-To'], 'reply_to1@example.com, reply_to2@example.com')
|
||||
|
||||
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()
|
||||
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):
|
||||
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):
|
||||
email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com'])
|
||||
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)
|
||||
|
||||
def test_space_continuation(self):
|
||||
"""
|
||||
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()
|
||||
# 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):
|
||||
"""
|
||||
|
@ -161,7 +189,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
"""
|
||||
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()
|
||||
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
|
||||
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()
|
||||
self.assertEqual(message['From'], 'from@example.com')
|
||||
message = email.message()
|
||||
|
@ -211,10 +245,22 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
make sure the email addresses are parsed correctly (especially with
|
||||
regards to commas)
|
||||
"""
|
||||
email = EmailMessage('Subject', 'Content', 'from@example.com', ['"Firstname Sürname" <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')
|
||||
email = EmailMessage(
|
||||
'Subject', 'Content', 'from@example.com',
|
||||
['"Firstname Sürname" <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):
|
||||
email = EmailMessage("Gżegżółka", "Content", "from@example.com", ["to@example.com"],
|
||||
|
@ -274,7 +320,9 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
('MIME-Version', '1.0'),
|
||||
('Content-Type', 'text/html; charset="iso-8859-1"'),
|
||||
('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):
|
||||
"""Regression test for #9367"""
|
||||
|
@ -341,7 +389,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
Make sure that dummy backends returns correct number of sent messages
|
||||
"""
|
||||
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)
|
||||
|
||||
def test_arbitrary_keyword(self):
|
||||
|
@ -356,19 +407,31 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
"""Test custom backend defined in this suite."""
|
||||
conn = mail.get_connection('mail.custombackend.EmailBackend')
|
||||
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])
|
||||
self.assertEqual(len(conn.test_outbox), 1)
|
||||
|
||||
def test_backend_arg(self):
|
||||
"""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.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.console.EmailBackend'), console.EmailBackend)
|
||||
self.assertIsInstance(
|
||||
mail.get_connection('django.core.mail.backends.console.EmailBackend'),
|
||||
console.EmailBackend
|
||||
)
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
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:
|
||||
shutil.rmtree(tmp_dir)
|
||||
self.assertIsInstance(mail.get_connection(), locmem.EmailBackend)
|
||||
|
@ -413,29 +476,44 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
def test_dont_mangle_from_in_body(self):
|
||||
# Regression for #13433 - Make sure that EmailMessage doesn't mangle
|
||||
# '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())
|
||||
|
||||
def test_dont_base64_encode(self):
|
||||
# Ticket #3472
|
||||
# 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())
|
||||
|
||||
# Ticket #11212
|
||||
# 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()
|
||||
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s)
|
||||
self.assertIn(b'Content-Transfer-Encoding: 7bit', s)
|
||||
|
||||
# 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()
|
||||
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', 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()
|
||||
self.assertNotIn(b'Content-Transfer-Encoding: quoted-printable', s)
|
||||
self.assertIn(b'Content-Transfer-Encoding: 8bit', s)
|
||||
|
@ -444,11 +522,17 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
# Ticket #18967
|
||||
# Shouldn't use base64 encoding for a child EmailMessage attachment.
|
||||
# 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()
|
||||
|
||||
# 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
|
||||
parent_msg.attach(content=child_s, mimetype='message/rfc822')
|
||||
|
@ -458,7 +542,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
self.assertIn(str('Child Subject'), parent_s)
|
||||
|
||||
# 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_s = parent_msg.message().as_string()
|
||||
|
||||
|
@ -466,7 +553,10 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
|
|||
self.assertIn(str('Child Subject'), parent_s)
|
||||
|
||||
# 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_s = parent_msg.message().as_string()
|
||||
|
||||
|
@ -769,7 +859,10 @@ class LocmemBackendTests(BaseEmailBackendTests, SimpleTestCase):
|
|||
"""
|
||||
connection = 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])
|
||||
connection2.send_messages([email])
|
||||
self.assertEqual(len(mail.outbox), 2)
|
||||
|
@ -808,7 +901,10 @@ class FileBackendTests(BaseEmailBackendTests, SimpleTestCase):
|
|||
|
||||
def test_file_sessions(self):
|
||||
"""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.send_messages([msg])
|
||||
|
||||
|
|
|
@ -485,10 +485,12 @@ class ManyToOneTests(TestCase):
|
|||
expected_message % ', '.join(sorted(f.name for f in Reporter._meta.get_fields())),
|
||||
Article.objects.values_list,
|
||||
'reporter__notafield')
|
||||
self.assertRaisesMessage(FieldError,
|
||||
expected_message % ', '.join(['EXTRA'] + sorted(f.name for f in Article._meta.get_fields())),
|
||||
Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list,
|
||||
'notafield')
|
||||
self.assertRaisesMessage(
|
||||
FieldError,
|
||||
expected_message % ', '.join(['EXTRA'] + sorted(f.name for f in Article._meta.get_fields())),
|
||||
Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list,
|
||||
'notafield'
|
||||
)
|
||||
|
||||
def test_fk_assignment_and_related_object_cache(self):
|
||||
# Tests of ForeignKey assignment and the related-object cache (see #6886).
|
||||
|
|
|
@ -395,10 +395,13 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
|
|||
self._add_middleware(post_middleware)
|
||||
self._add_middleware(middleware)
|
||||
self._add_middleware(pre_middleware)
|
||||
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead.",
|
||||
],
|
||||
ValueError())
|
||||
self.assert_exceptions_handled(
|
||||
'/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return "
|
||||
"an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError()
|
||||
)
|
||||
|
||||
# Check that the right middleware methods have been invoked
|
||||
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(middleware)
|
||||
self._add_middleware(pre_middleware)
|
||||
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError())
|
||||
self.assert_exceptions_handled(
|
||||
'/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return "
|
||||
"an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError()
|
||||
)
|
||||
|
||||
# Check that the right middleware methods have been invoked
|
||||
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(bad_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
|
||||
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(bad_middleware)
|
||||
self._add_middleware(pre_middleware)
|
||||
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead.",
|
||||
'Test Response Exception'
|
||||
])
|
||||
self.assert_exceptions_handled(
|
||||
'/middleware_exceptions/null_view/', [
|
||||
"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
|
||||
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(bad_middleware)
|
||||
self._add_middleware(pre_middleware)
|
||||
self.assert_exceptions_handled('/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError())
|
||||
self.assert_exceptions_handled(
|
||||
'/middleware_exceptions/null_view/', [
|
||||
"The view middleware_exceptions.views.null_view didn't return "
|
||||
"an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError()
|
||||
)
|
||||
|
||||
# Check that the right middleware methods have been invoked
|
||||
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(middleware)
|
||||
self._add_middleware(pre_middleware)
|
||||
self.assert_exceptions_handled('/middleware_exceptions/template_response/', [
|
||||
"NoTemplateResponseMiddleware.process_template_response didn't return an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError())
|
||||
self.assert_exceptions_handled(
|
||||
'/middleware_exceptions/template_response/', [
|
||||
"NoTemplateResponseMiddleware.process_template_response didn't "
|
||||
"return an HttpResponse object. It returned None instead."
|
||||
],
|
||||
ValueError()
|
||||
)
|
||||
|
||||
# Check that the right middleware methods have been invoked
|
||||
self.assert_middleware_usage(pre_middleware, True, True, False, True, False)
|
||||
|
|
|
@ -1337,7 +1337,10 @@ class AutodetectorTests(TestCase):
|
|||
self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
|
||||
self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user')
|
||||
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')
|
||||
|
||||
def test_add_field_with_default(self):
|
||||
|
|
|
@ -505,8 +505,10 @@ class MakeMigrationsTests(MigrationTestBase):
|
|||
self.assertIn('ÚÑÍ¢ÓÐÉ', content) # title.verbose_name
|
||||
self.assertIn('“Ðjáñgó”', content) # title.default
|
||||
else:
|
||||
self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8', content) # Meta.verbose_name
|
||||
self.assertIn('\\xfa\\xf1\\xed\\xa9\\xf3\\xf0\\xe9 \\xb5\\xf3\\xf0\\xe9\\xf8\\xdf', content) # Meta.verbose_name_plural
|
||||
# Meta.verbose_name
|
||||
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('\\u201c\\xd0j\\xe1\\xf1g\\xf3\\u201d', content) # title.default
|
||||
|
||||
|
@ -878,7 +880,8 @@ class MakeMigrationsTests(MigrationTestBase):
|
|||
app_label = "migrations"
|
||||
|
||||
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)
|
||||
|
||||
# Migrations file is actually created in the expected path.
|
||||
|
|
|
@ -47,7 +47,10 @@ class GraphTests(SimpleTestCase):
|
|||
# Test whole graph
|
||||
self.assertEqual(
|
||||
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
|
||||
self.assertEqual(
|
||||
|
@ -101,12 +104,19 @@ class GraphTests(SimpleTestCase):
|
|||
# Test whole graph
|
||||
self.assertEqual(
|
||||
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
|
||||
self.assertEqual(
|
||||
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
|
||||
self.assertEqual(
|
||||
|
|
|
@ -517,7 +517,10 @@ class OperationTests(OperationTestBase):
|
|||
self.assertNotIn(("test_rmwsrf", "rider"), new_state.models)
|
||||
self.assertIn(("test_rmwsrf", "horserider"), new_state.models)
|
||||
# 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
|
||||
self.assertTableExists("test_rmwsrf_rider")
|
||||
self.assertTableNotExists("test_rmwsrf_horserider")
|
||||
|
@ -889,7 +892,9 @@ class OperationTests(OperationTestBase):
|
|||
self.assertFalse(Pony._meta.get_field('stables').blank)
|
||||
|
||||
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")
|
||||
self.assertTrue(Pony._meta.get_field('stables').blank)
|
||||
|
@ -939,7 +944,10 @@ class OperationTests(OperationTestBase):
|
|||
("pony", models.ForeignKey('test_rmflmmwt.Pony', 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")
|
||||
|
||||
|
@ -1323,8 +1331,13 @@ class OperationTests(OperationTestBase):
|
|||
self.assertEqual(operation.describe(), "Set order_with_respect_to on Rider to pony")
|
||||
new_state = project_state.clone()
|
||||
operation.state_forwards("test_alorwrtto", new_state)
|
||||
self.assertEqual(project_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), None)
|
||||
self.assertEqual(new_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), "pony")
|
||||
self.assertIsNone(
|
||||
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
|
||||
self.assertColumnNotExists("test_alorwrtto_rider", "_order")
|
||||
# Create some rows before alteration
|
||||
|
|
|
@ -25,9 +25,13 @@ class OptimizerTests(SimpleTestCase):
|
|||
expected = [repr(f.deconstruct()) for f in expected]
|
||||
self.assertEqual(expected, result)
|
||||
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:
|
||||
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):
|
||||
self.assertOptimizesTo(operations, operations)
|
||||
|
@ -280,12 +284,16 @@ class OptimizerTests(SimpleTestCase):
|
|||
[
|
||||
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
||||
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("LinkThrough", []),
|
||||
migrations.AddField("Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")),
|
||||
migrations.AddField(
|
||||
"Foo", "link", models.ManyToManyField("migrations.Link", through="migrations.LinkThrough")
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -122,7 +122,10 @@ class StateTests(SimpleTestCase):
|
|||
self.assertEqual(author_state.fields[1][1].max_length, 255)
|
||||
self.assertEqual(author_state.fields[2][1].null, False)
|
||||
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(book_state.app_label, "migrations")
|
||||
|
|
|
@ -441,7 +441,9 @@ class WriterTests(SimpleTestCase):
|
|||
"operations": [
|
||||
migrations.CreateModel("MyModel", tuple(fields.items()), options, (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.AddField("OtherModel", "datetimefield", fields["datetimefield"]),
|
||||
],
|
||||
|
|
|
@ -86,7 +86,10 @@ class TestQuerying(TestCase):
|
|||
|
||||
|
||||
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):
|
||||
instance = UUIDModel(field=uuid.UUID('550e8400e29b41d4a716446655440000'))
|
||||
|
|
|
@ -494,9 +494,12 @@ class ModelFormBaseTest(TestCase):
|
|||
|
||||
self.assertHTMLEqual(
|
||||
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_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>"""
|
||||
"""<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_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):
|
||||
|
@ -509,8 +512,10 @@ class ModelFormBaseTest(TestCase):
|
|||
['url', 'name'])
|
||||
self.assertHTMLEqual(
|
||||
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_name">Name:</label></th><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_name">Name:</label></th>
|
||||
<td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>"""
|
||||
)
|
||||
|
||||
def test_orderfields2_form(self):
|
||||
|
@ -894,7 +899,10 @@ class UniqueTest(TestCase):
|
|||
class Meta(PostForm.Meta):
|
||||
error_messages = {
|
||||
'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()
|
||||
self.assertHTMLEqual(
|
||||
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_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>"""
|
||||
"""<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_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(
|
||||
str(f.as_ul()),
|
||||
|
@ -1025,7 +1036,9 @@ class ModelFormBasicTests(TestCase):
|
|||
'headline': 'Your headline here',
|
||||
'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>Pub date: <input type="text" name="pub_date" /></li>
|
||||
<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
|
||||
# inserted as 'initial' data in each Field.
|
||||
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(
|
||||
headline='Test article',
|
||||
|
@ -1061,7 +1078,9 @@ class ModelFormBasicTests(TestCase):
|
|||
art_id_1 = art.id
|
||||
|
||||
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>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
|
||||
<li>Writer: <select name="writer">
|
||||
|
@ -1113,8 +1132,12 @@ class ModelFormBasicTests(TestCase):
|
|||
ModelForm = modelform_factory(Article, fields=['headline', 'categories'],
|
||||
formfield_callback=formfield_for_dbfield)
|
||||
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>
|
||||
<li><label for="id_categories">Categories:</label> <select multiple="multiple" name="categories" id="id_categories">
|
||||
self.assertHTMLEqual(
|
||||
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">It&39;s a 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.
|
||||
f = BaseCategoryForm({'name': '', 'slug': 'not a slug!', 'url': 'foo'})
|
||||
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'})
|
||||
with self.assertRaises(ValueError):
|
||||
f.save()
|
||||
|
@ -1168,7 +1194,9 @@ class ModelFormBasicTests(TestCase):
|
|||
# ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
|
||||
# fields with the 'choices' attribute are represented by a ChoiceField.
|
||||
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>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
|
||||
<tr><th>Writer:</th><td><select name="writer">
|
||||
|
@ -1196,7 +1224,9 @@ class ModelFormBasicTests(TestCase):
|
|||
new_art.categories.add(Category.objects.get(name='Entertainment'))
|
||||
self.assertQuerysetEqual(new_art.categories.all(), ["Entertainment"])
|
||||
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>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
|
||||
<li>Writer: <select name="writer">
|
||||
|
@ -1230,7 +1260,9 @@ class ModelFormBasicTests(TestCase):
|
|||
fields = ('headline', 'pub_date')
|
||||
|
||||
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>''')
|
||||
|
||||
# You can create a form over a subset of the available fields
|
||||
|
@ -1249,9 +1281,12 @@ class ModelFormBasicTests(TestCase):
|
|||
'slug': 'new-headline',
|
||||
'pub_date': '1988-01-04'
|
||||
}, 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>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())
|
||||
new_art = f.save()
|
||||
self.assertEqual(new_art.id, art.id)
|
||||
|
@ -1337,7 +1372,9 @@ class ModelFormBasicTests(TestCase):
|
|||
# the data in the database when the form is instantiated.
|
||||
self.create_basic_data()
|
||||
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>Pub date: <input type="text" name="pub_date" /></li>
|
||||
<li>Writer: <select name="writer">
|
||||
|
@ -1360,7 +1397,9 @@ class ModelFormBasicTests(TestCase):
|
|||
|
||||
c4 = Category.objects.create(name='Fourth', url='4th')
|
||||
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>Pub date: <input type="text" name="pub_date" /></li>
|
||||
<li>Writer: <select name="writer">
|
||||
|
@ -1714,12 +1753,17 @@ class ModelOneToOneFieldTests(TestCase):
|
|||
self.w_woodward = Writer.objects.create(name='Bob Woodward')
|
||||
|
||||
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="%s">Bob Woodward</option>
|
||||
<option value="%s">Mike Royko</option>
|
||||
</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 = {
|
||||
'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')
|
||||
|
||||
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="%s" selected="selected">Bob Woodward</option>
|
||||
<option value="%s">Mike Royko</option>
|
||||
</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):
|
||||
class AuthorForm(forms.ModelForm):
|
||||
|
@ -2082,7 +2131,8 @@ class FileAndImageFieldTests(TestCase):
|
|||
self.assertEqual(instance.width, 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(
|
||||
data={'description': 'New Description'},
|
||||
instance=instance)
|
||||
|
@ -2123,7 +2173,10 @@ class ModelOtherFieldTests(SimpleTestCase):
|
|||
self.assertTrue(bif.is_valid())
|
||||
bif = BigIntForm({'biggie': '-9223372036854775809'})
|
||||
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'})
|
||||
self.assertTrue(bif.is_valid())
|
||||
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
|
||||
# the ModelForm.
|
||||
f = ModelFormWithMedia()
|
||||
self.assertHTMLEqual(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>''')
|
||||
self.assertHTMLEqual(
|
||||
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):
|
||||
# Choices on CharField and IntegerField
|
||||
|
@ -2251,8 +2307,13 @@ class OtherModelFormTests(TestCase):
|
|||
self.assertEqual(list(CategoryForm.base_fields),
|
||||
['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>
|
||||
<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(
|
||||
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 ##################
|
||||
|
||||
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):
|
||||
self.assertEqual(list(CustomFieldForExclusionForm.base_fields),
|
||||
['name'])
|
||||
self.assertHTMLEqual(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>''')
|
||||
self.assertHTMLEqual(
|
||||
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):
|
||||
class ColourfulItemForm(forms.ModelForm):
|
||||
|
@ -2298,19 +2362,20 @@ class OtherModelFormTests(TestCase):
|
|||
today_str = str(datetime.date.today())
|
||||
self.assertHTMLEqual(
|
||||
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>
|
||||
<input id="id_date_published" name="date_published" type="text" value="{0}" />
|
||||
<input id="initial-id_date_published" name="initial-date_published" type="hidden" value="{0}" /></p>
|
||||
<p><label for="id_mode">Mode:</label> <select id="id_mode" name="mode">
|
||||
<option value="di" selected="selected">direct</option>
|
||||
<option value="de">delayed</option></select>
|
||||
<input id="initial-id_mode" name="initial-mode" type="hidden" value="di" /></p>
|
||||
<p><label for="id_category">Category:</label> <select id="id_category" name="category">
|
||||
<option value="1">Games</option>
|
||||
<option value="2">Comics</option>
|
||||
<option value="3" selected="selected">Novel</option></select>
|
||||
<input id="initial-id_category" name="initial-category" type="hidden" value="3" />
|
||||
"""
|
||||
<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>
|
||||
<input id="id_date_published" name="date_published" type="text" value="{0}" />
|
||||
<input id="initial-id_date_published" name="initial-date_published" type="hidden" value="{0}" /></p>
|
||||
<p><label for="id_mode">Mode:</label> <select id="id_mode" name="mode">
|
||||
<option value="di" selected="selected">direct</option>
|
||||
<option value="de">delayed</option></select>
|
||||
<input id="initial-id_mode" name="initial-mode" type="hidden" value="di" /></p>
|
||||
<p><label for="id_category">Category:</label> <select id="id_category" name="category">
|
||||
<option value="1">Games</option>
|
||||
<option value="2">Comics</option>
|
||||
<option value="3" selected="selected">Novel</option></select>
|
||||
<input id="initial-id_category" name="initial-category" type="hidden" value="3" />
|
||||
""".format(today_str)
|
||||
)
|
||||
empty_data = {
|
||||
|
|
|
@ -151,12 +151,24 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorFormSet(queryset=qs)
|
||||
self.assertEqual(len(formset.forms), 3)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>')
|
||||
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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
)
|
||||
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 = {
|
||||
'form-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -189,12 +201,24 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorFormSet(queryset=qs)
|
||||
self.assertEqual(len(formset.forms), 3)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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)
|
||||
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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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
|
||||
)
|
||||
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 = {
|
||||
'form-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -227,18 +251,41 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorFormSet(queryset=qs)
|
||||
self.assertEqual(len(formset.forms), 4)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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'
|
||||
'<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)
|
||||
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" /></p>\n'
|
||||
'<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>\n'
|
||||
'<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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
'<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
|
||||
)
|
||||
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" /></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 = {
|
||||
'form-TOTAL_FORMS': '4', # the number of forms rendered
|
||||
|
@ -480,9 +527,14 @@ class ModelFormsetTest(TestCase):
|
|||
BetterAuthorFormSet = modelformset_factory(BetterAuthor, fields="__all__")
|
||||
formset = BetterAuthorFormSet()
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_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 = {
|
||||
'form-TOTAL_FORMS': '1', # the number of forms rendered
|
||||
|
@ -503,12 +555,22 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = BetterAuthorFormSet()
|
||||
self.assertEqual(len(formset.forms), 2)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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'
|
||||
'<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)
|
||||
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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
'<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
|
||||
)
|
||||
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 = {
|
||||
'form-TOTAL_FORMS': '2', # the number of forms rendered
|
||||
|
@ -535,12 +597,27 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorBooksFormSet(instance=author)
|
||||
self.assertEqual(len(formset.forms), 3)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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)
|
||||
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)
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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
|
||||
)
|
||||
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 = {
|
||||
'book_set-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -569,12 +646,30 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorBooksFormSet(instance=author)
|
||||
self.assertEqual(len(formset.forms), 3)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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))
|
||||
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)
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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,
|
||||
)
|
||||
)
|
||||
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 = {
|
||||
'book_set-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -633,24 +728,45 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorBooksFormSet(prefix="test")
|
||||
self.assertEqual(len(formset.forms), 2)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>')
|
||||
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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
)
|
||||
|
||||
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):
|
||||
# Test inline formsets where the inline-edited object has a custom
|
||||
# primary key that is not the fk to the parent object.
|
||||
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')
|
||||
|
||||
formset = AuthorBooksFormSet2(instance=author)
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_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 = {
|
||||
'bookwithcustompk_set-TOTAL_FORMS': '1', # the number of forms rendered
|
||||
|
@ -680,9 +796,19 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = AuthorBooksFormSet3(instance=author)
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_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 = {
|
||||
'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
|
||||
# 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')
|
||||
|
||||
data = {
|
||||
|
@ -771,16 +899,44 @@ class ModelFormsetTest(TestCase):
|
|||
custom_qs = Book.objects.order_by('-title')
|
||||
formset = AuthorBooksFormSet(instance=author, queryset=custom_qs)
|
||||
self.assertEqual(len(formset.forms), 5)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>')
|
||||
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" 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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
)
|
||||
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" '
|
||||
'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 = {
|
||||
'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')
|
||||
formset = AuthorBooksFormSet(instance=author, queryset=custom_qs)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>')
|
||||
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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
)
|
||||
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 = {
|
||||
'book_set-TOTAL_FORMS': '3', # the number of forms rendered
|
||||
|
@ -863,9 +1035,13 @@ class ModelFormsetTest(TestCase):
|
|||
CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey, fields="__all__")
|
||||
formset = CustomPrimaryKeyFormSet()
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_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 ############
|
||||
|
||||
|
@ -874,10 +1050,20 @@ class ModelFormsetTest(TestCase):
|
|||
FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False, fields="__all__")
|
||||
formset = FormSet(instance=place)
|
||||
self.assertEqual(len(formset.forms), 2)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>')
|
||||
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[0].as_p(),
|
||||
'<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>'
|
||||
)
|
||||
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 = {
|
||||
'owner_set-TOTAL_FORMS': '2',
|
||||
|
@ -898,13 +1084,28 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = FormSet(instance=place)
|
||||
self.assertEqual(len(formset.forms), 3)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
% 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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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>'
|
||||
% 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 = {
|
||||
'owner_set-TOTAL_FORMS': '3',
|
||||
|
@ -929,14 +1130,18 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
FormSet = modelformset_factory(OwnerProfile, fields="__all__")
|
||||
formset = FormSet()
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<p><label for="id_form-0-owner">Owner:</label> <select name="form-0-owner" id="id_form-0-owner">\n'
|
||||
'<option value="" selected="selected">---------</option>\n'
|
||||
'<option value="%d">Joe Perry at Giordanos</option>\n'
|
||||
'<option value="%d">Jack Berry at Giordanos</option>\n'
|
||||
'</select></p>\n'
|
||||
'<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))
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<p><label for="id_form-0-owner">Owner:</label>'
|
||||
'<select name="form-0-owner" id="id_form-0-owner">'
|
||||
'<option value="" selected="selected">---------</option>'
|
||||
'<option value="%d">Joe Perry at Giordanos</option>'
|
||||
'<option value="%d">Jack Berry at Giordanos</option>'
|
||||
'</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')
|
||||
FormSet = inlineformset_factory(Owner, OwnerProfile, max_num=1, can_delete=False, fields="__all__")
|
||||
|
@ -944,9 +1149,13 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = FormSet(instance=owner1)
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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)
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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 = {
|
||||
'ownerprofile-TOTAL_FORMS': '1',
|
||||
|
@ -965,9 +1174,13 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = FormSet(instance=owner1)
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_p(),
|
||||
'<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)
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_p(),
|
||||
'<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 = {
|
||||
'ownerprofile-TOTAL_FORMS': '1',
|
||||
|
@ -994,9 +1207,15 @@ class ModelFormsetTest(TestCase):
|
|||
|
||||
formset = FormSet(instance=place)
|
||||
self.assertEqual(len(formset.forms), 1)
|
||||
self.assertHTMLEqual(formset.forms[0].as_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>\n'
|
||||
'<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>')
|
||||
self.assertHTMLEqual(
|
||||
formset.forms[0].as_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):
|
||||
self.assertEqual(type(_get_foreign_key(Restaurant, Owner)), models.ForeignKey)
|
||||
|
@ -1147,9 +1366,17 @@ class ModelFormsetTest(TestCase):
|
|||
now = form.fields['date_joined'].initial()
|
||||
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)
|
||||
self.assertHTMLEqual(result,
|
||||
'<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'
|
||||
'<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>'
|
||||
self.assertHTMLEqual(
|
||||
result,
|
||||
'<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)
|
||||
|
||||
# test for validation with callable defaults. Validations rely on hidden fields
|
||||
|
@ -1192,7 +1419,14 @@ class ModelFormsetTest(TestCase):
|
|||
super(MembershipForm, self).__init__(**kwargs)
|
||||
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 = {
|
||||
'membership_set-TOTAL_FORMS': '1',
|
||||
'membership_set-INITIAL_FORMS': '0',
|
||||
|
|
|
@ -202,7 +202,10 @@ class InlineFormsetTests(TestCase):
|
|||
FormSet(instance=None)
|
||||
|
||||
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=())
|
||||
formset = UserFormSet()
|
||||
for form in formset.forms:
|
||||
|
|
|
@ -248,13 +248,12 @@ class RelationTreeTests(SimpleTestCase):
|
|||
self.assertEqual(
|
||||
sorted([field.related_query_name() for field in BasePerson._meta._relation_tree]),
|
||||
sorted([
|
||||
'+', '_relating_basepeople_hidden_+', 'BasePerson_following_abstract+', 'BasePerson_following_abstract+',
|
||||
'BasePerson_following_base+', 'BasePerson_following_base+', 'BasePerson_friends_abstract+',
|
||||
'BasePerson_friends_abstract+', 'BasePerson_friends_base+', 'BasePerson_friends_base+',
|
||||
'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
||||
'Relating_basepeople_hidden+', 'followers_abstract',
|
||||
'followers_base', 'friends_abstract_rel_+', 'friends_base_rel_+',
|
||||
'person', 'relating_basepeople', 'relating_baseperson',
|
||||
'+', '_relating_basepeople_hidden_+', 'BasePerson_following_abstract+',
|
||||
'BasePerson_following_abstract+', 'BasePerson_following_base+', 'BasePerson_following_base+',
|
||||
'BasePerson_friends_abstract+', 'BasePerson_friends_abstract+', 'BasePerson_friends_base+',
|
||||
'BasePerson_friends_base+', 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
||||
'Relating_basepeople_hidden+', 'followers_abstract', 'followers_base', 'friends_abstract_rel_+',
|
||||
'friends_base_rel_+', 'person', 'relating_basepeople', 'relating_baseperson',
|
||||
])
|
||||
)
|
||||
self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], [])
|
||||
|
|
|
@ -37,7 +37,8 @@ class ValidationTestModel(models.Model):
|
|||
is_active = models.BooleanField(default=False)
|
||||
pub_date = models.DateTimeField()
|
||||
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):
|
||||
return self.pub_date.strftime('%Y')[:3] + "0's"
|
||||
|
|
|
@ -1029,9 +1029,11 @@ class ListDisplayLinksCheckTests(CheckTestCase):
|
|||
list_display_links = ('non_existent_field',)
|
||||
|
||||
self.assertIsInvalid(
|
||||
ValidationTestModelAdmin, ValidationTestModel,
|
||||
"The value of 'list_display_links[0]' refers to 'non_existent_field', which is not defined in 'list_display'.",
|
||||
'admin.E111')
|
||||
ValidationTestModelAdmin, ValidationTestModel, (
|
||||
"The value of 'list_display_links[0]' refers to "
|
||||
"'non_existent_field', which is not defined in 'list_display'."
|
||||
), 'admin.E111'
|
||||
)
|
||||
|
||||
def test_missing_in_list_display(self):
|
||||
class ValidationTestModelAdmin(ModelAdmin):
|
||||
|
@ -1244,9 +1246,10 @@ class OrderingCheckTests(CheckTestCase):
|
|||
|
||||
self.assertIsInvalid(
|
||||
ValidationTestModelAdmin,
|
||||
ValidationTestModel,
|
||||
"The value of 'ordering[0]' refers to 'non_existent_field', which is not an attribute of 'modeladmin.ValidationTestModel'.",
|
||||
'admin.E033',
|
||||
ValidationTestModel, (
|
||||
"The value of 'ordering[0]' refers to 'non_existent_field', "
|
||||
"which is not an attribute of 'modeladmin.ValidationTestModel'."
|
||||
), 'admin.E033'
|
||||
)
|
||||
|
||||
def test_random_marker_not_alone(self):
|
||||
|
|
|
@ -188,15 +188,23 @@ class QueryTestCase(TestCase):
|
|||
self.assertEqual(Book.authors.through.objects.using('other').count(), 1)
|
||||
|
||||
# Check that queries work across m2m joins
|
||||
self.assertEqual(list(Book.objects.using('default').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='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('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
|
||||
['Dive into Python'])
|
||||
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']
|
||||
)
|
||||
|
||||
# Reget the objects to clear caches
|
||||
dive = Book.objects.using('other').get(title="Dive into Python")
|
||||
|
@ -222,35 +230,53 @@ class QueryTestCase(TestCase):
|
|||
|
||||
# Add a second author
|
||||
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)
|
||||
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='John Smith').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']
|
||||
)
|
||||
self.assertEqual(
|
||||
list(Book.objects.using('other').filter(authors__name='John Smith').values_list('title', flat=True)),
|
||||
['Dive into Python']
|
||||
)
|
||||
|
||||
# Remove the second author
|
||||
dive.authors.remove(john)
|
||||
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='John Smith').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='John Smith').values_list('title', flat=True)),
|
||||
[]
|
||||
)
|
||||
|
||||
# Clear all authors
|
||||
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='John Smith').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)),
|
||||
[]
|
||||
)
|
||||
|
||||
# Create an author through the m2m interface
|
||||
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='Jane Brown').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)),
|
||||
[]
|
||||
)
|
||||
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):
|
||||
"M2M reverse manipulations are all constrained to a single DB"
|
||||
|
@ -269,31 +295,53 @@ class QueryTestCase(TestCase):
|
|||
|
||||
# Add a books to the m2m
|
||||
mark.book_set.add(grease)
|
||||
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
|
||||
['Mark Pilgrim'])
|
||||
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='Dive into Python').values_list('name', flat=True)),
|
||||
['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
|
||||
mark.book_set.remove(grease)
|
||||
self.assertEqual(list(Person.objects.using('other').filter(book__title='Dive into Python').values_list('name', flat=True)),
|
||||
['Mark Pilgrim'])
|
||||
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='Dive into Python').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
|
||||
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='Greasemonkey Hacks').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)
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
# Create a book through the m2m interface
|
||||
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 HTML5').values_list('name', flat=True)),
|
||||
['Mark Pilgrim'])
|
||||
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']
|
||||
)
|
||||
|
||||
def test_m2m_cross_database_protection(self):
|
||||
"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")
|
||||
|
||||
# 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)),
|
||||
['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='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(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)),
|
||||
['Chris Mills'])
|
||||
self.assertEqual(
|
||||
list(
|
||||
Person.objects.using('default').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)
|
||||
),
|
||||
['Chris Mills']
|
||||
)
|
||||
|
||||
# Reget the objects to clear caches
|
||||
chris = Person.objects.using('other').get(name="Chris Mills")
|
||||
|
@ -452,37 +512,65 @@ class QueryTestCase(TestCase):
|
|||
|
||||
# Add a second book edited by chris
|
||||
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)
|
||||
self.assertEqual(list(Person.objects.using('other').filter(edited__title='Dive into HTML5').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'])
|
||||
self.assertEqual(
|
||||
list(Person.objects.using('other').filter(edited__title='Dive into HTML5').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']
|
||||
)
|
||||
|
||||
# Remove the second editor
|
||||
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 Python').values_list('name', flat=True)),
|
||||
['Chris Mills'])
|
||||
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']
|
||||
)
|
||||
|
||||
# Clear all edited books
|
||||
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 Python').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)
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
# Create an author through the m2m interface
|
||||
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 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 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)
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
def test_foreign_key_cross_database_protection(self):
|
||||
"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")
|
||||
|
||||
# Check that queries work across joins
|
||||
self.assertEqual(list(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='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(User.objects.using('other').filter(userprofile__flavor='crunchy frog').values_list('username', flat=True)),
|
||||
['bob'])
|
||||
self.assertEqual(
|
||||
list(
|
||||
User.objects.using('default')
|
||||
.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
|
||||
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)
|
||||
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('other').filter(object_id=dive.pk).values_list('source', flat=True)),
|
||||
['Python Weekly'])
|
||||
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']
|
||||
)
|
||||
|
||||
# Add a second review
|
||||
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('other').filter(object_id=dive.pk).values_list('source', flat=True)),
|
||||
['Python Monthly', 'Python Weekly'])
|
||||
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']
|
||||
)
|
||||
|
||||
# Remove the second author
|
||||
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('other').filter(object_id=dive.pk).values_list('source', flat=True)),
|
||||
['Python Monthly'])
|
||||
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']
|
||||
)
|
||||
|
||||
# Clear all reviews
|
||||
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('other').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)),
|
||||
[]
|
||||
)
|
||||
|
||||
# Create an author through the generic interface
|
||||
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('other').filter(object_id=dive.pk).values_list('source', flat=True)),
|
||||
['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('other').filter(object_id=dive.pk).values_list('source', flat=True)),
|
||||
['Python Daily']
|
||||
)
|
||||
|
||||
def test_generic_key_cross_database_protection(self):
|
||||
"Operations that involve sharing generic key objects across databases raise an error"
|
||||
|
@ -750,17 +878,25 @@ class QueryTestCase(TestCase):
|
|||
review3.content_object = dive
|
||||
self.assertEqual(review3._state.db, 'other')
|
||||
# ... but it isn't saved yet
|
||||
self.assertEqual(list(Review.objects.using('default').filter(object_id=pro.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 Weekly'])
|
||||
self.assertEqual(
|
||||
list(Review.objects.using('default').filter(object_id=pro.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 Weekly']
|
||||
)
|
||||
|
||||
# When saved, John goes to 'other'
|
||||
review3.save()
|
||||
self.assertEqual(list(Review.objects.using('default').filter(object_id=pro.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 Daily', 'Python Weekly'])
|
||||
self.assertEqual(
|
||||
list(Review.objects.using('default').filter(object_id=pro.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 Daily', 'Python Weekly']
|
||||
)
|
||||
|
||||
def test_generic_key_deletion(self):
|
||||
"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')
|
||||
|
||||
# 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')
|
||||
|
||||
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()])
|
||||
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()
|
||||
management.call_command('loaddata', 'pets', stdout=new_io, stderr=new_io)
|
||||
command_output = new_io.getvalue().strip()
|
||||
|
|
|
@ -140,7 +140,10 @@ class DeeplyNestedForeignKeysTests(TestCase):
|
|||
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__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__name')), 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('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__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__name')), 2)
|
||||
self.assertEqual(len(Package.objects.values('screening__movie__title', 'screening__movie__director__pk')), 2)
|
||||
|
|
|
@ -24,7 +24,10 @@ class OrLookupsTests(TestCase):
|
|||
|
||||
def test_filter_or(self):
|
||||
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',
|
||||
'Goodbye',
|
||||
'Hello and goodbye'
|
||||
|
|
|
@ -15,7 +15,9 @@ class Migration(migrations.Migration):
|
|||
name='CharTextArrayIndexModel',
|
||||
fields=[
|
||||
('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)),
|
||||
('text', django.contrib.postgres.fields.ArrayField(models.TextField(), db_index=True)),
|
||||
],
|
||||
|
|
|
@ -341,7 +341,9 @@ class TestMigrations(TransactionTestCase):
|
|||
|
||||
|
||||
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):
|
||||
instance = IntegerArrayModel(field=[1, 2])
|
||||
|
@ -360,7 +362,10 @@ class TestValidation(PostgreSQLTestCase):
|
|||
with self.assertRaises(exceptions.ValidationError) as cm:
|
||||
field.clean([1, None], None)
|
||||
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):
|
||||
field = ArrayField(models.IntegerField(blank=True, null=True))
|
||||
|
@ -388,7 +393,10 @@ class TestValidation(PostgreSQLTestCase):
|
|||
with self.assertRaises(exceptions.ValidationError) as cm:
|
||||
field.clean([0], None)
|
||||
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):
|
||||
|
|
|
@ -627,5 +627,6 @@ class TestWidget(PostgreSQLTestCase):
|
|||
)
|
||||
self.assertHTMLEqual(
|
||||
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" />'
|
||||
)
|
||||
|
|
|
@ -313,7 +313,10 @@ class CustomPrefetchTests(TestCase):
|
|||
# Ambiguous: Lookup houses_lst doesn't yet exist when performing houses_lst__rooms.
|
||||
with self.assertRaises(AttributeError):
|
||||
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']]
|
||||
)
|
||||
|
||||
|
@ -324,7 +327,10 @@ class CustomPrefetchTests(TestCase):
|
|||
)
|
||||
|
||||
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']]
|
||||
)
|
||||
|
||||
|
@ -537,8 +543,15 @@ class CustomPrefetchTests(TestCase):
|
|||
|
||||
# Test queryset filtering.
|
||||
with self.assertNumQueries(2):
|
||||
lst2 = list(Person.objects.prefetch_related(
|
||||
Prefetch('houses', queryset=House.objects.filter(pk__in=[self.house1.pk, self.house3.pk]), to_attr='houses_lst')))
|
||||
lst2 = list(
|
||||
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(lst2[0].houses_lst[0], self.house1)
|
||||
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'))
|
||||
lst2 = self.traverse_qs(rooms, [['house_attr', 'owner']])
|
||||
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):
|
||||
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)
|
||||
rooms = Room.objects.all().prefetch_related(Prefetch('house', queryset=House.objects.only('name')))
|
||||
with self.assertNumQueries(2):
|
||||
|
@ -617,13 +634,21 @@ class CustomPrefetchTests(TestCase):
|
|||
lst2 = self.traverse_qs(rooms, [['main_room_of', 'owner']])
|
||||
self.assertEqual(lst1, lst2)
|
||||
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']])
|
||||
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):
|
||||
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)
|
||||
|
||||
def test_nested_prefetch_related_are_not_overwritten(self):
|
||||
|
|
|
@ -227,11 +227,25 @@ class Queries1Tests(BaseQuerysetTest):
|
|||
4
|
||||
)
|
||||
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
|
||||
)
|
||||
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
|
||||
)
|
||||
xx.delete()
|
||||
|
@ -355,7 +369,10 @@ class Queries1Tests(BaseQuerysetTest):
|
|||
# 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))
|
||||
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
|
||||
)
|
||||
|
||||
|
@ -568,7 +585,13 @@ class Queries1Tests(BaseQuerysetTest):
|
|||
self.assertEqual(d, {'a': 'one', 'b': 'two'})
|
||||
|
||||
# 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])
|
||||
|
||||
def test_ticket6154(self):
|
||||
|
@ -704,7 +727,9 @@ class Queries1Tests(BaseQuerysetTest):
|
|||
|
||||
def test_ticket7277(self):
|
||||
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>']
|
||||
)
|
||||
|
||||
|
@ -1376,12 +1401,19 @@ class Queries4Tests(BaseQuerysetTest):
|
|||
self.assertEqual(str(q1.query), str(q2.query))
|
||||
|
||||
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.assertEqual(str(q1.query), str(q2.query))
|
||||
|
||||
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.assertEqual(str(q1.query), str(q2.query))
|
||||
|
||||
|
@ -2621,7 +2653,10 @@ class DefaultValuesInsertTest(TestCase):
|
|||
try:
|
||||
DumbCategory.objects.create()
|
||||
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):
|
||||
|
@ -3524,7 +3559,10 @@ class RelatedLookupTypeTests(TestCase):
|
|||
# child objects
|
||||
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=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
|
||||
self.assertQuerysetEqual(ObjectC.objects.exclude(childobjecta=self.oa), out_c)
|
||||
|
|
|
@ -16,10 +16,26 @@ class RawQueryTests(TestCase):
|
|||
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.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.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.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.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.c2 = Coffee.objects.create(brand='starbucks')
|
||||
cls.r1 = Reviewer.objects.create()
|
||||
|
@ -211,7 +227,12 @@ class RawQueryTests(TestCase):
|
|||
pass
|
||||
|
||||
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 = (
|
||||
('book_count', 3),
|
||||
('book_count', 0),
|
||||
|
|
|
@ -88,10 +88,20 @@ class RequestsTests(SimpleTestCase):
|
|||
Refs #20169.
|
||||
"""
|
||||
# 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/')
|
||||
# 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/')
|
||||
|
||||
def test_wsgirequest_with_force_script_name(self):
|
||||
|
@ -101,7 +111,12 @@ class RequestsTests(SimpleTestCase):
|
|||
Refs #20169.
|
||||
"""
|
||||
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/')
|
||||
|
||||
def test_wsgirequest_path_with_force_script_name_trailing_slash(self):
|
||||
|
|
|
@ -336,7 +336,10 @@ class SchemaTests(TransactionTestCase):
|
|||
columns = self.column_classes(Author)
|
||||
# BooleanField are stored as TINYINT(1) on MySQL.
|
||||
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):
|
||||
"""
|
||||
|
@ -1097,7 +1100,9 @@ class SchemaTests(TransactionTestCase):
|
|||
editor.create_model(TagM2MTest)
|
||||
editor.create_model(UniqueTest)
|
||||
# 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:
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']:
|
||||
|
@ -1113,7 +1118,10 @@ class SchemaTests(TransactionTestCase):
|
|||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(LocalBookWithM2M, old_field, new_field)
|
||||
# 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
|
||||
constraints = self.get_constraints(new_field.remote_field.through._meta.db_table)
|
||||
if connection.features.supports_foreign_keys:
|
||||
|
|
|
@ -53,7 +53,11 @@ class SelectRelatedTests(TestCase):
|
|||
extra queries
|
||||
"""
|
||||
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
|
||||
self.assertEqual(domain.name, 'Eukaryota')
|
||||
|
||||
|
|
|
@ -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],
|
||||
[(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],
|
||||
[(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')])
|
||||
|
||||
|
|
|
@ -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="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field>
|
||||
</object>
|
||||
</django-objects>"""
|
||||
</django-objects>""" # NOQA
|
||||
|
||||
@staticmethod
|
||||
def _comparison_value(value):
|
||||
|
|
|
@ -36,7 +36,10 @@ class SitesFrameworkTestCase(TestCase):
|
|||
self.assertEqual(SyndicatedArticle.on_site.all().get(), article)
|
||||
|
||||
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)
|
||||
|
||||
def test_invalid_name(self):
|
||||
|
|
|
@ -58,7 +58,10 @@ class FeedTestCase(TestCase):
|
|||
elem.getElementsByTagName(k)[0].firstChild.wholeText, v)
|
||||
|
||||
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
|
||||
|
@ -101,7 +104,12 @@ class SyndicationFeedTest(FeedTestCase):
|
|||
d = Entry.objects.latest('published').published
|
||||
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, {
|
||||
'title': 'My blog',
|
||||
'description': 'A more thorough description of my blog.',
|
||||
|
@ -197,7 +205,12 @@ class SyndicationFeedTest(FeedTestCase):
|
|||
chan_elem = feed.getElementsByTagName('channel')
|
||||
self.assertEqual(len(chan_elem), 1)
|
||||
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
|
||||
self.assertChildNodeContent(chan, {
|
||||
|
@ -232,7 +245,10 @@ class SyndicationFeedTest(FeedTestCase):
|
|||
|
||||
self.assertEqual(feed.nodeName, 'feed')
|
||||
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'):
|
||||
if link.getAttribute('rel') == 'self':
|
||||
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.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')
|
||||
self.assertEqual(len(entries), Entry.objects.count())
|
||||
|
|
|
@ -42,7 +42,9 @@ class DateTests(TimezoneTestCase):
|
|||
# Timezone name
|
||||
@setup({'date06': '{{ d|date:"e" }}'})
|
||||
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')
|
||||
|
||||
@setup({'date07': '{{ d|date:"e" }}'})
|
||||
|
|
|
@ -8,10 +8,14 @@ class RandomTests(SimpleTestCase):
|
|||
|
||||
@setup({'random01': '{{ a|random }} {{ b|random }}'})
|
||||
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&b a&b')
|
||||
|
||||
@setup({'random02': '{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}'})
|
||||
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')
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue