django/tests/model_fields/test_manytomanyfield.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

108 lines
3.7 KiB
Python
Raw Normal View History

from django.apps import apps
from django.db import models
from django.test import SimpleTestCase, TestCase
from django.test.utils import isolate_apps
from .models import ManyToMany
class ManyToManyFieldTests(SimpleTestCase):
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("Referred", through="Through")
class Meta:
app_label = "model_fields"
abstract = True
def assert_app_model_resolved(label):
class Referred(models.Model):
class Meta:
app_label = label
class Through(models.Model):
referred = models.ForeignKey("Referred", 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, Referred
)
self.assertEqual(ConcreteReferent.reference.through, Through)
assert_app_model_resolved("model_fields")
assert_app_model_resolved("tests")
def test_invalid_to_parameter(self):
msg = (
"ManyToManyField(1) is invalid. First parameter to "
"ManyToManyField must be either a model, a model name, or the "
"string 'self'"
)
with self.assertRaisesMessage(TypeError, msg):
class MyModel(models.Model):
m2m = models.ManyToManyField(1)
@isolate_apps("model_fields")
def test_through_db_table_mutually_exclusive(self):
class Child(models.Model):
pass
class Through(models.Model):
referred = models.ForeignKey(Child, on_delete=models.CASCADE)
referent = models.ForeignKey(Child, on_delete=models.CASCADE)
msg = "Cannot specify a db_table if an intermediary model is used."
with self.assertRaisesMessage(ValueError, msg):
class MyModel(models.Model):
m2m = models.ManyToManyField(
Child,
through="Through",
db_table="custom_name",
)
class ManyToManyFieldDBTests(TestCase):
def test_value_from_object_instance_without_pk(self):
obj = ManyToMany()
self.assertEqual(obj._meta.get_field("m2m").value_from_object(obj), [])
def test_value_from_object_instance_with_pk(self):
obj = ManyToMany.objects.create()
related_obj = ManyToMany.objects.create()
obj.m2m.add(related_obj)
self.assertEqual(
obj._meta.get_field("m2m").value_from_object(obj), [related_obj]
)