From 8c41bd93c2412ddeb9dbe8bd73e1d3c3427d171b Mon Sep 17 00:00:00 2001
From: Claude Paroz <claude@2xlibre.net>
Date: Mon, 1 Apr 2013 19:51:53 +0200
Subject: [PATCH] Fixed #16737 -- Support non-ascii column names in inspectdb

Thanks moof at metamoof.net for the report.
---
 django/db/backends/mysql/introspection.py               | 9 ++++++---
 django/db/backends/postgresql_psycopg2/introspection.py | 3 ++-
 tests/inspectdb/models.py                               | 4 ++++
 tests/inspectdb/tests.py                                | 8 +++++++-
 4 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py
index 3e3b7808c2..548877e8e6 100644
--- a/django/db/backends/mysql/introspection.py
+++ b/django/db/backends/mysql/introspection.py
@@ -2,6 +2,7 @@ import re
 from .base import FIELD_TYPE
 
 from django.db.backends import BaseDatabaseIntrospection, FieldInfo
+from django.utils.encoding import force_text
 
 
 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
@@ -55,9 +56,11 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
         numeric_map = dict([(line[0], tuple([int(n) for n in line[1:]])) for line in cursor.fetchall()])
 
         cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
-        return [FieldInfo(*(line[:3] + (length_map.get(line[0], line[3]),)
-                                     + numeric_map.get(line[0], line[4:6])
-                                     + (line[6],)))
+        return [FieldInfo(*((force_text(line[0]),)
+                            + line[1:3]
+                            + (length_map.get(line[0], line[3]),)
+                            + numeric_map.get(line[0], line[4:6])
+                            + (line[6],)))
             for line in cursor.description]
 
     def _name_to_index(self, cursor, table_name):
diff --git a/django/db/backends/postgresql_psycopg2/introspection.py b/django/db/backends/postgresql_psycopg2/introspection.py
index 5161b15f92..c334b9d6d0 100644
--- a/django/db/backends/postgresql_psycopg2/introspection.py
+++ b/django/db/backends/postgresql_psycopg2/introspection.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 from django.db.backends import BaseDatabaseIntrospection, FieldInfo
+from django.utils.encoding import force_text
 
 
 class DatabaseIntrospection(BaseDatabaseIntrospection):
@@ -46,7 +47,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
             WHERE table_name = %s""", [table_name])
         null_map = dict(cursor.fetchall())
         cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
-        return [FieldInfo(*(line[:6] + (null_map[line[0]]=='YES',)))
+        return [FieldInfo(*((force_text(line[0]),) + line[1:6] + (null_map[force_text(line[0])]=='YES',)))
                 for line in cursor.description]
 
     def get_relations(self, cursor, table_name):
diff --git a/tests/inspectdb/models.py b/tests/inspectdb/models.py
index ff9f6f01b0..2862f7f3dc 100644
--- a/tests/inspectdb/models.py
+++ b/tests/inspectdb/models.py
@@ -1,3 +1,6 @@
+# -*- encoding: utf-8 -*-
+from __future__ import unicode_literals
+
 from django.db import models
 
 
@@ -29,6 +32,7 @@ class SpecialColumnName(models.Model):
     field_field_2 = models.IntegerField(db_column='__field')
     # Other chars
     prc_x = models.IntegerField(db_column='prc(%) x')
+    non_ascii = models.IntegerField(db_column='tamaño')
 
 class ColumnTypes(models.Model):
     id = models.AutoField(primary_key=True)
diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py
index 39685484a2..79cbbfa3f2 100644
--- a/tests/inspectdb/tests.py
+++ b/tests/inspectdb/tests.py
@@ -1,3 +1,4 @@
+# -*- encoding: utf-8 -*-
 from __future__ import unicode_literals
 
 import re
@@ -6,7 +7,7 @@ from django.core.management import call_command
 from django.db import connection
 from django.test import TestCase, skipUnlessDBFeature
 from django.utils.unittest import expectedFailure
-from django.utils.six import StringIO
+from django.utils.six import PY3, StringIO
 
 if connection.vendor == 'oracle':
     expectedFailureOnOracle = expectedFailure
@@ -146,6 +147,11 @@ class InspectDBTestCase(TestCase):
         self.assertIn("field_field_0 = models.IntegerField(db_column='%s__')" % base_name, output)
         self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output)
         self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output)
+        if PY3:
+            # Python 3 allows non-ascii identifiers
+            self.assertIn("tamaño = models.IntegerField()", output)
+        else:
+            self.assertIn("tama_o = models.IntegerField(db_column='tama\\xf1o')", output)
 
     def test_managed_models(self):
         """Test that by default the command generates models with `Meta.managed = False` (#14305)"""