Repository: django/django
File: tests/foreign_object/tests.py (Python)

Code before:
        self.assertIn("path_infos", foreign_object_rel.__dict__)
        foreign_object_rel_restored = pickle.loads(pickle.dumps(foreign_object_rel))
        self.assertNotIn("path_infos", foreign_object_rel_restored.__dict__)

    def test_pickling_foreignobject(self):
        """
        Pickling a ForeignObject does not remove the cached PathInfo values.

        ForeignObject will always keep the path_infos and reverse_path_infos
        attributes within the same process, because of the way
        Field.__reduce__() is used for restoring values.
        """
        foreign_object = Membership._meta.get_field("person")
        # Trigger storage of cached_property into ForeignObjectRel's __dict__
        foreign_object.path_infos
        foreign_object.reverse_path_infos
        self.assertIn("path_infos", foreign_object.__dict__)
        self.assertIn("reverse_path_infos", foreign_object.__dict__)
        foreign_object_restored = pickle.loads(pickle.dumps(foreign_object))
        self.assertIn("path_infos", foreign_object_restored.__dict__)
        self.assertIn("reverse_path_infos", foreign_object_restored.__dict__)


class ForeignObjectModelValidationTests(TestCase):
    def setUp(self):
        CustomerTab._meta.constraints = [
            models.CheckConstraint(
                condition=Q(customer__lt=1000),
                name="customer_id_limit",
            )
        ]

    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_with_foreign_object(self):
        customer_tab = CustomerTab(customer_id=1500)
        with self.assertRaisesMessage(ValidationError, "customer_id_limit"):
            customer_tab.validate_constraints()

    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_success_case_single_query(self):
        customer_tab = CustomerTab(customer_id=500)
        with CaptureQueriesContext(connection) as ctx:
            customer_tab.validate_constraints()
        select_queries = [
            query["sql"]
            for query in ctx.captured_queries
            if "select" in query["sql"].lower()
        ]
        self.assertEqual(len(select_queries), 1)

    @skipUnlessDBFeature("supports_table_check_constraints")

Review comment (suggestion):
I bet we could move these to `invalid_models_tests.test_models.ConstraintsTests` to avoid the hack, but I didn't look too closely.

Code after:
        self.assertNotIn("path_infos", foreign_object_rel_restored.__dict__)

    def test_pickling_foreignobject(self):
        """
        Pickling a ForeignObject does not remove the cached PathInfo values.

        ForeignObject will always keep the path_infos and reverse_path_infos
        attributes within the same process, because of the way
        Field.__reduce__() is used for restoring values.
        """
        foreign_object = Membership._meta.get_field("person")
        # Trigger storage of cached_property into ForeignObjectRel's __dict__
        foreign_object.path_infos
        foreign_object.reverse_path_infos
        self.assertIn("path_infos", foreign_object.__dict__)
        self.assertIn("reverse_path_infos", foreign_object.__dict__)
        foreign_object_restored = pickle.loads(pickle.dumps(foreign_object))
        self.assertIn("path_infos", foreign_object_restored.__dict__)
        self.assertIn("reverse_path_infos", foreign_object_restored.__dict__)


class ForeignObjectModelValidationTests(TestCase):
    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_with_foreign_object(self):
        customer_tab = CustomerTab(customer_id=1500)
        with self.assertRaisesMessage(ValidationError, "customer_id_limit"):
            customer_tab.validate_constraints()

    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_success_case_single_query(self):
        customer_tab = CustomerTab(customer_id=500)
        with CaptureQueriesContext(connection) as ctx:
            customer_tab.validate_constraints()
        select_queries = [
            query["sql"]
            for query in ctx.captured_queries
            if "select" in query["sql"].lower()
        ]
        self.assertEqual(len(select_queries), 1)

    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_excluding_foreign_object(self):
        customer_tab = CustomerTab(customer_id=150)
        customer_tab.validate_constraints(exclude={"customer"})

    @skipUnlessDBFeature("supports_table_check_constraints")
    def test_validate_constraints_excluding_foreign_object_member(self):
        customer_tab = CustomerTab(customer_id=150)
        customer_tab.validate_constraints(exclude={"customer_id"})