From d3e12c901777697b7bf08b25e2dd46f0b951db8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=96=9B=E4=B8=9E=E5=AE=8F?= <ihcaoe@gmail.com>
Date: Tue, 23 Jun 2015 14:08:12 +0800
Subject: [PATCH] Fixed #25016 -- Reallowed non-ASCII values for
 ForeignKey.related_name on Python 3.

---
 django/db/models/fields/related.py               | 16 ++++++++++++----
 docs/releases/1.8.3.txt                          |  3 +++
 docs/spelling_wordlist                           |  1 +
 .../invalid_models_tests/test_relative_fields.py | 11 +++++++++--
 4 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 0788db48f8..b038fdf116 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -119,10 +119,18 @@ class RelatedField(Field):
         import re
         import keyword
         related_name = self.remote_field.related_name
-
-        is_valid_id = (related_name and re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', related_name)
-                       and not keyword.iskeyword(related_name))
-        if related_name and not (is_valid_id or related_name.endswith('+')):
+        if not related_name:
+            return []
+        is_valid_id = True
+        if keyword.iskeyword(related_name):
+            is_valid_id = False
+        if six.PY3:
+            if not related_name.isidentifier():
+                is_valid_id = False
+        else:
+            if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*\Z', related_name):
+                is_valid_id = False
+        if not (is_valid_id or related_name.endswith('+')):
             return [
                 checks.Error(
                     "The name '%s' is invalid related_name for field %s.%s" %
diff --git a/docs/releases/1.8.3.txt b/docs/releases/1.8.3.txt
index 38bcaf5374..512d6ff7c7 100644
--- a/docs/releases/1.8.3.txt
+++ b/docs/releases/1.8.3.txt
@@ -82,3 +82,6 @@ Bugfixes
 
 * Fixed a regression when deleting a model through the admin that has a
   ``GenericRelation`` with a ``related_query_name`` (:ticket:`24940`).
+
+* Reallowed non-ASCII values for ``ForeignKey.related_name`` on Python 3 by
+  fixing the false positive system check (:ticket:`25016`).
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 293aa6f816..ff37b3159e 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -625,6 +625,7 @@ quo
 quoteless
 Radziej
 rc
+reallowed
 rebase
 rebased
 rebasing
diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py
index b6ac3de722..5d174d0c9b 100644
--- a/tests/invalid_models_tests/test_relative_fields.py
+++ b/tests/invalid_models_tests/test_relative_fields.py
@@ -5,6 +5,7 @@ from django.core.checks import Error, Warning as DjangoWarning
 from django.db import models
 from django.test.testcases import skipIfDBFeature
 from django.test.utils import override_settings
+from django.utils import six
 
 from .base import IsolatedModelsTestCase
 
@@ -559,9 +560,12 @@ class RelativeFieldTests(IsolatedModelsTestCase):
             'contains_%s_whitespace' % whitespace,
             'ends_with_with_illegal_non_alphanumeric_%s' % illegal_non_alphanumeric,
             'ends_with_whitespace_%s' % whitespace,
-            # Python's keyword
-            'with',
+            'with',  # a Python keyword
+            'related_name\n',
         ]
+        # Python 2 crashes on non-ASCII strings.
+        if six.PY3:
+            invalid_related_names.append(',')
 
         class Parent(models.Model):
             pass
@@ -600,6 +604,9 @@ class RelativeFieldTests(IsolatedModelsTestCase):
             '_+',
             '+',
         ]
+        # Python 2 crashes on non-ASCII strings.
+        if six.PY3:
+            related_names.extend(['試', '試驗+'])
 
         class Parent(models.Model):
             pass