﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
25145	Models of apps w/o migrations don't have relational fields to other apps w/o migrations when applying migrations	Markus Holtermann	nobody	"Consider the three apps `w_migrations`, `wo_migrations1` and `wo_migrations2` with the following models:

`w_migrations`:

{{{#!python
class With(models.Model):
    without1 = models.ForeignKey('wo_migrations1.Without1')
}}}

`wo_migrations1`:

{{{#!python
class Without1(models.Model):
    without2 = models.ForeignKey('wo_migrations2.Without2')
}}}

`wo_migrations2`:

{{{#!python
class Without2(models.Model):
    i = models.IntegerField()
}}}

When you create the migration for `w_migrations` and add an additional `RunPython` operation:

{{{#!python

def forward(apps, schema_editor):
    print(apps.get_model('wo_migrations1', 'Without1')._meta._get_fields())


operations = [
    ...,
    migrations.RunPython(forward, migrations.RunPython.noop),
]
}}}

you will get the following output:

{{{#!python
(<django.db.models.fields.AutoField: id>,)
}}}

However, one would expect to see the `ForeignKey` to `wo_migrations2`, too.

A fix should be rather simple by updating `django.db.migrations.state.ModelState.from_model()` similar to those lines:

{{{#!diff
diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py
index b1cba07..4dd25ba 100644
--- a/django/db/migrations/state.py
+++ b/django/db/migrations/state.py
@@ -219,7 +219,7 @@ class StateApps(Apps):
         for app_label in real_apps:
             app = global_apps.get_app_config(app_label)
             for model in app.get_models():
-                self.real_models.append(ModelState.from_model(model, exclude_rels=True))
+                self.real_models.append(ModelState.from_model(model, exclude_rels=True, allow_rels_to=real_apps))
         # Populate the app registry with a stub for each application.
         app_labels = {model_state.app_label for model_state in models.values()}
         app_configs = [AppConfigStub(label) for label in sorted(real_apps + list(app_labels))]
@@ -346,14 +346,15 @@ class ModelState(object):
         return self.name.lower()

     @classmethod
-    def from_model(cls, model, exclude_rels=False):
+    def from_model(cls, model, exclude_rels=False, allow_rels_to=[]):
         """"""
         Feed me a model, get a ModelState representing it out.
         """"""
         # Deconstruct the fields
         fields = []
         for field in model._meta.local_fields:
-            if getattr(field, ""remote_field"", None) and exclude_rels:
+            if (exclude_rels and field.is_relation and
+                    _get_app_label_and_model_name(field.related_model)[0] not in allow_rels_to):
                 continue
             if isinstance(field, OrderWrt):
                 continue
@@ -367,18 +368,20 @@ class ModelState(object):
                     model._meta.label,
                     e,
                 ))
-        if not exclude_rels:
-            for field in model._meta.local_many_to_many:
-                name, path, args, kwargs = field.deconstruct()
-                field_class = import_string(path)
-                try:
-                    fields.append((name, field_class(*args, **kwargs)))
-                except TypeError as e:
-                    raise TypeError(""Couldn't reconstruct m2m field %s on %s: %s"" % (
-                        name,
-                        model._meta.object_name,
-                        e,
-                    ))
+        for field in model._meta.local_many_to_many:
+            if (exclude_rels and field.is_relation and
+                    _get_app_label_and_model_name(field.related_model)[0] not in allow_rels_to):
+                continue
+            name, path, args, kwargs = field.deconstruct()
+            field_class = import_string(path)
+            try:
+                fields.append((name, field_class(*args, **kwargs)))
+            except TypeError as e:
+                raise TypeError(""Couldn't reconstruct m2m field %s on %s: %s"" % (
+                    name,
+                    model._meta.object_name,
+                    e,
+                ))
         # Extract the options
         options = {}
         for name in DEFAULT_NAMES:
}}}

I believe this bug is also present on 1.8, haven't investigated though. If it is, it is I think it is a regression from 1.7 to 1.8."	Bug	closed	Migrations	1.8	Normal	duplicate			Unreviewed	0	0	0	0	0	0
