Loading django/db/backends/mysql/validation.py +23 −0 Original line number Diff line number Diff line from django.core import checks from django.db.backends.base.validation import BaseDatabaseValidation from django.utils.version import get_docs_version class DatabaseValidation(BaseDatabaseValidation): def check(self, **kwargs): issues = super(DatabaseValidation, self).check(**kwargs) issues.extend(self._check_sql_mode(**kwargs)) return issues def _check_sql_mode(self, **kwargs): with self.connection.cursor() as cursor: cursor.execute("SELECT @@sql_mode") sql_mode = cursor.fetchone() modes = set(sql_mode[0].split(',')) if not (modes & {'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES'}): return [checks.Warning( "MySQL Strict Mode is not set for database connection '%s'" % self.connection.alias, hint="MySQL's Strict Mode fixes many data integrity problems in MySQL, " "such as data truncation upon insertion, by escalating warnings into " "errors. It is strongly recommended you activate it. See: " "https://docs.djangoproject.com/en/%s/ref/databases/#mysql-sql-mode" % (get_docs_version(),), id='mysql.W002', )] return [] def check_field(self, field, **kwargs): """ MySQL has the following field length restriction: Loading docs/ref/checks.txt +2 −0 Original line number Diff line number Diff line Loading @@ -592,6 +592,8 @@ If you're using MySQL, the following checks will be performed: * **mysql.E001**: MySQL does not allow unique ``CharField``\s to have a ``max_length`` > 255. * **mysql.W002**: MySQL Strict Mode is not set for database connection '<alias>'. See also :ref:`mysql-sql-mode`. Templates --------- Loading tests/check_framework/test_database.py +25 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,28 @@ class DatabaseCheckTests(TestCase): with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check: run_checks(tags=[Tags.database]) self.assertTrue(mocked_check.called) @unittest.skipUnless(connection.vendor == 'mysql', 'Test only for MySQL') def test_mysql_strict_mode(self): good_sql_modes = [ 'STRICT_TRANS_TABLES,STRICT_ALL_TABLES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', ] for response in good_sql_modes: with mock.patch( 'django.db.backends.utils.CursorWrapper.fetchone', create=True, return_value=(response,) ): self.assertEqual(self.func(None), []) bad_sql_modes = ['', 'WHATEVER'] for response in bad_sql_modes: with mock.patch( 'django.db.backends.utils.CursorWrapper.fetchone', create=True, return_value=(response,) ): # One warning for each database alias result = self.func(None) self.assertEqual(len(result), 2) self.assertEqual([r.id for r in result], ['mysql.W002', 'mysql.W002']) Loading
django/db/backends/mysql/validation.py +23 −0 Original line number Diff line number Diff line from django.core import checks from django.db.backends.base.validation import BaseDatabaseValidation from django.utils.version import get_docs_version class DatabaseValidation(BaseDatabaseValidation): def check(self, **kwargs): issues = super(DatabaseValidation, self).check(**kwargs) issues.extend(self._check_sql_mode(**kwargs)) return issues def _check_sql_mode(self, **kwargs): with self.connection.cursor() as cursor: cursor.execute("SELECT @@sql_mode") sql_mode = cursor.fetchone() modes = set(sql_mode[0].split(',')) if not (modes & {'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES'}): return [checks.Warning( "MySQL Strict Mode is not set for database connection '%s'" % self.connection.alias, hint="MySQL's Strict Mode fixes many data integrity problems in MySQL, " "such as data truncation upon insertion, by escalating warnings into " "errors. It is strongly recommended you activate it. See: " "https://docs.djangoproject.com/en/%s/ref/databases/#mysql-sql-mode" % (get_docs_version(),), id='mysql.W002', )] return [] def check_field(self, field, **kwargs): """ MySQL has the following field length restriction: Loading
docs/ref/checks.txt +2 −0 Original line number Diff line number Diff line Loading @@ -592,6 +592,8 @@ If you're using MySQL, the following checks will be performed: * **mysql.E001**: MySQL does not allow unique ``CharField``\s to have a ``max_length`` > 255. * **mysql.W002**: MySQL Strict Mode is not set for database connection '<alias>'. See also :ref:`mysql-sql-mode`. Templates --------- Loading
tests/check_framework/test_database.py +25 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,28 @@ class DatabaseCheckTests(TestCase): with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check: run_checks(tags=[Tags.database]) self.assertTrue(mocked_check.called) @unittest.skipUnless(connection.vendor == 'mysql', 'Test only for MySQL') def test_mysql_strict_mode(self): good_sql_modes = [ 'STRICT_TRANS_TABLES,STRICT_ALL_TABLES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', ] for response in good_sql_modes: with mock.patch( 'django.db.backends.utils.CursorWrapper.fetchone', create=True, return_value=(response,) ): self.assertEqual(self.func(None), []) bad_sql_modes = ['', 'WHATEVER'] for response in bad_sql_modes: with mock.patch( 'django.db.backends.utils.CursorWrapper.fetchone', create=True, return_value=(response,) ): # One warning for each database alias result = self.func(None) self.assertEqual(len(result), 2) self.assertEqual([r.id for r in result], ['mysql.W002', 'mysql.W002'])