[1.11.x] Bumped MySQLdb version requirement to 1.2.3.

Older versions don't support Python 2.7.

Partial backport of 2d96c027f5 from master
This commit is contained in:
Tim Graham 2017-01-25 10:16:10 -05:00
parent c94cb4f865
commit ec0af19f4c
3 changed files with 19 additions and 80 deletions

View File

@ -42,13 +42,12 @@ from .operations import DatabaseOperations # isort:skip
from .schema import DatabaseSchemaEditor # isort:skip from .schema import DatabaseSchemaEditor # isort:skip
from .validation import DatabaseValidation # isort:skip from .validation import DatabaseValidation # isort:skip
# We want version (1, 2, 1, 'final', 2) or later. We can't just use
# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
# inadvertently passes the version test.
version = Database.version_info version = Database.version_info
if (version < (1, 2, 1) or ( if version < (1, 2, 3):
version[:3] == (1, 2, 1) and (len(version) < 5 or version[3] != 'final' or version[4] < 2))): raise ImproperlyConfigured(
raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__) "MySQLdb/mysqlclient 1.2.3 or newer is required; you have %s"
% Database.__version__
)
def adapt_datetime_warn_on_aware_datetime(value, conv): def adapt_datetime_warn_on_aware_datetime(value, conv):
@ -65,11 +64,11 @@ def adapt_datetime_warn_on_aware_datetime(value, conv):
return Thing2Literal(value.strftime("%Y-%m-%d %H:%M:%S.%f"), conv) return Thing2Literal(value.strftime("%Y-%m-%d %H:%M:%S.%f"), conv)
# MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like # MySQLdb returns TIME columns as timedelta -- they are more like timedelta in
# timedelta in terms of actual behavior as they are signed and include days -- # terms of actual behavior as they are signed and include days -- and Django
# and Django expects time, so we still need to override that. We also need to # expects time, so we still need to override that. We also need to add special
# add special handling for SafeText and SafeBytes as MySQLdb's type # handling for SafeText and SafeBytes as MySQLdb's type checking is too tight
# checking is too tight to catch those (see Django ticket #6052). # to catch those (see Django ticket #6052).
django_conversions = conversions.copy() django_conversions = conversions.copy()
django_conversions.update({ django_conversions.update({
FIELD_TYPE.TIME: backend_utils.typecast_time, FIELD_TYPE.TIME: backend_utils.typecast_time,
@ -83,13 +82,6 @@ django_conversions.update({
server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})') server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
# MySQLdb-1.2.1 and newer automatically makes use of SHOW WARNINGS on
# MySQL-4.1 and newer, so the MysqlDebugWrapper is unnecessary. Since the
# point is to raise Warnings as exceptions, this can be done with the Python
# warning module, and this is setup when the connection is created, and the
# standard backend_utils.CursorDebugWrapper can be used. Also, using sql_mode
# TRADITIONAL will automatically cause most warnings to be treated as errors.
class CursorWrapper(object): class CursorWrapper(object):
""" """
A thin wrapper around MySQLdb's normal cursor class so that we can catch A thin wrapper around MySQLdb's normal cursor class so that we can catch

View File

@ -301,7 +301,7 @@ MySQL Connector/Python includes `its own`_.
MySQLdb MySQLdb
~~~~~~~ ~~~~~~~
Django requires MySQLdb version 1.2.1p2 or later. Django requires MySQLdb version 1.2.3 or later.
At the time of writing, the latest release of MySQLdb (1.2.5) doesn't support At the time of writing, the latest release of MySQLdb (1.2.5) doesn't support
Python 3. In order to use MySQLdb under Python 3, you'll have to install Python 3. In order to use MySQLdb under Python 3, you'll have to install
@ -319,9 +319,8 @@ Python 3. In order to use MySQLdb under Python 3, you'll have to install
mysqlclient mysqlclient
~~~~~~~~~~~ ~~~~~~~~~~~
Django requires `mysqlclient`_ 1.3.3 or later. Note that Python 3.2 is not Django requires `mysqlclient`_ 1.3.3 or later. mysqlclient should mostly behave
supported. Except for the Python 3.3+ support, mysqlclient should mostly behave the same as MySQLdb.
the same as MySQLDB.
MySQL Connector/Python MySQL Connector/Python
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@ -374,46 +373,9 @@ comparisons being done in a *case-insensitive* manner. That is, ``"Fred"`` and
``"freD"`` are considered equal at the database level. If you have a unique ``"freD"`` are considered equal at the database level. If you have a unique
constraint on a field, it would be illegal to try to insert both ``"aa"`` and constraint on a field, it would be illegal to try to insert both ``"aa"`` and
``"AA"`` into the same column, since they compare as equal (and, hence, ``"AA"`` into the same column, since they compare as equal (and, hence,
non-unique) with the default collation. non-unique) with the default collation. If you want case-sensitive comparisons
on a particular column or table, change the column or table to use the
In many cases, this default will not be a problem. However, if you really want ``utf8_bin`` collation.
case-sensitive comparisons on a particular column or table, you would change
the column or table to use the ``utf8_bin`` collation. The main thing to be
aware of in this case is that if you are using MySQLdb 1.2.2, the database
backend in Django will then return bytestrings (instead of unicode strings) for
any character fields it receive from the database. This is a strong variation
from Django's normal practice of *always* returning unicode strings. It is up
to you, the developer, to handle the fact that you will receive bytestrings if
you configure your table(s) to use ``utf8_bin`` collation. Django itself should
mostly work smoothly with such columns (except for the ``contrib.sessions``
``Session`` and ``contrib.admin`` ``LogEntry`` tables described below), but
your code must be prepared to call ``django.utils.encoding.force_text()`` at
times if it really wants to work with consistent data -- Django will not do
this for you (the database backend layer and the model population layer are
separated internally so the database layer doesn't know it needs to make this
conversion in this one particular case).
If you're using MySQLdb 1.2.1p2, Django's standard
:class:`~django.db.models.CharField` class will return unicode strings even
with ``utf8_bin`` collation. However, :class:`~django.db.models.TextField`
fields will be returned as an ``array.array`` instance (from Python's standard
``array`` module). There isn't a lot Django can do about that, since, again,
the information needed to make the necessary conversions isn't available when
the data is read in from the database. This problem was `fixed in MySQLdb
1.2.2`_, so if you want to use :class:`~django.db.models.TextField` with
``utf8_bin`` collation, upgrading to version 1.2.2 and then dealing with the
bytestrings (which shouldn't be too difficult) as described above is the
recommended solution.
Should you decide to use ``utf8_bin`` collation for some of your tables with
MySQLdb 1.2.1p2 or 1.2.2, you should still use ``utf8_general_ci``
(the default) collation for the ``django.contrib.sessions.models.Session``
table (usually called ``django_session``) and the
:class:`django.contrib.admin.models.LogEntry` table (usually called
``django_admin_log``). Those are the two standard tables that use
:class:`~django.db.models.TextField` internally.
.. _fixed in MySQLdb 1.2.2: http://sourceforge.net/tracker/index.php?func=detail&aid=1495765&group_id=22307&atid=374932
Please note that according to `MySQL Unicode Character Sets`_, comparisons for Please note that according to `MySQL Unicode Character Sets`_, comparisons for
the ``utf8_general_ci`` collation are faster, but slightly less correct, than the ``utf8_general_ci`` collation are faster, but slightly less correct, than
@ -467,12 +429,11 @@ Here's a sample configuration which uses a MySQL option file::
password = PASSWORD password = PASSWORD
default-character-set = utf8 default-character-set = utf8
Several other MySQLdb connection options may be useful, such as ``ssl``, Several other `MySQLdb connection options`_ may be useful, such as ``ssl``,
``init_command``, and ``sql_mode``. Consult the `MySQLdb documentation`_ for ``init_command``, and ``sql_mode``.
more details.
.. _MySQL option file: https://dev.mysql.com/doc/refman/en/option-files.html .. _MySQL option file: https://dev.mysql.com/doc/refman/en/option-files.html
.. _MySQLdb documentation: http://mysql-python.sourceforge.net/ .. _MySQLdb connection options: https://mysqlclient.readthedocs.io/en/latest/user_guide.html#functions-and-attributes
.. _mysql-sql-mode: .. _mysql-sql-mode:

View File

@ -473,13 +473,6 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
``max_length`` for some backends. Refer to the :doc:`database backend ``max_length`` for some backends. Refer to the :doc:`database backend
notes </ref/databases>` for details. notes </ref/databases>` for details.
.. admonition:: MySQL users
If you are using this field with MySQLdb 1.2.2 and the ``utf8_bin``
collation (which is *not* the default), there are some issues to be aware
of. Refer to the :ref:`MySQL database notes <mysql-collation>` for
details.
``CommaSeparatedIntegerField`` ``CommaSeparatedIntegerField``
------------------------------ ------------------------------
@ -1097,13 +1090,6 @@ If you specify a ``max_length`` attribute, it will be reflected in the
However it is not enforced at the model or database level. Use a However it is not enforced at the model or database level. Use a
:class:`CharField` for that. :class:`CharField` for that.
.. admonition:: MySQL users
If you are using this field with MySQLdb 1.2.1p2 and the ``utf8_bin``
collation (which is *not* the default), there are some issues to be aware
of. Refer to the :ref:`MySQL database notes <mysql-collation>` for
details.
``TimeField`` ``TimeField``
------------- -------------