a lazy callable may be used for foreignkey default a foo objects createid1 aabc ddecimal12 34 b bar objects createbbcd self assertequalb a a skipifdbfeatureinterpretsemptystringsasnulls def testemptystringfkself charmodelempty primarykeycharmodel objects createstring fkmodelempty fktochar objects createoutcharmodelempty fkmodelempty fktochar objects selectrelatedout get idfkmodelempty pk self assertequalfkmodelempty out charmodelempty isolateappsmodelfields def testwarningwhenuniquetrueonfkself class foomodels model pass class fkuniquetruemodels model fkfield models foreignkeyfoo models cascade uniquetrue model fkuniquetrue expectedwarnings checks warning setting uniquetrue on a foreignkey has the same effect as using a onetoonefield hint foreignkeyuniquetrue is usually better served by a onetoonefield objfkuniquetrue fkfield field idfields w342 warnings model check self assertequalwarnings expectedwarnings def testrelatednameconvertedtotextself relname bar meta getfielda remotefield relatedname self assertisinstancerelname str def testabstractmodelpendingoperationsself pendingopsbefore listapps pendingoperations items class abstractforeignkeymodelmodels model fk models foreignkeymissing fk models cascade class meta abstract true self assertisabstractforeignkeymodel meta apps apps self assertequal pendingopsbefore listapps pendingoperations items pending lookup added for a foreign key on an abstract model isolateappsmodelfields modelfields tests def testabstractmodelapprelativeforeignkeyself class abstractreferentmodels model reference models foreignkeyreferred ondeletemodels cascade class meta applabel modelfields abstract true def assertappmodelresolvedlabel class referredmodels model class meta applabel label class concretereferentabstractreferent class meta applabel label self assertequal concretereferent meta getfieldreference relatedmodel referred assertappmodelresolvedmodelfields assertappmodelresolvedtests isolateappsmodelfields def testtopythonself class foomodels model pass class barmodels model fk models foreignkeyfoo models cascade self assertequalbar meta getfieldfk topython1 1 isolateappsmodelfields def testfktofkgetcoloutputfieldself class foomodels model pass class barmodels model foo models foreignkeyfoo models cascade primarykeytrue class bazmodels model bar models foreignkeybar models cascade primarykeytrue col baz meta getfieldbar getcolalias self assertiscol outputfield foo meta pk isolateappsmodelfields def testrecursivefksgetcolself class foomodels model bar models foreignkeybar models cascade primarykeytrue class barmodels model foo models foreignkeyfoo models cascade primarykeytrue with self assertraisesmessagevalueerror cannot resolve outputfield foo meta getfieldbar getcolalias isolateappsmodelfields def testnonlocaltofieldself class parentmodels model key models integerfielduniquetrue class childparent pass class relatedmodels model child models foreignkeychild ondeletemodels cascade tofieldkey msg modelfields related child refers to field key which is not local to model modelfields child with self assertraisesmessagefielderror msg related meta getfieldchild relatedfields def testinvalidtoparameterself msg foreignkey1 is invalid first parameter to foreignkey must be either a model a model name or the string self with self assertraisesmessagetypeerror msg class mymodelmodels model child models foreignkey1 models cascade def testmanagerclassgetitemself self assertismodels foreignkeyfoo models foreignkey a lazy callable may be used for foreignkey default empty strings foreign key values don t get converted to none 19299 foreign key fields declared on abstract models should not add lazy relations to resolve relationship declared as string 24215
from decimal import Decimal

from django.apps import apps
from django.core import checks
from django.core.exceptions import FieldError
from django.db import models
from django.test import TestCase, skipIfDBFeature
from django.test.utils import isolate_apps

from .models import Bar, FkToChar, Foo, PrimaryKeyCharModel


class ForeignKeyTests(TestCase):
    def test_callable_default(self):
        
        a = Foo.objects.create(id=1, a="abc", d=Decimal("12.34"))
        b = Bar.objects.create(b="bcd")
        self.assertEqual(b.a, a)

    @skipIfDBFeature("interprets_empty_strings_as_nulls")
    def test_empty_string_fk(self):
        
        char_model_empty = PrimaryKeyCharModel.objects.create(string="")
        fk_model_empty = FkToChar.objects.create(out=char_model_empty)
        fk_model_empty = FkToChar.objects.select_related("out").get(
            id=fk_model_empty.pk
        )
        self.assertEqual(fk_model_empty.out, char_model_empty)

    @isolate_apps("model_fields")
    def test_warning_when_unique_true_on_fk(self):
        class Foo(models.Model):
            pass

        class FKUniqueTrue(models.Model):
            fk_field = models.ForeignKey(Foo, models.CASCADE, unique=True)

        model = FKUniqueTrue()
        expected_warnings = [
            checks.Warning(
                "Setting unique=True on a ForeignKey has the same effect as using a "
                "OneToOneField.",
                hint=(
                    "ForeignKey(unique=True) is usually better served by a "
                    "OneToOneField."
                ),
                obj=FKUniqueTrue.fk_field.field,
                id="fields.W342",
            )
        ]
        warnings = model.check()
        self.assertEqual(warnings, expected_warnings)

    def test_related_name_converted_to_text(self):
        rel_name = Bar._meta.get_field("a").remote_field.related_name
        self.assertIsInstance(rel_name, str)

    def test_abstract_model_pending_operations(self):
        
        pending_ops_before = list(apps._pending_operations.items())

        class AbstractForeignKeyModel(models.Model):
            fk = models.ForeignKey("missing.FK", models.CASCADE)

            class Meta:
                abstract = True

        self.assertIs(AbstractForeignKeyModel._meta.apps, apps)
        self.assertEqual(
            pending_ops_before,
            list(apps._pending_operations.items()),
            "Pending lookup added for a foreign key 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.ForeignKey("Referred", on_delete=models.CASCADE)

            class Meta:
                app_label = "model_fields"
                abstract = True

        def assert_app_model_resolved(label):
            class Referred(models.Model):
                class Meta:
                    app_label = label

            class ConcreteReferent(AbstractReferent):
                class Meta:
                    app_label = label

            self.assertEqual(
                ConcreteReferent._meta.get_field("reference").related_model, Referred
            )

        assert_app_model_resolved("model_fields")
        assert_app_model_resolved("tests")

    @isolate_apps("model_fields")
    def test_to_python(self):
        class Foo(models.Model):
            pass

        class Bar(models.Model):
            fk = models.ForeignKey(Foo, models.CASCADE)

        self.assertEqual(Bar._meta.get_field("fk").to_python("1"), 1)

    @isolate_apps("model_fields")
    def test_fk_to_fk_get_col_output_field(self):
        class Foo(models.Model):
            pass

        class Bar(models.Model):
            foo = models.ForeignKey(Foo, models.CASCADE, primary_key=True)

        class Baz(models.Model):
            bar = models.ForeignKey(Bar, models.CASCADE, primary_key=True)

        col = Baz._meta.get_field("bar").get_col("alias")
        self.assertIs(col.output_field, Foo._meta.pk)

    @isolate_apps("model_fields")
    def test_recursive_fks_get_col(self):
        class Foo(models.Model):
            bar = models.ForeignKey("Bar", models.CASCADE, primary_key=True)

        class Bar(models.Model):
            foo = models.ForeignKey(Foo, models.CASCADE, primary_key=True)

        with self.assertRaisesMessage(ValueError, "Cannot resolve output_field"):
            Foo._meta.get_field("bar").get_col("alias")

    @isolate_apps("model_fields")
    def test_non_local_to_field(self):
        class Parent(models.Model):
            key = models.IntegerField(unique=True)

        class Child(Parent):
            pass

        class Related(models.Model):
            child = models.ForeignKey(Child, on_delete=models.CASCADE, to_field="key")

        msg = (
            "'model_fields.Related.child' refers to field 'key' which is not "
            "local to model 'model_fields.Child'."
        )
        with self.assertRaisesMessage(FieldError, msg):
            Related._meta.get_field("child").related_fields

    def test_invalid_to_parameter(self):
        msg = (
            "ForeignKey(1) is invalid. First parameter to ForeignKey must be "
            "either a model, a model name, or the string 'self'"
        )
        with self.assertRaisesMessage(TypeError, msg):

            class MyModel(models.Model):
                child = models.ForeignKey(1, models.CASCADE)

    def test_manager_class_getitem(self):
        self.assertIs(models.ForeignKey["Foo"], models.ForeignKey)