from django.apps import apps from django.db import models from django.test import SimpleTestCase from django.test.utils import isolate_apps class ManyToManyFieldTests(SimpleTestCase): @isolate_apps('model_fields') def test_value_from_object_instance_without_pk(self): class ManyToManyModel(models.Model): m2m = models.ManyToManyField('self', models.CASCADE) instance = ManyToManyModel() qs = instance._meta.get_field('m2m').value_from_object(instance) self.assertEqual(qs.model, ManyToManyModel) self.assertEqual(list(qs), []) def test_abstract_model_pending_operations(self): """ Many-to-many fields declared on abstract models should not add lazy relations to resolve relationship declared as string (#24215). """ pending_ops_before = list(apps._pending_operations.items()) class AbstractManyToManyModel(models.Model): fk = models.ForeignKey('missing.FK', models.CASCADE) class Meta: abstract = True self.assertIs(AbstractManyToManyModel._meta.apps, apps) self.assertEqual( pending_ops_before, list(apps._pending_operations.items()), 'Pending lookup added for a many-to-many field on an abstract model' ) @isolate_apps('model_fields', 'model_fields.tests') def test_abstract_model_app_relative_foreign_key(self): class AbstractReferent(models.Model): reference = models.ManyToManyField('Refered', through='Through') class Meta: app_label = 'model_fields' abstract = True def assert_app_model_resolved(label): class Refered(models.Model): class Meta: app_label = label class Through(models.Model): refered = models.ForeignKey('Refered', on_delete=models.CASCADE) referent = models.ForeignKey('ConcreteReferent', on_delete=models.CASCADE) class Meta: app_label = label class ConcreteReferent(AbstractReferent): class Meta: app_label = label self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Refered) self.assertEqual(ConcreteReferent.reference.through, Through) assert_app_model_resolved('model_fields') assert_app_model_resolved('tests')