diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
index 044e6163ad5..bc4e6871712 100644
--- a/django/contrib/admin/actions.py
+++ b/django/contrib/admin/actions.py
@@ -8,7 +8,6 @@ from django.contrib.admin.utils import get_deleted_objects, model_ngettext
from django.core.exceptions import PermissionDenied
from django.db import router
from django.template.response import TemplateResponse
-from django.utils.encoding import force_text
from django.utils.translation import gettext as _, gettext_lazy
@@ -44,7 +43,7 @@ def delete_selected(modeladmin, request, queryset):
n = queryset.count()
if n:
for obj in queryset:
- obj_display = force_text(obj)
+ obj_display = str(obj)
modeladmin.log_deletion(request, obj, obj_display)
queryset.delete()
modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
@@ -63,7 +62,7 @@ def delete_selected(modeladmin, request, queryset):
context = dict(
modeladmin.admin_site.each_context(request),
title=title,
- objects_name=objects_name,
+ objects_name=str(objects_name),
deletable_objects=[deletable_objects],
model_count=dict(model_count).items(),
queryset=queryset,
diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py
index a15bea94140..9dbd8a8f26d 100644
--- a/django/contrib/admin/filters.py
+++ b/django/contrib/admin/filters.py
@@ -14,7 +14,6 @@ from django.contrib.admin.utils import (
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
from django.utils import timezone
-from django.utils.encoding import force_text
from django.utils.translation import gettext_lazy as _
@@ -107,7 +106,7 @@ class SimpleListFilter(ListFilter):
}
for lookup, title in self.lookup_choices:
yield {
- 'selected': self.value() == force_text(lookup),
+ 'selected': self.value() == str(lookup),
'query_string': changelist.get_query_string({self.parameter_name: lookup}, []),
'display': title,
}
@@ -204,7 +203,7 @@ class RelatedFieldListFilter(FieldListFilter):
}
for pk_val, val in self.lookup_choices:
yield {
- 'selected': self.lookup_val == force_text(pk_val),
+ 'selected': self.lookup_val == str(pk_val),
'query_string': changelist.get_query_string({
self.lookup_kwarg: pk_val,
}, [self.lookup_kwarg_isnull]),
@@ -290,7 +289,7 @@ class ChoicesFieldListFilter(FieldListFilter):
none_title = title
continue
yield {
- 'selected': force_text(lookup) == self.lookup_val,
+ 'selected': str(lookup) == self.lookup_val,
'query_string': changelist.get_query_string(
{self.lookup_kwarg: lookup}, [self.lookup_kwarg_isnull]
),
@@ -415,7 +414,7 @@ class AllValuesFieldListFilter(FieldListFilter):
if val is None:
include_none = True
continue
- val = force_text(val)
+ val = str(val)
yield {
'selected': self.lookup_val == val,
'query_string': changelist.get_query_string({
diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py
index ca4df1d9704..82b3cc0585d 100644
--- a/django/contrib/admin/models.py
+++ b/django/contrib/admin/models.py
@@ -6,7 +6,6 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.urls import NoReverseMatch, reverse
from django.utils import timezone
-from django.utils.encoding import force_text
from django.utils.text import get_text_list
from django.utils.translation import gettext, gettext_lazy as _
@@ -24,7 +23,7 @@ class LogEntryManager(models.Manager):
return self.model.objects.create(
user_id=user_id,
content_type_id=content_type_id,
- object_id=force_text(object_id),
+ object_id=str(object_id),
object_repr=object_repr[:200],
action_flag=action_flag,
change_message=change_message,
@@ -64,7 +63,7 @@ class LogEntry(models.Model):
ordering = ('-action_time',)
def __repr__(self):
- return force_text(self.action_time)
+ return str(self.action_time)
def __str__(self):
if self.is_addition():
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index c3801889f6b..80540aa7e6e 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -38,7 +38,6 @@ from django.http.response import HttpResponseBase
from django.template.response import SimpleTemplateResponse, TemplateResponse
from django.urls import reverse
from django.utils.decorators import method_decorator
-from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.http import urlencode
from django.utils.safestring import mark_safe
@@ -722,7 +721,7 @@ class ModelAdmin(BaseModelAdmin):
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
- object_repr=force_text(object),
+ object_repr=str(object),
action_flag=ADDITION,
change_message=message,
)
@@ -738,7 +737,7 @@ class ModelAdmin(BaseModelAdmin):
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
- object_repr=force_text(object),
+ object_repr=str(object),
action_flag=CHANGE,
change_message=message,
)
@@ -763,7 +762,7 @@ class ModelAdmin(BaseModelAdmin):
"""
A list_display column containing a checkbox widget.
"""
- return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
+ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, str(obj.pk))
action_checkbox.short_description = mark_safe('')
def get_actions(self, request):
@@ -1056,7 +1055,7 @@ class ModelAdmin(BaseModelAdmin):
if self.has_change_permission(request, obj):
obj_repr = format_html('{}', urlquote(obj_url), obj)
else:
- obj_repr = force_text(obj)
+ obj_repr = str(obj)
msg_dict = {
'name': opts.verbose_name,
'obj': obj_repr,
@@ -1652,7 +1651,7 @@ class ModelAdmin(BaseModelAdmin):
context = dict(
self.admin_site.each_context(request),
- module_name=force_text(opts.verbose_name_plural),
+ module_name=str(opts.verbose_name_plural),
selection_note=_('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
selection_note_all=selection_note_all % {'total_count': cl.result_count},
title=cl.title,
@@ -1710,7 +1709,7 @@ class ModelAdmin(BaseModelAdmin):
if request.POST and not protected: # The user has confirmed the deletion.
if perms_needed:
raise PermissionDenied
- obj_display = force_text(obj)
+ obj_display = str(obj)
attr = str(to_field) if to_field else opts.pk.attname
obj_id = obj.serializable_value(attr)
self.log_deletion(request, obj, obj_display)
@@ -1718,7 +1717,7 @@ class ModelAdmin(BaseModelAdmin):
return self.response_delete(request, obj_display, obj_id)
- object_name = force_text(opts.verbose_name)
+ object_name = str(opts.verbose_name)
if perms_needed or protected:
title = _("Cannot delete %(name)s") % {"name": object_name}
@@ -1769,7 +1768,7 @@ class ModelAdmin(BaseModelAdmin):
self.admin_site.each_context(request),
title=_('Change history: %s') % obj,
action_list=action_list,
- module_name=capfirst(force_text(opts.verbose_name_plural)),
+ module_name=str(capfirst(opts.verbose_name_plural)),
object=obj,
opts=opts,
preserved_filters=self.get_preserved_filters(request),
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 6901c4cec9c..75b117f34e0 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -14,7 +14,6 @@ from django.template.loader import get_template
from django.templatetags.static import static
from django.urls import NoReverseMatch
from django.utils import formats
-from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.text import capfirst
@@ -233,7 +232,7 @@ def items_for_result(cl, result, form):
result_repr = display_for_field(value, f, empty_value_display)
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
row_classes.append('nowrap')
- if force_text(result_repr) == '':
+ if str(result_repr) == '':
result_repr = mark_safe(' ')
row_class = mark_safe(' class="%s"' % ' '.join(row_classes))
# If list_display_links not defined, add the link tag to the first field
@@ -277,7 +276,7 @@ def items_for_result(cl, result, form):
field_name == cl.model._meta.pk.name and
form[cl.model._meta.pk.name].is_hidden)):
bf = form[field_name]
- result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
+ result_repr = mark_safe(str(bf.errors) + str(bf))
yield format_html('
{}
', row_class, result_repr)
if form and not form[cl.model._meta.pk.name].is_hidden:
yield format_html('
{}
', form[cl.model._meta.pk.name])
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index 6e59c83548c..05fbcebcb9b 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -11,7 +11,6 @@ from django.db.models.sql.constants import QUERY_TERMS
from django.forms.utils import pretty_name
from django.urls import NoReverseMatch, reverse
from django.utils import formats, timezone
-from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.text import capfirst
from django.utils.translation import ngettext, override as translation_override
@@ -338,7 +337,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
label = field.related_model._meta.verbose_name
except FieldDoesNotExist:
if name == "__str__":
- label = force_text(model._meta.verbose_name)
+ label = str(model._meta.verbose_name)
attr = str
else:
if callable(name):
@@ -427,9 +426,9 @@ def display_for_value(value, empty_value_display, boolean=False):
elif isinstance(value, (int, decimal.Decimal, float)):
return formats.number_format(value)
elif isinstance(value, (list, tuple)):
- return ', '.join(force_text(v) for v in value)
+ return ', '.join(str(v) for v in value)
else:
- return force_text(value)
+ return str(value)
class NotRelationField(Exception):
@@ -512,23 +511,23 @@ def construct_change_message(form, formsets, add):
for added_object in formset.new_objects:
change_message.append({
'added': {
- 'name': force_text(added_object._meta.verbose_name),
- 'object': force_text(added_object),
+ 'name': str(added_object._meta.verbose_name),
+ 'object': str(added_object),
}
})
for changed_object, changed_fields in formset.changed_objects:
change_message.append({
'changed': {
- 'name': force_text(changed_object._meta.verbose_name),
- 'object': force_text(changed_object),
+ 'name': str(changed_object._meta.verbose_name),
+ 'object': str(changed_object),
'fields': changed_fields,
}
})
for deleted_object in formset.deleted_objects:
change_message.append({
'deleted': {
- 'name': force_text(deleted_object._meta.verbose_name),
- 'object': force_text(deleted_object),
+ 'name': str(deleted_object._meta.verbose_name),
+ 'object': str(deleted_object),
}
})
return change_message
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
index f073c56c8df..4b932f2c01f 100644
--- a/django/contrib/admin/widgets.py
+++ b/django/contrib/admin/widgets.py
@@ -7,7 +7,6 @@ from django import forms
from django.db.models.deletion import CASCADE
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch
-from django.utils.encoding import force_text
from django.utils.html import smart_urlquote
from django.utils.safestring import mark_safe
from django.utils.text import Truncator
@@ -215,7 +214,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
return value.split(',')
def format_value(self, value):
- return ','.join(force_text(v) for v in value) if value else ''
+ return ','.join(str(v) for v in value) if value else ''
class RelatedFieldWidgetWrapper(forms.Widget):
diff --git a/django/contrib/auth/mixins.py b/django/contrib/auth/mixins.py
index 0949b539c01..c6011225c4b 100644
--- a/django/contrib/auth/mixins.py
+++ b/django/contrib/auth/mixins.py
@@ -2,7 +2,6 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
-from django.utils.encoding import force_text
class AccessMixin:
@@ -25,7 +24,7 @@ class AccessMixin:
'{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override '
'{0}.get_login_url().'.format(self.__class__.__name__)
)
- return force_text(login_url)
+ return str(login_url)
def get_permission_denied_message(self):
"""
diff --git a/django/contrib/auth/password_validation.py b/django/contrib/auth/password_validation.py
index 926bb69904f..1350dec9c81 100644
--- a/django/contrib/auth/password_validation.py
+++ b/django/contrib/auth/password_validation.py
@@ -8,7 +8,6 @@ from django.conf import settings
from django.core.exceptions import (
FieldDoesNotExist, ImproperlyConfigured, ValidationError,
)
-from django.utils.encoding import force_text
from django.utils.functional import lazy
from django.utils.html import format_html
from django.utils.module_loading import import_string
@@ -145,7 +144,7 @@ class UserAttributeSimilarityValidator:
for value_part in value_parts:
if SequenceMatcher(a=password.lower(), b=value_part.lower()).quick_ratio() >= self.max_similarity:
try:
- verbose_name = force_text(user._meta.get_field(attribute_name).verbose_name)
+ verbose_name = str(user._meta.get_field(attribute_name).verbose_name)
except FieldDoesNotExist:
verbose_name = attribute_name
raise ValidationError(
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index df6113f4625..fc269bbc73e 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -11,7 +11,6 @@ from django.db.models.fields.related import (
lazy_related_operation,
)
from django.db.models.query_utils import PathInfo
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
@@ -398,7 +397,7 @@ class GenericRelation(ForeignObject):
def value_to_string(self, obj):
qs = getattr(obj, self.name).all()
- return force_text([instance._get_pk_val() for instance in qs])
+ return str([instance._get_pk_val() for instance in qs])
def contribute_to_class(self, cls, name, **kwargs):
kwargs['private_only'] = True
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 4b9bcdc3bad..ad2e0bc904b 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -2,7 +2,6 @@ from collections import defaultdict
from django.apps import apps
from django.db import models
-from django.utils.encoding import force_text
from django.utils.translation import gettext_lazy as _
@@ -151,7 +150,7 @@ class ContentType(models.Model):
model = self.model_class()
if not model:
return self.model
- return force_text(model._meta.verbose_name)
+ return str(model._meta.verbose_name)
def model_class(self):
"""Return the model class for this type of content."""
diff --git a/django/contrib/postgres/fields/hstore.py b/django/contrib/postgres/fields/hstore.py
index e0226a8d4ad..82f731f8bfd 100644
--- a/django/contrib/postgres/fields/hstore.py
+++ b/django/contrib/postgres/fields/hstore.py
@@ -4,7 +4,6 @@ from django.contrib.postgres import forms, lookups
from django.contrib.postgres.fields.array import ArrayField
from django.core import exceptions
from django.db.models import Field, TextField, Transform
-from django.utils.encoding import force_text
from django.utils.translation import gettext_lazy as _
__all__ = ['HStoreField']
@@ -57,14 +56,14 @@ class HStoreField(Field):
if isinstance(value, dict):
prep_value = {}
for key, val in value.items():
- key = force_text(key)
+ key = str(key)
if val is not None:
- val = force_text(val)
+ val = str(val)
prep_value[key] = val
value = prep_value
if isinstance(value, list):
- value = [force_text(item) for item in value]
+ value = [str(item) for item in value]
return value
diff --git a/django/contrib/postgres/lookups.py b/django/contrib/postgres/lookups.py
index 8521b26c6e1..afef01ef9e7 100644
--- a/django/contrib/postgres/lookups.py
+++ b/django/contrib/postgres/lookups.py
@@ -1,5 +1,4 @@
from django.db.models import Lookup, Transform
-from django.utils.encoding import force_text
from .search import SearchVector, SearchVectorExact, SearchVectorField
@@ -38,7 +37,7 @@ class HasKeys(PostgresSimpleLookup):
operator = '?&'
def get_prep_lookup(self):
- return [force_text(item) for item in self.rhs]
+ return [str(item) for item in self.rhs]
class HasAnyKeys(HasKeys):
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index a395b589b16..64955b8bb71 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -10,7 +10,7 @@ from django.utils import timezone
from django.utils.crypto import (
constant_time_compare, get_random_string, salted_hmac,
)
-from django.utils.encoding import force_bytes, force_text
+from django.utils.encoding import force_bytes
from django.utils.module_loading import import_string
# session_key should not be case sensitive because some backends can store it
@@ -112,7 +112,7 @@ class SessionBase:
# these happen, just return an empty dictionary (an empty session).
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
- logger.warning(force_text(e))
+ logger.warning(str(e))
return {}
def update(self, dict_):
diff --git a/django/contrib/sessions/backends/cached_db.py b/django/contrib/sessions/backends/cached_db.py
index fd8cc9ebc1b..dc5eb27c3d8 100644
--- a/django/contrib/sessions/backends/cached_db.py
+++ b/django/contrib/sessions/backends/cached_db.py
@@ -9,7 +9,6 @@ from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.core.cache import caches
from django.core.exceptions import SuspiciousOperation
from django.utils import timezone
-from django.utils.encoding import force_text
KEY_PREFIX = "django.contrib.sessions.cached_db"
@@ -49,7 +48,7 @@ class SessionStore(DBStore):
except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
- logger.warning(force_text(e))
+ logger.warning(str(e))
self._session_key = None
data = {}
return data
diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py
index 18691c9a27b..43bfde628c2 100644
--- a/django/contrib/sessions/backends/db.py
+++ b/django/contrib/sessions/backends/db.py
@@ -6,7 +6,6 @@ from django.contrib.sessions.backends.base import (
from django.core.exceptions import SuspiciousOperation
from django.db import DatabaseError, IntegrityError, router, transaction
from django.utils import timezone
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
@@ -38,7 +37,7 @@ class SessionStore(SessionBase):
except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
- logger.warning(force_text(e))
+ logger.warning(str(e))
self._session_key = None
return {}
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index aeec2520fce..818c90e3ba9 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -11,7 +11,6 @@ from django.contrib.sessions.backends.base import (
from django.contrib.sessions.exceptions import InvalidSessionKey
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.utils import timezone
-from django.utils.encoding import force_text
class SessionStore(SessionBase):
@@ -92,7 +91,7 @@ class SessionStore(SessionBase):
except (EOFError, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
- logger.warning(force_text(e))
+ logger.warning(str(e))
self.create()
# Remove expired sessions.
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index 34aa3b7ba66..a8b98c84ae1 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.http import Http404, HttpResponse
from django.template import TemplateDoesNotExist, loader
from django.utils import feedgenerator
-from django.utils.encoding import force_text, iri_to_uri
+from django.utils.encoding import iri_to_uri
from django.utils.html import escape
from django.utils.http import http_date
from django.utils.timezone import get_default_timezone, is_naive, make_aware
@@ -48,10 +48,10 @@ class Feed:
def item_title(self, item):
# Titles should be double escaped by default (see #6533)
- return escape(force_text(item))
+ return escape(str(item))
def item_description(self, item):
- return force_text(item)
+ return str(item)
def item_link(self, item):
try:
@@ -66,9 +66,9 @@ class Feed:
enc_url = self._get_dynamic_attr('item_enclosure_url', item)
if enc_url:
enc = feedgenerator.Enclosure(
- url=force_text(enc_url),
- length=force_text(self._get_dynamic_attr('item_enclosure_length', item)),
- mime_type=force_text(self._get_dynamic_attr('item_enclosure_mime_type', item)),
+ url=str(enc_url),
+ length=str(self._get_dynamic_attr('item_enclosure_length', item)),
+ mime_type=str(self._get_dynamic_attr('item_enclosure_mime_type', item)),
)
return [enc]
return []
diff --git a/django/core/checks/messages.py b/django/core/checks/messages.py
index 62bd909c6f6..aacac632eb4 100644
--- a/django/core/checks/messages.py
+++ b/django/core/checks/messages.py
@@ -1,5 +1,3 @@
-from django.utils.encoding import force_text
-
# Levels
DEBUG = 10
INFO = 20
@@ -35,7 +33,7 @@ class CheckMessage:
# method doesn't return "applabel.modellabel" and cannot be changed.
obj = self.obj._meta.label
else:
- obj = force_text(self.obj)
+ obj = str(self.obj)
id = "(%s) " % self.id if self.id else ""
hint = "\n\tHINT: %s" % self.hint if self.hint else ''
return "%s: %s%s%s" % (obj, id, self.msg, hint)
diff --git a/django/core/exceptions.py b/django/core/exceptions.py
index 983053ca5ba..04ed3bd2051 100644
--- a/django/core/exceptions.py
+++ b/django/core/exceptions.py
@@ -1,7 +1,6 @@
"""
Global Django exception and warning classes.
"""
-from django.utils.encoding import force_text
class FieldDoesNotExist(Exception):
@@ -174,7 +173,7 @@ class ValidationError(Exception):
message = error.message
if error.params:
message %= error.params
- yield force_text(message)
+ yield str(message)
def __str__(self):
if hasattr(self, 'error_dict'):
diff --git a/django/core/handlers/exception.py b/django/core/handlers/exception.py
index 91baa54ef65..be2e4734ee4 100644
--- a/django/core/handlers/exception.py
+++ b/django/core/handlers/exception.py
@@ -11,7 +11,6 @@ from django.core.exceptions import (
from django.http import Http404
from django.http.multipartparser import MultiPartParserError
from django.urls import get_resolver, get_urlconf
-from django.utils.encoding import force_text
from django.views import debug
logger = logging.getLogger('django.request')
@@ -71,7 +70,7 @@ def response_for_exception(request, exc):
# The security logger receives events for all SuspiciousOperations
security_logger = logging.getLogger('django.security.%s' % exc.__class__.__name__)
security_logger.error(
- force_text(exc),
+ str(exc),
extra={'status_code': 400, 'request': request},
)
if settings.DEBUG:
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index 51023768e62..73329449b6d 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -55,7 +55,7 @@ ADDRESS_HEADERS = {
def forbid_multi_line_headers(name, val, encoding):
"""Forbid multi-line headers to prevent header injection."""
encoding = encoding or settings.DEFAULT_CHARSET
- val = force_text(val)
+ val = str(val) # val may be lazy
if '\n' in val or '\r' in val:
raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
try:
@@ -100,7 +100,7 @@ def sanitize_address(addr, encoding):
Format a pair of (name, address) or an email address string.
"""
if not isinstance(addr, tuple):
- addr = parseaddr(force_text(addr))
+ addr = parseaddr(addr)
nm, addr = addr
localpart, domain = None, None
nm = Header(nm, encoding).encode()
@@ -258,11 +258,11 @@ class EmailMessage:
msg = self._create_message(msg)
msg['Subject'] = self.subject
msg['From'] = self.extra_headers.get('From', self.from_email)
- msg['To'] = self.extra_headers.get('To', ', '.join(map(force_text, self.to)))
+ msg['To'] = self.extra_headers.get('To', ', '.join(map(str, self.to)))
if self.cc:
- msg['Cc'] = ', '.join(map(force_text, self.cc))
+ msg['Cc'] = ', '.join(map(str, self.cc))
if self.reply_to:
- msg['Reply-To'] = self.extra_headers.get('Reply-To', ', '.join(map(force_text, self.reply_to)))
+ msg['Reply-To'] = self.extra_headers.get('Reply-To', ', '.join(map(str, self.reply_to)))
# Email header names are case-insensitive (RFC 2045), so we have to
# accommodate that when doing comparisons.
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index cf860d1d24b..23a07ef43a1 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -11,7 +11,6 @@ from django.apps import apps
from django.conf import settings
from django.core.serializers import base
from django.db import DEFAULT_DB_ALIAS, models
-from django.utils.encoding import force_text
from django.utils.xmlutils import (
SimplerXMLGenerator, UnserializableContentError,
)
@@ -48,11 +47,11 @@ class Serializer(base.Serializer):
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
self.indent(1)
- attrs = OrderedDict([("model", force_text(obj._meta))])
+ attrs = OrderedDict([("model", str(obj._meta))])
if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
obj_pk = obj._get_pk_val()
if obj_pk is not None:
- attrs['pk'] = force_text(obj_pk)
+ attrs['pk'] = str(obj_pk)
self.xml.startElement("object", attrs)
@@ -101,10 +100,10 @@ class Serializer(base.Serializer):
# Iterable natural keys are rolled out as subelements
for key_value in related:
self.xml.startElement("natural", {})
- self.xml.characters(force_text(key_value))
+ self.xml.characters(str(key_value))
self.xml.endElement("natural")
else:
- self.xml.characters(force_text(related_att))
+ self.xml.characters(str(related_att))
else:
self.xml.addQuickElement("None")
self.xml.endElement("field")
@@ -125,13 +124,13 @@ class Serializer(base.Serializer):
self.xml.startElement("object", {})
for key_value in natural:
self.xml.startElement("natural", {})
- self.xml.characters(force_text(key_value))
+ self.xml.characters(str(key_value))
self.xml.endElement("natural")
self.xml.endElement("object")
else:
def handle_m2m(value):
self.xml.addQuickElement("object", attrs={
- 'pk': force_text(value._get_pk_val())
+ 'pk': str(value._get_pk_val())
})
for relobj in getattr(obj, field.name).iterator():
handle_m2m(relobj)
@@ -144,7 +143,7 @@ class Serializer(base.Serializer):
self.xml.startElement("field", OrderedDict([
("name", field.name),
("rel", field.remote_field.__class__.__name__),
- ("to", force_text(field.remote_field.model._meta)),
+ ("to", str(field.remote_field.model._meta)),
]))
diff --git a/django/core/validators.py b/django/core/validators.py
index 89568cfb05e..e454ca213b6 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -5,7 +5,6 @@ from urllib.parse import urlsplit, urlunsplit
from django.core.exceptions import ValidationError
from django.utils.deconstruct import deconstructible
-from django.utils.encoding import force_text
from django.utils.functional import SimpleLazyObject
from django.utils.ipv6 import is_valid_ipv6_address
from django.utils.translation import gettext_lazy as _, ngettext_lazy
@@ -55,8 +54,7 @@ class RegexValidator:
Validate that the input contains a match for the regular expression
if inverse_match is False, otherwise raise ValidationError.
"""
- if not (self.inverse_match is not bool(self.regex.search(
- force_text(value)))):
+ if not (self.inverse_match is not bool(self.regex.search(str(value)))):
raise ValidationError(self.message, code=self.code)
def __eq__(self, other):
diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py
index d1149cc0fec..c3df3465c35 100644
--- a/django/db/backends/base/operations.py
+++ b/django/db/backends/base/operations.py
@@ -410,7 +410,7 @@ class BaseDatabaseOperations:
def prep_for_like_query(self, x):
"""Prepare a value for use in a LIKE query."""
- return force_text(x).replace("\\", "\\\\").replace("%", r"\%").replace("_", r"\_")
+ return str(x).replace("\\", "\\\\").replace("%", r"\%").replace("_", r"\_")
# Same as prep_for_like_query(), but called for "iexact" matches, which
# need not necessarily be implemented using "LIKE" in the backend.
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index c234a382ca9..78064020558 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -16,7 +16,6 @@ from django.utils import timezone
from django.utils.dateparse import (
parse_date, parse_datetime, parse_duration, parse_time,
)
-from django.utils.encoding import force_text
from .client import DatabaseClient # isort:skip
from .creation import DatabaseCreation # isort:skip
@@ -456,7 +455,7 @@ def _sqlite_timestamp_diff(lhs, rhs):
def _sqlite_regexp(re_pattern, re_string):
- return bool(re.search(re_pattern, force_text(re_string))) if re_string is not None else False
+ return bool(re.search(re_pattern, str(re_string))) if re_string is not None else False
def _sqlite_power(x, y):
diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py
index f56b5053816..9c135a5fa9b 100644
--- a/django/db/migrations/serializer.py
+++ b/django/db/migrations/serializer.py
@@ -13,7 +13,6 @@ from django.db import models
from django.db.migrations.operations.base import Operation
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
from django.utils import datetime_safe
-from django.utils.encoding import force_text
from django.utils.functional import LazyObject, Promise
from django.utils.timezone import utc
from django.utils.version import get_docs_version
@@ -303,7 +302,7 @@ class UUIDSerializer(BaseSerializer):
def serializer_factory(value):
from django.db.migrations.writer import SettingsReference
if isinstance(value, Promise):
- value = force_text(value)
+ value = str(value)
elif isinstance(value, LazyObject):
# The unwrapped value is returned as the first item of the arguments
# tuple.
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 95630ebb4ec..ee48a02d92d 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -25,7 +25,7 @@ from django.utils.dateparse import (
parse_date, parse_datetime, parse_duration, parse_time,
)
from django.utils.duration import duration_string
-from django.utils.encoding import force_bytes, force_text, smart_text
+from django.utils.encoding import force_bytes, smart_text
from django.utils.functional import Promise, cached_property, curry
from django.utils.ipv6 import clean_ipv6_address
from django.utils.itercompat import is_iterable
@@ -805,7 +805,7 @@ class Field(RegisterLookupMixin):
Return a string value of this field from the passed obj.
This is used by the serialization framework.
"""
- return force_text(self.value_from_object(obj))
+ return str(self.value_from_object(obj))
def _get_flatchoices(self):
"""Flattened version of choices tuple."""
@@ -1058,7 +1058,7 @@ class CharField(Field):
def to_python(self, value):
if isinstance(value, str) or value is None:
return value
- return force_text(value)
+ return str(value)
def get_prep_value(self, value):
value = super().get_prep_value(value)
@@ -1920,7 +1920,7 @@ class GenericIPAddressField(Field):
if value is None:
return None
if not isinstance(value, str):
- value = force_text(value)
+ value = str(value)
value = value.strip()
if ':' in value:
return clean_ipv6_address(value, self.unpack_ipv4, self.error_messages['invalid'])
@@ -2089,7 +2089,7 @@ class TextField(Field):
def to_python(self, value):
if isinstance(value, str) or value is None:
return value
- return force_text(value)
+ return str(value)
def get_prep_value(self, value):
value = super().get_prep_value(value)
diff --git a/django/db/models/fields/reverse_related.py b/django/db/models/fields/reverse_related.py
index 3e0285abea8..36396ac2822 100644
--- a/django/db/models/fields/reverse_related.py
+++ b/django/db/models/fields/reverse_related.py
@@ -10,7 +10,6 @@ they're the closest concept currently available.
"""
from django.core import exceptions
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
from . import BLANK_CHOICE_DASH
@@ -123,7 +122,7 @@ class ForeignObjectRel:
initially for utilization by RelatedFieldListFilter.
"""
return (blank_choice if include_blank else []) + [
- (x._get_pk_val(), force_text(x)) for x in self.related_model._default_manager.all()
+ (x._get_pk_val(), str(x)) for x in self.related_model._default_manager.all()
]
def is_hidden(self):
diff --git a/django/db/models/options.py b/django/db/models/options.py
index c8f7ade82ca..cd50ff0aaae 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -14,7 +14,6 @@ from django.db.models.fields.proxy import OrderWrt
from django.db.models.query_utils import PathInfo
from django.utils.datastructures import ImmutableList, OrderedSet
from django.utils.deprecation import RemovedInDjango21Warning
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.text import camel_case_to_spaces, format_lazy
from django.utils.translation import override
@@ -317,7 +316,7 @@ class Options:
def verbose_name_raw(self):
"""Return the untranslated verbose name."""
with override(None):
- return force_text(self.verbose_name)
+ return str(self.verbose_name)
@property
def swapped(self):
diff --git a/django/forms/boundfield.py b/django/forms/boundfield.py
index f3f6e3aea01..128d9ce80aa 100644
--- a/django/forms/boundfield.py
+++ b/django/forms/boundfield.py
@@ -4,7 +4,6 @@ import warnings
from django.forms.utils import flatatt, pretty_name
from django.forms.widgets import Textarea, TextInput
from django.utils.deprecation import RemovedInDjango21Warning
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.html import conditional_escape, format_html, html_safe
from django.utils.inspect import func_supports_parameter
@@ -213,9 +212,9 @@ class BoundField:
Calculate and return the ID attribute for this BoundField, if the
associated Form has specified auto_id. Return an empty string otherwise.
"""
- auto_id = self.form.auto_id
- if auto_id and '%s' in force_text(auto_id):
- return force_text(auto_id) % self.html_name
+ auto_id = self.form.auto_id # Boolean or string
+ if auto_id and '%s' in str(auto_id):
+ return auto_id % self.html_name
elif auto_id:
return self.html_name
return ''
diff --git a/django/forms/fields.py b/django/forms/fields.py
index e42c1597c71..a4132d8f33c 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -28,7 +28,6 @@ from django.forms.widgets import (
from django.utils import formats
from django.utils.dateparse import parse_duration
from django.utils.duration import duration_string
-from django.utils.encoding import force_text
from django.utils.ipv6 import clean_ipv6_address
from django.utils.translation import gettext_lazy as _, ngettext_lazy
@@ -221,7 +220,7 @@ class CharField(Field):
"""Return a string."""
if value in self.empty_values:
return self.empty_value
- value = force_text(value)
+ value = str(value)
if self.strip:
value = value.strip()
return value
@@ -268,7 +267,7 @@ class IntegerField(Field):
value = formats.sanitize_separators(value)
# Strip trailing decimal and zeros.
try:
- value = int(self.re_decimal.sub('', force_text(value)))
+ value = int(self.re_decimal.sub('', str(value)))
except (ValueError, TypeError):
raise ValidationError(self.error_messages['invalid'], code='invalid')
return value
@@ -341,7 +340,7 @@ class DecimalField(IntegerField):
return None
if self.localize:
value = formats.sanitize_separators(value)
- value = force_text(value).strip()
+ value = str(value).strip()
try:
value = Decimal(value)
except DecimalException:
@@ -484,7 +483,7 @@ class DurationField(Field):
return None
if isinstance(value, datetime.timedelta):
return value
- value = parse_duration(force_text(value))
+ value = parse_duration(str(value))
if value is None:
raise ValidationError(self.error_messages['invalid'], code='invalid')
return value
@@ -784,7 +783,7 @@ class ChoiceField(Field):
"""Return a string."""
if value in self.empty_values:
return ''
- return force_text(value)
+ return str(value)
def validate(self, value):
"""Validate that the input is in self.choices."""
@@ -798,15 +797,15 @@ class ChoiceField(Field):
def valid_value(self, value):
"""Check to see if the provided value is a valid choice."""
- text_value = force_text(value)
+ text_value = str(value)
for k, v in self.choices:
if isinstance(v, (list, tuple)):
# This is an optgroup, so look inside the group for options
for k2, v2 in v:
- if value == k2 or text_value == force_text(k2):
+ if value == k2 or text_value == str(k2):
return True
else:
- if value == k or text_value == force_text(k):
+ if value == k or text_value == str(k):
return True
return False
@@ -851,7 +850,7 @@ class MultipleChoiceField(ChoiceField):
return []
elif not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages['invalid_list'], code='invalid_list')
- return [force_text(val) for val in value]
+ return [str(val) for val in value]
def validate(self, value):
"""Validate that the input is a list or tuple."""
@@ -873,8 +872,8 @@ class MultipleChoiceField(ChoiceField):
data = []
if len(initial) != len(data):
return True
- initial_set = set(force_text(value) for value in initial)
- data_set = set(force_text(value) for value in data)
+ initial_set = set(str(value) for value in initial)
+ data_set = set(str(value) for value in data)
return data_set != initial_set
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 80613570ad1..e2e7c645ff2 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -12,7 +12,6 @@ from django.forms.fields import Field, FileField
# pretty_name is imported for backwards compatibility in Django 1.9
from django.forms.utils import ErrorDict, ErrorList, pretty_name # NOQA
from django.forms.widgets import Media, MediaDefiningClass
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.html import conditional_escape, html_safe
from django.utils.safestring import mark_safe
@@ -205,7 +204,7 @@ class BaseForm:
if bf.is_hidden:
if bf_errors:
top_errors.extend(
- [_('(Hidden field %(name)s) %(error)s') % {'name': name, 'error': force_text(e)}
+ [_('(Hidden field %(name)s) %(error)s') % {'name': name, 'error': str(e)}
for e in bf_errors])
hidden_fields.append(str(bf))
else:
@@ -216,10 +215,10 @@ class BaseForm:
html_class_attr = ' class="%s"' % css_classes
if errors_on_separate_row and bf_errors:
- output.append(error_row % force_text(bf_errors))
+ output.append(error_row % str(bf_errors))
if bf.label:
- label = conditional_escape(force_text(bf.label))
+ label = conditional_escape(bf.label)
label = bf.label_tag(label) or ''
else:
label = ''
diff --git a/django/forms/models.py b/django/forms/models.py
index b259a8df288..adc31081b7c 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -16,7 +16,6 @@ from django.forms.utils import ErrorList
from django.forms.widgets import (
HiddenInput, MultipleHiddenInput, SelectMultiple,
)
-from django.utils.encoding import force_text
from django.utils.text import capfirst, get_text_list
from django.utils.translation import gettext, gettext_lazy as _
@@ -1085,7 +1084,7 @@ class InlineForeignKeyField(Field):
orig = getattr(self.parent_instance, self.to_field)
else:
orig = self.parent_instance.pk
- if force_text(value) != force_text(orig):
+ if str(value) != str(orig):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
return self.parent_instance
@@ -1176,7 +1175,7 @@ class ModelChoiceField(ChoiceField):
presented by this object. Subclasses can override this method to
customize the display of the choices.
"""
- return force_text(obj)
+ return str(obj)
def _get_choices(self):
# If self._choices is set, then somebody must have manually set
@@ -1219,7 +1218,7 @@ class ModelChoiceField(ChoiceField):
def has_changed(self, initial, data):
initial_value = initial if initial is not None else ''
data_value = data if data is not None else ''
- return force_text(self.prepare_value(initial_value)) != force_text(data_value)
+ return str(self.prepare_value(initial_value)) != str(data_value)
class ModelMultipleChoiceField(ModelChoiceField):
@@ -1286,9 +1285,9 @@ class ModelMultipleChoiceField(ModelChoiceField):
params={'pk': pk},
)
qs = self.queryset.filter(**{'%s__in' % key: value})
- pks = set(force_text(getattr(o, key)) for o in qs)
+ pks = set(str(getattr(o, key)) for o in qs)
for val in value:
- if force_text(val) not in pks:
+ if str(val) not in pks:
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
@@ -1310,8 +1309,8 @@ class ModelMultipleChoiceField(ModelChoiceField):
data = []
if len(initial) != len(data):
return True
- initial_set = set(force_text(value) for value in self.prepare_value(initial))
- data_set = set(force_text(value) for value in data)
+ initial_set = set(str(value) for value in self.prepare_value(initial))
+ data_set = set(str(value) for value in data)
return data_set != initial_set
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 04f800785bd..2feded85c71 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -12,7 +12,6 @@ from django.forms.utils import to_current_timezone
from django.templatetags.static import static
from django.utils import datetime_safe, formats
from django.utils.dates import MONTHS
-from django.utils.encoding import force_text
from django.utils.formats import get_format
from django.utils.html import format_html, html_safe
from django.utils.safestring import mark_safe
@@ -184,7 +183,7 @@ class Widget(metaclass=MediaDefiningClass):
return None
if self.is_localized:
return formats.localize_input(value)
- return force_text(value)
+ return str(value)
def get_context(self, name, value, attrs):
context = {}
@@ -483,7 +482,7 @@ class CheckboxInput(Input):
"""Only return the 'value' attribute if value isn't empty."""
if value is True or value is False or value is None or value == '':
return
- return force_text(value)
+ return str(value)
def get_context(self, name, value, attrs):
if self.check_test(value):
@@ -570,7 +569,7 @@ class ChoiceWidget(Widget):
for subvalue, sublabel in choices:
selected = (
- force_text(subvalue) in value and
+ str(subvalue) in value and
(not has_selected or self.allow_multiple_selected)
)
if selected and not has_selected:
diff --git a/django/http/response.py b/django/http/response.py
index e8417a9fd76..2495ebcc091 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -13,7 +13,7 @@ from django.core.exceptions import DisallowedRedirect
from django.core.serializers.json import DjangoJSONEncoder
from django.http.cookie import SimpleCookie
from django.utils import timezone
-from django.utils.encoding import force_bytes, force_text, iri_to_uri
+from django.utils.encoding import force_bytes, iri_to_uri
from django.utils.http import cookie_date
_charset_from_content_type_re = re.compile(r';\s*charset=(?P[^\s;]+)', re.I)
@@ -405,7 +405,7 @@ class HttpResponseRedirectBase(HttpResponse):
def __init__(self, redirect_to, *args, **kwargs):
super().__init__(*args, **kwargs)
self['Location'] = iri_to_uri(redirect_to)
- parsed = urlparse(force_text(redirect_to))
+ parsed = urlparse(str(redirect_to))
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
diff --git a/django/shortcuts.py b/django/shortcuts.py
index 0ce7ee327f9..6fe3d2d5906 100644
--- a/django/shortcuts.py
+++ b/django/shortcuts.py
@@ -11,7 +11,6 @@ from django.http import (
from django.template import loader
from django.urls import NoReverseMatch, reverse
from django.utils.deprecation import RemovedInDjango30Warning
-from django.utils.encoding import force_text
from django.utils.functional import Promise
@@ -138,7 +137,7 @@ def resolve_url(to, *args, **kwargs):
if isinstance(to, Promise):
# Expand the lazy instance, as it can cause issues when it is passed
# further to some Python functions like urlparse.
- to = force_text(to)
+ to = str(to)
if isinstance(to, str):
# Handle relative URLs
diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py
index 9b8462903e0..8bb80c86cb1 100644
--- a/django/urls/resolvers.py
+++ b/django/urls/resolvers.py
@@ -16,7 +16,6 @@ from django.core.checks import Warning
from django.core.checks.urls import check_resolver
from django.core.exceptions import ImproperlyConfigured
from django.utils.datastructures import MultiValueDict
-from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS
from django.utils.regex_helper import normalize
@@ -92,7 +91,7 @@ class LocaleRegexDescriptor:
return instance.__dict__['regex']
language_code = get_language()
if language_code not in instance._regex_dict:
- instance._regex_dict[language_code] = self._compile(force_text(instance._regex))
+ instance._regex_dict[language_code] = self._compile(str(instance._regex))
return instance._regex_dict[language_code]
def _compile(self, regex):
@@ -347,7 +346,7 @@ class RegexURLResolver(LocaleRegexProvider):
return name in self._callback_strs
def resolve(self, path):
- path = force_text(path) # path may be a reverse_lazy object
+ path = str(path) # path may be a reverse_lazy object
tried = []
match = self.regex.search(path)
if match:
@@ -422,8 +421,8 @@ class RegexURLResolver(LocaleRegexProvider):
def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
if args and kwargs:
raise ValueError("Don't mix *args and **kwargs in call to reverse()!")
- text_args = [force_text(v) for v in args]
- text_kwargs = {k: force_text(v) for (k, v) in kwargs.items()}
+ text_args = [str(v) for v in args]
+ text_kwargs = {k: str(v) for (k, v) in kwargs.items()}
if not self._populated:
self._populate()
diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py
index 6c8cab61f5e..d3f586aacf0 100644
--- a/django/utils/dateformat.py
+++ b/django/utils/dateformat.py
@@ -18,7 +18,6 @@ import time
from django.utils.dates import (
MONTHS, MONTHS_3, MONTHS_ALT, MONTHS_AP, WEEKDAYS, WEEKDAYS_ABBR,
)
-from django.utils.encoding import force_text
from django.utils.timezone import get_default_timezone, is_aware, is_naive
from django.utils.translation import gettext as _
@@ -29,14 +28,14 @@ re_escaped = re.compile(r'\\(.)')
class Formatter:
def format(self, formatstr):
pieces = []
- for i, piece in enumerate(re_formatchars.split(force_text(formatstr))):
+ for i, piece in enumerate(re_formatchars.split(str(formatstr))):
if i % 2:
if type(self.data) is datetime.date and hasattr(TimeFormat, piece):
raise TypeError(
"The format for date objects may not contain "
"time-related format specifiers (found '%s')." % piece
)
- pieces.append(force_text(getattr(self, piece)()))
+ pieces.append(str(getattr(self, piece)()))
elif piece:
pieces.append(re_escaped.sub(r'\1', piece))
return ''.join(pieces)
diff --git a/django/utils/html.py b/django/utils/html.py
index 25843ce576e..9f4f58c7a1c 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -43,7 +43,7 @@ def escape(text):
conditional_escape() instead.
"""
return mark_safe(
- force_text(text).replace('&', '&').replace('<', '<')
+ str(text).replace('&', '&').replace('<', '<')
.replace('>', '>').replace('"', '"').replace("'", ''')
)
@@ -70,7 +70,7 @@ _js_escapes.update((ord('%c' % z), '\\u%04X' % z) for z in range(32))
@keep_lazy(str, SafeText)
def escapejs(value):
"""Hex encode characters for use in JavaScript strings."""
- return mark_safe(force_text(value).translate(_js_escapes))
+ return mark_safe(str(value).translate(_js_escapes))
def conditional_escape(text):
@@ -121,8 +121,8 @@ def format_html_join(sep, format_string, args_generator):
@keep_lazy_text
def linebreaks(value, autoescape=False):
"""Convert newlines into
and s."""
- value = normalize_newlines(force_text(value))
- paras = re.split('\n{2,}', value)
+ value = normalize_newlines(value)
+ paras = re.split('\n{2,}', str(value))
if autoescape:
paras = ['
%s
' % escape(p).replace('\n', ' ') for p in paras]
else:
diff --git a/django/utils/text.py b/django/utils/text.py
index cd9e704ea1f..3e04f8bec77 100644
--- a/django/utils/text.py
+++ b/django/utils/text.py
@@ -4,7 +4,6 @@ import unicodedata
from gzip import GzipFile
from io import BytesIO
-from django.utils.encoding import force_text
from django.utils.functional import (
SimpleLazyObject, keep_lazy, keep_lazy_text, lazy,
)
@@ -15,7 +14,7 @@ from django.utils.translation import gettext as _, gettext_lazy, pgettext
@keep_lazy_text
def capfirst(x):
"""Capitalize the first letter of a string."""
- return x and force_text(x)[0].upper() + force_text(x)[1:]
+ return x and str(x)[0].upper() + str(x)[1:]
# Set up regular expressions
@@ -62,7 +61,7 @@ class Truncator(SimpleLazyObject):
An object used to truncate text, either by characters or words.
"""
def __init__(self, text):
- super().__init__(lambda: force_text(text))
+ super().__init__(lambda: str(text))
def add_truncation_text(self, text, truncate=None):
if truncate is None:
@@ -230,7 +229,7 @@ def get_valid_filename(s):
>>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg'
"""
- s = force_text(s).strip().replace(' ', '_')
+ s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
@@ -251,18 +250,17 @@ def get_text_list(list_, last_word=gettext_lazy('or')):
if len(list_) == 0:
return ''
if len(list_) == 1:
- return force_text(list_[0])
+ return str(list_[0])
return '%s %s %s' % (
# Translators: This string is used as a separator between list elements
- _(', ').join(force_text(i) for i in list_[:-1]),
- force_text(last_word), force_text(list_[-1]))
+ _(', ').join(str(i) for i in list_[:-1]), str(last_word), str(list_[-1])
+ )
@keep_lazy_text
def normalize_newlines(text):
"""Normalize CRLF and CR newlines to just LF."""
- text = force_text(text)
- return re_newlines.sub('\n', text)
+ return re_newlines.sub('\n', str(text))
@keep_lazy_text
@@ -349,8 +347,7 @@ def smart_split(text):
>>> list(smart_split(r'A "\"funky\" style" test.'))
['A', '"\\"funky\\" style"', 'test.']
"""
- text = force_text(text)
- for bit in smart_split_re.finditer(text):
+ for bit in smart_split_re.finditer(str(text)):
yield bit.group(0)
@@ -378,7 +375,7 @@ _entity_re = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));")
@keep_lazy_text
def unescape_entities(text):
- return _entity_re.sub(_replace_entity, force_text(text))
+ return _entity_re.sub(_replace_entity, str(text))
@keep_lazy_text
@@ -409,7 +406,7 @@ def slugify(value, allow_unicode=False):
Remove characters that aren't alphanumerics, underscores, or hyphens.
Convert to lowercase. Also strip leading and trailing whitespace.
"""
- value = force_text(value)
+ value = str(value)
if allow_unicode:
value = unicodedata.normalize('NFKC', value)
else:
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index dc4936a9763..f342cf7227a 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -6,7 +6,6 @@ import warnings
from contextlib import ContextDecorator
from django.utils.deprecation import RemovedInDjango21Warning
-from django.utils.encoding import force_text
from django.utils.functional import lazy
__all__ = [
@@ -226,7 +225,7 @@ def _string_concat(*strings):
'django.utils.translate.string_concat() is deprecated in '
'favor of django.utils.text.format_lazy().',
RemovedInDjango21Warning, stacklevel=2)
- return ''.join(force_text(s) for s in strings)
+ return ''.join(str(s) for s in strings)
string_concat = lazy(_string_concat, str)
diff --git a/django/views/debug.py b/django/views/debug.py
index d32188b3469..d3361486cb3 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -287,7 +287,7 @@ class ExceptionReporter:
user_str = None
else:
try:
- user_str = force_text(self.request.user)
+ user_str = str(self.request.user)
except Exception:
# request.user may raise OperationalError if the database is
# unavailable, for example.
@@ -318,7 +318,7 @@ class ExceptionReporter:
if self.exc_type:
c['exception_type'] = self.exc_type.__name__
if self.exc_value:
- c['exception_value'] = force_text(self.exc_value, errors='replace')
+ c['exception_value'] = str(self.exc_value)
if frames:
c['lastframe'] = frames[-1]
return c
diff --git a/django/views/defaults.py b/django/views/defaults.py
index e9057c455e7..dee081ec3d9 100644
--- a/django/views/defaults.py
+++ b/django/views/defaults.py
@@ -3,7 +3,6 @@ from django.http import (
HttpResponseServerError,
)
from django.template import Context, Engine, TemplateDoesNotExist, loader
-from django.utils.encoding import force_text
from django.views.decorators.csrf import requires_csrf_token
ERROR_404_TEMPLATE_NAME = '404.html'
@@ -117,5 +116,5 @@ def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME)
raise
return HttpResponseForbidden('
403 Forbidden
', content_type='text/html')
return HttpResponseForbidden(
- template.render(request=request, context={'exception': force_text(exception)})
+ template.render(request=request, context={'exception': str(exception)})
)
diff --git a/django/views/generic/edit.py b/django/views/generic/edit.py
index 3dff9ece334..ad2f2b1c673 100644
--- a/django/views/generic/edit.py
+++ b/django/views/generic/edit.py
@@ -1,7 +1,6 @@
from django.core.exceptions import ImproperlyConfigured
from django.forms import models as model_forms
from django.http import HttpResponseRedirect
-from django.utils.encoding import force_text
from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
from django.views.generic.detail import (
BaseDetailView, SingleObjectMixin, SingleObjectTemplateResponseMixin,
@@ -49,13 +48,9 @@ class FormMixin(ContextMixin):
def get_success_url(self):
"""Return the URL to redirect to after processing a valid form."""
- if self.success_url:
- # Forcing possible reverse_lazy evaluation
- url = force_text(self.success_url)
- else:
- raise ImproperlyConfigured(
- "No URL to redirect to. Provide a success_url.")
- return url
+ if not self.success_url:
+ raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.")
+ return str(self.success_url) # success_url may be lazy
def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt
index 54a62c50db5..a64790b34c3 100644
--- a/docs/howto/custom-model-fields.txt
+++ b/docs/howto/custom-model-fields.txt
@@ -706,10 +706,10 @@ smoothly:
2. Put a ``__str__()`` method on the class you're wrapping up as a field. There
are a lot of places where the default behavior of the field code is to call
- :func:`~django.utils.encoding.force_text` on the value. (In our
- examples in this document, ``value`` would be a ``Hand`` instance, not a
- ``HandField``). So if your ``__str__()`` method automatically converts to
- the string form of your Python object, you can save yourself a lot of work.
+ ``str()`` on the value. (In our examples in this document, ``value`` would
+ be a ``Hand`` instance, not a ``HandField``). So if your ``__str__()``
+ method automatically converts to the string form of your Python object, you
+ can save yourself a lot of work.
Writing a ``FileField`` subclass
================================
diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt
index fd1c8876ec9..9a1b977d98a 100644
--- a/docs/topics/serialization.txt
+++ b/docs/topics/serialization.txt
@@ -256,13 +256,12 @@ For example, if you have some custom type in an object to be serialized, you'll
have to write a custom :mod:`json` encoder for it. Something like this will
work::
- from django.utils.encoding import force_text
from django.core.serializers.json import DjangoJSONEncoder
class LazyEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, YourCustomType):
- return force_text(obj)
+ return str(obj)
return super().default(obj)
You can then pass ``cls=LazyEncoder`` to the ``serializers.serialize()``