Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 14804)
+++ django/db/models/base.py	(working copy)
@@ -14,7 +14,7 @@
 from django.db import (connections, router, transaction, DatabaseError,
     DEFAULT_DB_ALIAS)
 from django.db.models import signals
-from django.db.models.loading import register_models, get_model
+from django.db.models.loading import register_models, get_model, MODELS_MODULE_NAME
 from django.utils.translation import ugettext_lazy as _
 import django.utils.copycompat as copy
 from django.utils.functional import curry, update_wrapper
@@ -45,10 +45,22 @@
         base_meta = getattr(new_class, '_meta', None)
 
         if getattr(meta, 'app_label', None) is None:
-            # Figure out the app_label by looking one level up.
+            # Figure out the app_label by looking one level up from the package or module named 'models'.
+            # If no such package or module exists, fall back to the behavior of looking one level up from
+            # the module this model is defined in.
+            
             # For 'django.contrib.sites.models', this would be 'sites'.
+            # For 'geo.models.places' this would be 'geo'.
+            # For 'polymorphic.polymorphic_model' this would be 'polymorphic'
+            
             model_module = sys.modules[new_class.__module__]
-            kwargs = {"app_label": model_module.__name__.split('.')[-2]}
+            package_components = model_module.__name__.split('.')
+            package_components.reverse()  # For finding the last occurance of 'models'
+            try:
+                app_label_index = package_components.index(MODELS_MODULE_NAME) + 1
+            except ValueError:
+                app_label_index = 1
+            kwargs = {"app_label": package_components[app_label_index]}
         else:
             kwargs = {}
 
Index: django/db/models/loading.py
===================================================================
--- django/db/models/loading.py	(revision 14804)
+++ django/db/models/loading.py	(working copy)
@@ -12,8 +12,10 @@
 import threading
 
 __all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
-        'load_app', 'app_cache_ready')
+        'load_app', 'app_cache_ready', 'MODELS_MODULE_NAME')
 
+MODELS_MODULE_NAME = 'models'
+
 class AppCache(object):
     """
     A cache that stores installed applications and their models. Used to
@@ -75,12 +77,12 @@
         self.nesting_level += 1
         app_module = import_module(app_name)
         try:
-            models = import_module('.models', app_name)
+            models = import_module('.' + MODELS_MODULE_NAME, app_name)
         except ImportError:
             self.nesting_level -= 1
             # If the app doesn't have a models module, we can just ignore the
             # ImportError and return no models for it.
-            if not module_has_submodule(app_module, 'models'):
+            if not module_has_submodule(app_module, MODELS_MODULE_NAME):
                 return None
             # But if the app does have a models module, we need to figure out
             # whether to suppress or propagate the error. If can_postpone is
Index: tests/modeltests/model_package_automatic_discovery/models/publication.py
===================================================================
--- tests/modeltests/model_package_automatic_discovery/models/publication.py	(revision 0)
+++ tests/modeltests/model_package_automatic_discovery/models/publication.py	(revision 0)
@@ -0,0 +1,4 @@
+from django.db import models
+
+class Publication(models.Model):
+    title = models.CharField(max_length=30)

Property changes on: tests/modeltests/model_package_automatic_discovery/models/publication.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tests/modeltests/model_package_automatic_discovery/models/__init__.py
===================================================================
--- tests/modeltests/model_package_automatic_discovery/models/__init__.py	(revision 0)
+++ tests/modeltests/model_package_automatic_discovery/models/__init__.py	(revision 0)
@@ -0,0 +1,3 @@
+# Import all the models from subpackages
+from article import Article
+from publication import Publication

Property changes on: tests/modeltests/model_package_automatic_discovery/models/__init__.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tests/modeltests/model_package_automatic_discovery/models/article.py
===================================================================
--- tests/modeltests/model_package_automatic_discovery/models/article.py	(revision 0)
+++ tests/modeltests/model_package_automatic_discovery/models/article.py	(revision 0)
@@ -0,0 +1,5 @@
+from django.db import models
+
+class Article(models.Model):
+    headline = models.CharField(max_length=100)
+    publications = models.ManyToManyField("model_package_automatic_discovery.Publication", null=True, blank=True,)
\ No newline at end of file

Property changes on: tests/modeltests/model_package_automatic_discovery/models/article.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tests/modeltests/model_package_automatic_discovery/__init__.py
===================================================================
--- tests/modeltests/model_package_automatic_discovery/__init__.py	(revision 0)
+++ tests/modeltests/model_package_automatic_discovery/__init__.py	(revision 0)
@@ -0,0 +1 @@
+

Property changes on: tests/modeltests/model_package_automatic_discovery/__init__.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tests/modeltests/model_package_automatic_discovery/tests.py
===================================================================
--- tests/modeltests/model_package_automatic_discovery/tests.py	(revision 0)
+++ tests/modeltests/model_package_automatic_discovery/tests.py	(revision 0)
@@ -0,0 +1,70 @@
+from django.db import models
+
+class Advertisment(models.Model):
+    customer = models.CharField(max_length=100)
+    publications = models.ManyToManyField("model_package_automatic_discovery.Publication", null=True, blank=True)
+
+__test__ = {'API_TESTS': """
+>>> from models.publication import Publication
+>>> from models.article import Article
+
+>>> p = Publication(title="FooBar")
+>>> p.save()
+>>> p
+<Publication: Publication object>
+
+# Regression for #12168: models split into subpackages still get M2M tables
+
+>>> a = Article(headline="a foo headline")
+>>> a.save()
+>>> a.publications.add(p)
+
+>>> a = Article.objects.get(id=1)
+>>> a
+<Article: Article object>
+>>> a.id
+1
+
+# Regression for #12245 - Models can exist in the test package, too
+
+>>> ad = Advertisment(customer="Lawrence Journal-World")
+>>> ad.save()
+>>> ad.publications.add(p)
+
+>>> ad = Advertisment.objects.get(id=1)
+>>> ad
+<Advertisment: Advertisment object>
+
+>>> ad.publications.count()
+1
+
+# Regression for #12386 - field names on the autogenerated intermediate class
+# that are specified as dotted strings don't retain any path component for the
+# field or column name
+
+>>> Article.publications.through._meta.fields[1].name
+'article'
+
+>>> Article.publications.through._meta.fields[1].get_attname_column()
+('article_id', 'article_id')
+
+>>> Article.publications.through._meta.fields[2].name
+'publication'
+
+>>> Article.publications.through._meta.fields[2].get_attname_column()
+('publication_id', 'publication_id')
+
+# The oracle backend truncates the name to 'model_package_automatic_di4b50'.
+>>> Article._meta.get_field('publications').m2m_db_table() \\
+... in ('model_package_automatic_discovery_article_publications', 'model_package_automatic_di4b50')
+True
+
+>>> Article._meta.get_field('publications').m2m_column_name()
+'article_id'
+
+>>> Article._meta.get_field('publications').m2m_reverse_name()
+'publication_id'
+
+"""}
+
+

Property changes on: tests/modeltests/model_package_automatic_discovery/tests.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

