diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 572c274f5..3f64ef101 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,10 @@ Changelog 0.26.0 (unreleased) ------------------- +Changed +^^^^^ +- feat: foreignkey to model type (#2027) + 0.25 ==== diff --git a/examples/complex_filtering.py b/examples/complex_filtering.py index d9d1f2207..9e9508c53 100644 --- a/examples/complex_filtering.py +++ b/examples/complex_filtering.py @@ -23,7 +23,7 @@ class Event(Model): id = fields.IntField(primary_key=True) name = fields.TextField() tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events" + Tournament, related_name="events" ) participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team" diff --git a/examples/complex_prefetching.py b/examples/complex_prefetching.py index c458fecb4..0be720e1e 100644 --- a/examples/complex_prefetching.py +++ b/examples/complex_prefetching.py @@ -17,7 +17,7 @@ class Event(Model): id = fields.IntField(primary_key=True) name = fields.TextField() tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events" + Tournament, related_name="events" ) participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team" diff --git a/examples/functions.py b/examples/functions.py index 210aaac64..890d849fd 100644 --- a/examples/functions.py +++ b/examples/functions.py @@ -19,7 +19,7 @@ class Event(Model): id = fields.IntField(primary_key=True) name = fields.TextField() tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events" + Tournament, related_name="events" ) participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team" diff --git a/examples/global_table_name_generator.py b/examples/global_table_name_generator.py index 0bf43eb0c..4844651bf 100644 --- a/examples/global_table_name_generator.py +++ b/examples/global_table_name_generator.py @@ -26,7 +26,7 @@ class BlogPost(Model): id = fields.IntField(primary_key=True) title = fields.TextField() author: fields.ForeignKeyRelation[UserProfile] = fields.ForeignKeyField( - "models.UserProfile", related_name="posts" + UserProfile, related_name="posts" ) class Meta: diff --git a/examples/group_by.py b/examples/group_by.py index 7ca9b10fe..43a999c6d 100644 --- a/examples/group_by.py +++ b/examples/group_by.py @@ -5,14 +5,16 @@ class Author(Model): name = fields.CharField(max_length=255) + books: fields.ReverseRelation["Book"] + class Book(Model): name = fields.CharField(max_length=255) - author: fields.ForeignKeyRelation[Author] = fields.ForeignKeyField( - "models.Author", related_name="books" - ) + author: fields.ForeignKeyRelation[Author] = fields.ForeignKeyField(Author, related_name="books") rating = fields.FloatField() + author_id: int + async def run(): await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]}) diff --git a/examples/pydantic/basic.py b/examples/pydantic/basic.py index b7075c8f3..2e06ef8ca 100644 --- a/examples/pydantic/basic.py +++ b/examples/pydantic/basic.py @@ -23,7 +23,7 @@ class Event(Model): name = fields.TextField() created_at = fields.DatetimeField(auto_now_add=True) tournament: fields.ForeignKeyNullableRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events", null=True + Tournament, related_name="events", null=True ) participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team" @@ -40,7 +40,7 @@ class Address(Model): created_at = fields.DatetimeField(auto_now_add=True) event: fields.OneToOneRelation[Event] = fields.OneToOneField( - "models.Event", on_delete=fields.OnDelete.CASCADE, related_name="address", primary_key=True + Event, on_delete=fields.OnDelete.CASCADE, related_name="address", primary_key=True ) class Meta: diff --git a/examples/pydantic/early_init.py b/examples/pydantic/early_init.py index 5c791790d..8fd2e1076 100644 --- a/examples/pydantic/early_init.py +++ b/examples/pydantic/early_init.py @@ -23,7 +23,7 @@ class Event(Model): name = fields.TextField() created_at = fields.DatetimeField(auto_now_add=True) tournament: fields.ForeignKeyNullableRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events", null=True + Tournament, related_name="events", null=True ) class Meta: diff --git a/examples/pydantic/tutorial_3.py b/examples/pydantic/tutorial_3.py index 6c8ba40d4..580f04a11 100644 --- a/examples/pydantic/tutorial_3.py +++ b/examples/pydantic/tutorial_3.py @@ -32,7 +32,7 @@ class Event(Model): created_at = fields.DatetimeField(auto_now_add=True) tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events", description="The Tournament this happens in" + Tournament, related_name="events", description="The Tournament this happens in" ) diff --git a/examples/pydantic/tutorial_4.py b/examples/pydantic/tutorial_4.py index ecaa9b5ee..f732aec79 100644 --- a/examples/pydantic/tutorial_4.py +++ b/examples/pydantic/tutorial_4.py @@ -67,7 +67,7 @@ class Event(Model): created_at = fields.DatetimeField(auto_now_add=True) tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events", description="The Tournament this happens in" + Tournament, related_name="events", description="The Tournament this happens in" ) class Meta: diff --git a/examples/relations.py b/examples/relations.py index caf92fbf0..7a7557519 100644 --- a/examples/relations.py +++ b/examples/relations.py @@ -25,8 +25,9 @@ class Event(Model): id = fields.IntField(primary_key=True) name = fields.TextField() tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events" + Tournament, related_name="events" ) + # class Team does not defined before Event, so we have to use '{app}.{model_class}' participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team" ) @@ -40,7 +41,7 @@ class Address(Model): street = fields.CharField(max_length=128) event: fields.OneToOneRelation[Event] = fields.OneToOneField( - "models.Event", on_delete=fields.OnDelete.CASCADE, related_name="address", primary_key=True + Event, on_delete=fields.OnDelete.CASCADE, related_name="address", primary_key=True ) def __str__(self): diff --git a/examples/relations_with_unique.py b/examples/relations_with_unique.py index b45d7de2a..1fa042694 100644 --- a/examples/relations_with_unique.py +++ b/examples/relations_with_unique.py @@ -23,7 +23,7 @@ class Student(Model): id = fields.IntField(primary_key=True) name = fields.TextField() school: fields.ForeignKeyRelation[School] = fields.ForeignKeyField( - "models.School", related_name="students", to_field="id" + School, related_name="students", to_field="id" ) @@ -31,7 +31,7 @@ class Principal(Model): id = fields.IntField(primary_key=True) name = fields.TextField() school: fields.OneToOneRelation[School] = fields.OneToOneField( - "models.School", on_delete=fields.OnDelete.CASCADE, related_name="principal", to_field="id" + School, on_delete=fields.OnDelete.CASCADE, related_name="principal", to_field="id" ) diff --git a/examples/schema_create.py b/examples/schema_create.py index 40f7a5a47..3f4878409 100644 --- a/examples/schema_create.py +++ b/examples/schema_create.py @@ -22,7 +22,7 @@ class Event(Model): id = fields.IntField(primary_key=True, description="Event ID") name = fields.CharField(max_length=255, unique=True) tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events", description="FK to tournament" + Tournament, related_name="events", description="FK to tournament" ) participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", diff --git a/tests/test_relations.py b/tests/test_relations.py index f981413d1..bdc80be5d 100644 --- a/tests/test_relations.py +++ b/tests/test_relations.py @@ -1,3 +1,5 @@ +import subprocess # nosec + from tests.testmodels import ( Address, Author, @@ -501,3 +503,12 @@ async def test_reverse_relation_create_fk_errors_for_unsaved_instance(self): await tournament.events.create(name="Test Event") self.assertIn("hasn't been instanced", str(cm.exception)) + + @test.requireCapability(dialect="sqlite") + async def test_recursive(self) -> None: + file = "examples/relations_recursive.py" + r = subprocess.run(["python", file], capture_output=True, text=True) # nosec + assert not r.stderr + output = r.stdout + s = "2.1. Second H2 (to: ) (from: 2.2. Third H2, Loose, 1.1. First H2)" + self.assertIn(s, output) diff --git a/tests/testmodels.py b/tests/testmodels.py index c0b95f352..999a341f2 100644 --- a/tests/testmodels.py +++ b/tests/testmodels.py @@ -2,8 +2,6 @@ This is the testing Models """ -from __future__ import annotations - import binascii import datetime import os @@ -52,9 +50,7 @@ class Author(Model): class Book(Model): name = fields.CharField(max_length=255) - author: fields.ForeignKeyRelation[Author] = fields.ForeignKeyField( - "models.Author", related_name="books" - ) + author: fields.ForeignKeyRelation[Author] = fields.ForeignKeyField(Author, related_name="books") rating = fields.FloatField() subject = fields.CharField(max_length=255, null=True) @@ -73,9 +69,9 @@ class Tournament(Model): desc = fields.TextField(null=True) created = fields.DatetimeField(auto_now_add=True, db_index=True) - events: fields.ReverseRelation[Event] - minrelations: fields.ReverseRelation[MinRelation] - uniquetogetherfieldswithfks: fields.ReverseRelation[UniqueTogetherFieldsWithFK] + events: fields.ReverseRelation["Event"] + minrelations: fields.ReverseRelation["MinRelation"] + uniquetogetherfieldswithfks: fields.ReverseRelation["UniqueTogetherFieldsWithFK"] class PydanticMeta: exclude = ("minrelations", "uniquetogetherfieldswithfks") @@ -90,7 +86,7 @@ class Reporter(Model): id = fields.IntField(primary_key=True) name = fields.TextField() - events: fields.ReverseRelation[Event] + events: fields.ReverseRelation["Event"] class Meta: table = "re_port_er" @@ -107,12 +103,12 @@ class Event(Model): name = fields.TextField() #: What tournaments is a happenin' tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField( - "models.Tournament", related_name="events" + to="models.Tournament", related_name="events" ) reporter: fields.ForeignKeyNullableRelation[Reporter] = fields.ForeignKeyField( - "models.Reporter", null=True + to=Reporter, null=True ) - participants: fields.ManyToManyRelation[Team] = fields.ManyToManyField( + participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField( "models.Team", related_name="events", through="event_team", @@ -212,7 +208,7 @@ class Team(Model): name = fields.TextField() events: fields.ManyToManyRelation[Event] - minrelation_through: fields.ManyToManyRelation[MinRelation] + minrelation_through: fields.ManyToManyRelation["MinRelation"] alias = fields.IntField(null=True) class Meta: @@ -230,7 +226,7 @@ class EventTwo(Model): name = fields.TextField() tournament_id = fields.IntField() # Here we make link to events.Team, not models.Team - participants: fields.ManyToManyRelation[TeamTwo] = fields.ManyToManyField("events.TeamTwo") + participants: fields.ManyToManyRelation["TeamTwo"] = fields.ManyToManyField("events.TeamTwo") class Meta: app = "events" @@ -333,7 +329,7 @@ class FloatFields(Model): floatnum_null = fields.FloatField(null=True) -def raise_if_not_dict_or_list(value: dict | list): +def raise_if_not_dict_or_list(value: Union[dict, list]): # NOQA:FA100 if not isinstance(value, (dict, list)): raise ValidationError("Value must be a dict or list.") @@ -375,7 +371,7 @@ class MinRelation(Model): class M2MOne(Model): id = fields.IntField(primary_key=True) name = fields.CharField(max_length=255, null=True) - two: fields.ManyToManyRelation[M2MTwo] = fields.ManyToManyField( + two: fields.ManyToManyRelation["M2MTwo"] = fields.ManyToManyField( "models.M2MTwo", related_name="one" ) @@ -424,9 +420,9 @@ class ImplicitPkModel(Model): class UUIDPkModel(Model): id = fields.UUIDField(primary_key=True) - children: fields.ReverseRelation[UUIDFkRelatedModel] - children_null: fields.ReverseRelation[UUIDFkRelatedNullModel] - peers: fields.ManyToManyRelation[UUIDM2MRelatedModel] + children: fields.ReverseRelation["UUIDFkRelatedModel"] + children_null: fields.ReverseRelation["UUIDFkRelatedNullModel"] + peers: fields.ManyToManyRelation["UUIDM2MRelatedModel"] class UUIDFkRelatedModel(Model): @@ -557,15 +553,15 @@ class Meta: class Employee(Model): name = fields.CharField(max_length=50) - manager: fields.ForeignKeyNullableRelation[Employee] = fields.ForeignKeyField( + manager: fields.ForeignKeyNullableRelation["Employee"] = fields.ForeignKeyField( "models.Employee", related_name="team_members", null=True, on_delete=NO_ACTION ) - team_members: fields.ReverseRelation[Employee] + team_members: fields.ReverseRelation["Employee"] - talks_to: fields.ManyToManyRelation[Employee] = fields.ManyToManyField( + talks_to: fields.ManyToManyRelation["Employee"] = fields.ManyToManyField( "models.Employee", related_name="gets_talked_to", on_delete=NO_ACTION ) - gets_talked_to: fields.ManyToManyRelation[Employee] + gets_talked_to: fields.ManyToManyRelation["Employee"] def __str__(self): return self.name @@ -652,16 +648,16 @@ class StraightFields(Model): blip = fields.CharField(max_length=50, default="BLIP") nullable = fields.CharField(max_length=50, null=True) - fk: fields.ForeignKeyNullableRelation[StraightFields] = fields.ForeignKeyField( + fk: fields.ForeignKeyNullableRelation["StraightFields"] = fields.ForeignKeyField( "models.StraightFields", related_name="fkrev", null=True, description="Tree!", on_delete=NO_ACTION, ) - fkrev: fields.ReverseRelation[StraightFields] + fkrev: fields.ReverseRelation["StraightFields"] - o2o: fields.OneToOneNullableRelation[StraightFields] = fields.OneToOneField( + o2o: fields.OneToOneNullableRelation["StraightFields"] = fields.OneToOneField( "models.StraightFields", related_name="o2o_rev", null=True, @@ -670,13 +666,13 @@ class StraightFields(Model): ) o2o_rev: fields.Field - rel_to: fields.ManyToManyRelation[StraightFields] = fields.ManyToManyField( + rel_to: fields.ManyToManyRelation["StraightFields"] = fields.ManyToManyField( "models.StraightFields", related_name="rel_from", description="M2M to myself", on_delete=fields.NO_ACTION, ) - rel_from: fields.ManyToManyRelation[StraightFields] + rel_from: fields.ManyToManyRelation["StraightFields"] class Meta: unique_together = [["chars", "blip"]] @@ -700,7 +696,7 @@ class SourceFields(Model): blip = fields.CharField(max_length=50, default="BLIP", source_field="da_blip") nullable = fields.CharField(max_length=50, null=True, source_field="some_nullable") - fk: fields.ForeignKeyNullableRelation[SourceFields] = fields.ForeignKeyField( + fk: fields.ForeignKeyNullableRelation["SourceFields"] = fields.ForeignKeyField( "models.SourceFields", related_name="fkrev", null=True, @@ -708,9 +704,9 @@ class SourceFields(Model): description="Tree!", on_delete=NO_ACTION, ) - fkrev: fields.ReverseRelation[SourceFields] + fkrev: fields.ReverseRelation["SourceFields"] - o2o: fields.OneToOneNullableRelation[SourceFields] = fields.OneToOneField( + o2o: fields.OneToOneNullableRelation["SourceFields"] = fields.OneToOneField( "models.SourceFields", related_name="o2o_rev", null=True, @@ -720,7 +716,7 @@ class SourceFields(Model): ) o2o_rev: fields.Field - rel_to: fields.ManyToManyRelation[SourceFields] = fields.ManyToManyField( + rel_to: fields.ManyToManyRelation["SourceFields"] = fields.ManyToManyField( "models.SourceFields", related_name="rel_from", through="sometable_self", @@ -729,7 +725,7 @@ class SourceFields(Model): description="M2M to myself", on_delete=fields.NO_ACTION, ) - rel_from: fields.ManyToManyRelation[SourceFields] + rel_from: fields.ManyToManyRelation["SourceFields"] class Meta: table = "sometable" @@ -756,10 +752,10 @@ class EnumFields(Model): class DoubleFK(Model): name = fields.CharField(max_length=50) - left: fields.ForeignKeyNullableRelation[DoubleFK] = fields.ForeignKeyField( + left: fields.ForeignKeyNullableRelation["DoubleFK"] = fields.ForeignKeyField( "models.DoubleFK", null=True, related_name="left_rel", on_delete=NO_ACTION ) - right: fields.ForeignKeyNullableRelation[DoubleFK] = fields.ForeignKeyField( + right: fields.ForeignKeyNullableRelation["DoubleFK"] = fields.ForeignKeyField( "models.DoubleFK", null=True, related_name="right_rel", on_delete=NO_ACTION ) @@ -805,8 +801,8 @@ class School(Model): name = fields.TextField() id = fields.IntField(unique=True) - students: fields.ReverseRelation[Student] - principal: fields.ReverseRelation[Principal] + students: fields.ReverseRelation["Student"] + principal: fields.ReverseRelation["Principal"] class Student(Model): diff --git a/tortoise/__init__.py b/tortoise/__init__.py index fd22b902c..74d05b5ec 100644 --- a/tortoise/__init__.py +++ b/tortoise/__init__.py @@ -154,8 +154,12 @@ def init_fk_o2o_field(model: type[Model], field: str, is_o2o=False) -> None: fk_object = cast( "OneToOneFieldInstance | ForeignKeyFieldInstance", model._meta.fields_map[field] ) - related_app_name, related_model_name = split_reference(fk_object.model_name) - related_model = get_related_model(related_app_name, related_model_name) + reference = fk_object.model_name + if not isinstance(reference, str): + related_model: type[Model] = reference + else: + related_app_name, related_model_name = split_reference(reference) + related_model = get_related_model(related_app_name, related_model_name) if to_field := fk_object.to_field: related_field = related_model._meta.fields_map.get(to_field) @@ -248,8 +252,11 @@ def init_fk_o2o_field(model: type[Model], field: str, is_o2o=False) -> None: m2m_object.backward_key = backward_key reference = m2m_object.model_name - related_app_name, related_model_name = split_reference(reference) - related_model = get_related_model(related_app_name, related_model_name) + if not isinstance(reference, str): + related_model: type[Model] = reference + else: + related_app_name, related_model_name = split_reference(reference) + related_model = get_related_model(related_app_name, related_model_name) m2m_object.related_model = related_model diff --git a/tortoise/fields/relational.py b/tortoise/fields/relational.py index a68612b56..1f9c72fc9 100644 --- a/tortoise/fields/relational.py +++ b/tortoise/fields/relational.py @@ -2,15 +2,7 @@ import warnings from collections.abc import AsyncGenerator, Generator, Iterator -from typing import ( - TYPE_CHECKING, - Any, - Generic, - Literal, - Optional, - TypeVar, - overload, -) +from typing import TYPE_CHECKING, Any, Generic, Literal, Optional, TypeVar, overload from pypika_tortoise import Table @@ -306,8 +298,16 @@ def describe(self, serializable: bool) -> dict: return desc @classmethod - def validate_model_name(cls, model_name: str) -> None: - if len(model_name.split(".")) != 2: + def validate_model_name(cls, model_name: str | type[Model]) -> None: + if not isinstance(model_name, str): + model_class: type[Model] = model_name + try: + model_class._meta + except AttributeError: + raise ConfigurationError( + f"{cls.__name__}({model_name!r}) is invalid. model_name must be string or type[tortoise.models.Model]" + ) from None + elif len(model_name.split(".")) != 2: field_type = cls.__name__.replace("Instance", "") raise ConfigurationError(f'{field_type} accepts model name in format "app.Model"') @@ -315,7 +315,7 @@ def validate_model_name(cls, model_name: str) -> None: class ForeignKeyFieldInstance(RelationalField[MODEL]): def __init__( self, - model_name: str, + model_name: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, **kwargs: Any, @@ -358,7 +358,7 @@ def __init__( class OneToOneFieldInstance(ForeignKeyFieldInstance[MODEL]): def __init__( self, - model_name: str, + model_name: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, **kwargs: Any, @@ -375,7 +375,7 @@ class ManyToManyFieldInstance(RelationalField[MODEL]): def __init__( self, - model_name: str, + model_name: type[Model] | str, through: str | None = None, forward_key: str | None = None, backward_key: str = "", @@ -396,9 +396,14 @@ def __init__( unique = kwargs.pop("create_unique_index") super().__init__(field_type, unique=unique, **kwargs) self.validate_model_name(model_name) - self.model_name: str = model_name + self.model_name = model_name self.related_name: str = related_name - self.forward_key: str = forward_key or f"{model_name.split('.')[1].lower()}_id" + if not forward_key: + if not isinstance(model_name, str): + forward_key = f"{model_name.__name__.lower()}_id" + else: + forward_key = f"{model_name.split('.')[1].lower()}_id" + self.forward_key: str = forward_key self.backward_key: str = backward_key self.through: str = through # type: ignore self._generated: bool = False @@ -406,7 +411,12 @@ def __init__( def describe(self, serializable: bool) -> dict: desc = super().describe(serializable) - desc["model_name"] = self.model_name + if isinstance(self.model_name, str): + model_name = self.model_name + else: + model: type[Model] = self.model_name + model_name = f"{model._meta.app}.{model.__name__}" + desc["model_name"] = model_name desc["related_name"] = self.related_name desc["forward_key"] = self.forward_key desc["backward_key"] = self.backward_key @@ -418,7 +428,7 @@ def describe(self, serializable: bool) -> dict: @overload def OneToOneField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -430,7 +440,7 @@ def OneToOneField( @overload def OneToOneField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -440,7 +450,7 @@ def OneToOneField( def OneToOneField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -456,8 +466,8 @@ def OneToOneField( You must provide the following: - ``model_name``: - The name of the related model in a :samp:`'{app}.{model}'` format. + ``to``: + The related model or name of the related model in a :samp:`'{app}.{model}'` format. The following is optional: @@ -487,13 +497,13 @@ def OneToOneField( """ return OneToOneFieldInstance( - model_name, related_name, on_delete, db_constraint=db_constraint, null=null, **kwargs + to, related_name, on_delete, db_constraint=db_constraint, null=null, **kwargs ) @overload def ForeignKeyField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -505,7 +515,7 @@ def ForeignKeyField( @overload def ForeignKeyField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -515,7 +525,7 @@ def ForeignKeyField( def ForeignKeyField( - model_name: str, + to: type[Model] | str, related_name: str | None | Literal[False] = None, on_delete: OnDelete = CASCADE, db_constraint: bool = True, @@ -531,8 +541,8 @@ def ForeignKeyField( You must provide the following: - ``model_name``: - The name of the related model in a :samp:`'{app}.{model}'` format. + ``to``: + The related model or name of the related model in a :samp:`'{app}.{model}'` format. The following is optional: @@ -562,12 +572,12 @@ def ForeignKeyField( """ return ForeignKeyFieldInstance( - model_name, related_name, on_delete, db_constraint=db_constraint, null=null, **kwargs + to, related_name, on_delete, db_constraint=db_constraint, null=null, **kwargs ) def ManyToManyField( - model_name: str, + to: type[Model] | str, through: str | None = None, forward_key: str | None = None, backward_key: str = "", @@ -586,8 +596,8 @@ def ManyToManyField( You must provide the following: - ``model_name``: - The name of the related model in a :samp:`'{app}.{model}'` format. + ``to``: + The related model or name of the related model in a :samp:`'{app}.{model}'` format. The following is optional: @@ -625,7 +635,7 @@ def ManyToManyField( The default is True. If you want to allow repeat records, set this to False. """ return ManyToManyFieldInstance( # type: ignore - model_name, + to, through, forward_key, backward_key,