switch from class to instance fro fields
This commit is contained in:
@ -12,7 +12,7 @@ if TYPE_CHECKING: # pragma no cover
|
||||
from ormar.fields import BaseField
|
||||
|
||||
|
||||
def is_field_an_forward_ref(field: Type["BaseField"]) -> bool:
|
||||
def is_field_an_forward_ref(field: "BaseField") -> bool:
|
||||
"""
|
||||
Checks if field is a relation field and whether any of the referenced models
|
||||
are ForwardRefs that needs to be updated before proceeding.
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import warnings
|
||||
from typing import Dict, Optional, TYPE_CHECKING, Tuple, Type
|
||||
|
||||
import pydantic
|
||||
from pydantic.fields import ModelField
|
||||
from pydantic.utils import lenient_issubclass
|
||||
|
||||
import ormar # noqa: I100, I202
|
||||
from ormar.fields import BaseField
|
||||
from ormar.fields import BaseField # noqa: I100, I202
|
||||
|
||||
if TYPE_CHECKING: # pragma no cover
|
||||
from ormar import Model
|
||||
@ -14,7 +12,7 @@ if TYPE_CHECKING: # pragma no cover
|
||||
|
||||
|
||||
def create_pydantic_field(
|
||||
field_name: str, model: Type["Model"], model_field: Type["ManyToManyField"]
|
||||
field_name: str, model: Type["Model"], model_field: "ManyToManyField"
|
||||
) -> None:
|
||||
"""
|
||||
Registers pydantic field on through model that leads to passed model
|
||||
@ -59,38 +57,6 @@ def get_pydantic_field(field_name: str, model: Type["Model"]) -> "ModelField":
|
||||
)
|
||||
|
||||
|
||||
def populate_default_pydantic_field_value(
|
||||
ormar_field: Type["BaseField"], field_name: str, attrs: dict
|
||||
) -> dict:
|
||||
"""
|
||||
Grabs current value of the ormar Field in class namespace
|
||||
(so the default_value declared on ormar model if set)
|
||||
and converts it to pydantic.FieldInfo
|
||||
that pydantic is able to extract later.
|
||||
|
||||
On FieldInfo there are saved all needed params like max_length of the string
|
||||
and other constraints that pydantic can use to build
|
||||
it's own field validation used by ormar.
|
||||
|
||||
:param ormar_field: field to convert
|
||||
:type ormar_field: ormar Field
|
||||
:param field_name: field to convert name
|
||||
:type field_name: str
|
||||
:param attrs: current class namespace
|
||||
:type attrs: Dict
|
||||
:return: updated namespace dict
|
||||
:rtype: Dict
|
||||
"""
|
||||
curr_def_value = attrs.get(field_name, ormar.Undefined)
|
||||
if lenient_issubclass(curr_def_value, ormar.fields.BaseField):
|
||||
curr_def_value = ormar.Undefined
|
||||
if curr_def_value is None:
|
||||
attrs[field_name] = ormar_field.convert_to_pydantic_field_info(allow_null=True)
|
||||
else:
|
||||
attrs[field_name] = ormar_field.convert_to_pydantic_field_info()
|
||||
return attrs
|
||||
|
||||
|
||||
def populate_pydantic_default_values(attrs: Dict) -> Tuple[Dict, Dict]:
|
||||
"""
|
||||
Extracts ormar fields from annotations (deprecated) and from namespace
|
||||
@ -110,22 +76,11 @@ def populate_pydantic_default_values(attrs: Dict) -> Tuple[Dict, Dict]:
|
||||
:rtype: Tuple[Dict, Dict]
|
||||
"""
|
||||
model_fields = {}
|
||||
potential_fields = {
|
||||
k: v
|
||||
for k, v in attrs["__annotations__"].items()
|
||||
if lenient_issubclass(v, BaseField)
|
||||
}
|
||||
if potential_fields:
|
||||
warnings.warn(
|
||||
"Using ormar.Fields as type Model annotation has been deprecated,"
|
||||
" check documentation of current version",
|
||||
DeprecationWarning,
|
||||
)
|
||||
potential_fields = {}
|
||||
|
||||
potential_fields.update(get_potential_fields(attrs))
|
||||
for field_name, field in potential_fields.items():
|
||||
field.name = field_name
|
||||
attrs = populate_default_pydantic_field_value(field, field_name, attrs)
|
||||
model_fields[field_name] = field
|
||||
attrs["__annotations__"][field_name] = (
|
||||
field.__type__ if not field.nullable else Optional[field.__type__]
|
||||
@ -156,4 +111,8 @@ def get_potential_fields(attrs: Dict) -> Dict:
|
||||
:return: extracted fields that are ormar Fields
|
||||
:rtype: Dict
|
||||
"""
|
||||
return {k: v for k, v in attrs.items() if lenient_issubclass(v, BaseField)}
|
||||
return {
|
||||
k: v
|
||||
for k, v in attrs.items()
|
||||
if (lenient_issubclass(v, BaseField) or isinstance(v, BaseField))
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ if TYPE_CHECKING: # pragma no cover
|
||||
alias_manager = AliasManager()
|
||||
|
||||
|
||||
def register_relation_on_build(field: Type["ForeignKeyField"]) -> None:
|
||||
def register_relation_on_build(field: "ForeignKeyField") -> None:
|
||||
"""
|
||||
Registers ForeignKey relation in alias_manager to set a table_prefix.
|
||||
Registration include also reverse relation side to be able to join both sides.
|
||||
@ -32,7 +32,7 @@ def register_relation_on_build(field: Type["ForeignKeyField"]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def register_many_to_many_relation_on_build(field: Type["ManyToManyField"]) -> None:
|
||||
def register_many_to_many_relation_on_build(field: "ManyToManyField") -> None:
|
||||
"""
|
||||
Registers connection between through model and both sides of the m2m relation.
|
||||
Registration include also reverse relation side to be able to join both sides.
|
||||
@ -58,7 +58,7 @@ def register_many_to_many_relation_on_build(field: Type["ManyToManyField"]) -> N
|
||||
)
|
||||
|
||||
|
||||
def expand_reverse_relationship(model_field: Type["ForeignKeyField"]) -> None:
|
||||
def expand_reverse_relationship(model_field: "ForeignKeyField") -> None:
|
||||
"""
|
||||
If the reverse relation has not been set before it's set here.
|
||||
|
||||
@ -84,11 +84,11 @@ def expand_reverse_relationships(model: Type["Model"]) -> None:
|
||||
model_fields = list(model.Meta.model_fields.values())
|
||||
for model_field in model_fields:
|
||||
if model_field.is_relation and not model_field.has_unresolved_forward_refs():
|
||||
model_field = cast(Type["ForeignKeyField"], model_field)
|
||||
model_field = cast("ForeignKeyField", model_field)
|
||||
expand_reverse_relationship(model_field=model_field)
|
||||
|
||||
|
||||
def register_reverse_model_fields(model_field: Type["ForeignKeyField"]) -> None:
|
||||
def register_reverse_model_fields(model_field: "ForeignKeyField") -> None:
|
||||
"""
|
||||
Registers reverse ForeignKey field on related model.
|
||||
By default it's name.lower()+'s' of the model on which relation is defined.
|
||||
@ -113,7 +113,7 @@ def register_reverse_model_fields(model_field: Type["ForeignKeyField"]) -> None:
|
||||
orders_by=model_field.related_orders_by,
|
||||
)
|
||||
# register foreign keys on through model
|
||||
model_field = cast(Type["ManyToManyField"], model_field)
|
||||
model_field = cast("ManyToManyField", model_field)
|
||||
register_through_shortcut_fields(model_field=model_field)
|
||||
adjust_through_many_to_many_model(model_field=model_field)
|
||||
else:
|
||||
@ -128,7 +128,7 @@ def register_reverse_model_fields(model_field: Type["ForeignKeyField"]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def register_through_shortcut_fields(model_field: Type["ManyToManyField"]) -> None:
|
||||
def register_through_shortcut_fields(model_field: "ManyToManyField") -> None:
|
||||
"""
|
||||
Registers m2m relation through shortcut on both ends of the relation.
|
||||
|
||||
@ -156,7 +156,7 @@ def register_through_shortcut_fields(model_field: Type["ManyToManyField"]) -> No
|
||||
)
|
||||
|
||||
|
||||
def register_relation_in_alias_manager(field: Type["ForeignKeyField"]) -> None:
|
||||
def register_relation_in_alias_manager(field: "ForeignKeyField") -> None:
|
||||
"""
|
||||
Registers the relation (and reverse relation) in alias manager.
|
||||
The m2m relations require registration of through model between
|
||||
@ -172,7 +172,7 @@ def register_relation_in_alias_manager(field: Type["ForeignKeyField"]) -> None:
|
||||
if field.is_multi:
|
||||
if field.has_unresolved_forward_refs():
|
||||
return
|
||||
field = cast(Type["ManyToManyField"], field)
|
||||
field = cast("ManyToManyField", field)
|
||||
register_many_to_many_relation_on_build(field=field)
|
||||
elif field.is_relation and not field.is_through:
|
||||
if field.has_unresolved_forward_refs():
|
||||
@ -181,7 +181,7 @@ def register_relation_in_alias_manager(field: Type["ForeignKeyField"]) -> None:
|
||||
|
||||
|
||||
def verify_related_name_dont_duplicate(
|
||||
related_name: str, model_field: Type["ForeignKeyField"]
|
||||
related_name: str, model_field: "ForeignKeyField"
|
||||
) -> None:
|
||||
"""
|
||||
Verifies whether the used related_name (regardless of the fact if user defined or
|
||||
@ -213,7 +213,7 @@ def verify_related_name_dont_duplicate(
|
||||
)
|
||||
|
||||
|
||||
def reverse_field_not_already_registered(model_field: Type["ForeignKeyField"]) -> bool:
|
||||
def reverse_field_not_already_registered(model_field: "ForeignKeyField") -> bool:
|
||||
"""
|
||||
Checks if child is already registered in parents pydantic fields.
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ if TYPE_CHECKING: # pragma no cover
|
||||
from ormar.models import NewBaseModel
|
||||
|
||||
|
||||
def adjust_through_many_to_many_model(model_field: Type["ManyToManyField"]) -> None:
|
||||
def adjust_through_many_to_many_model(model_field: "ManyToManyField") -> None:
|
||||
"""
|
||||
Registers m2m relation on through model.
|
||||
Sets ormar.ForeignKey from through model to both child and parent models.
|
||||
@ -52,7 +52,7 @@ def adjust_through_many_to_many_model(model_field: Type["ManyToManyField"]) -> N
|
||||
|
||||
|
||||
def create_and_append_m2m_fk(
|
||||
model: Type["Model"], model_field: Type["ManyToManyField"], field_name: str
|
||||
model: Type["Model"], model_field: "ManyToManyField", field_name: str
|
||||
) -> None:
|
||||
"""
|
||||
Registers sqlalchemy Column with sqlalchemy.ForeignKey leading to the model.
|
||||
@ -190,22 +190,22 @@ def _process_fields(
|
||||
return pkname, columns
|
||||
|
||||
|
||||
def _is_through_model_not_set(field: Type["BaseField"]) -> bool:
|
||||
def _is_through_model_not_set(field: "BaseField") -> bool:
|
||||
"""
|
||||
Alias to if check that verifies if through model was created.
|
||||
:param field: field to check
|
||||
:type field: Type["BaseField"]
|
||||
:type field: "BaseField"
|
||||
:return: result of the check
|
||||
:rtype: bool
|
||||
"""
|
||||
return field.is_multi and not field.through
|
||||
|
||||
|
||||
def _is_db_field(field: Type["BaseField"]) -> bool:
|
||||
def _is_db_field(field: "BaseField") -> bool:
|
||||
"""
|
||||
Alias to if check that verifies if field should be included in database.
|
||||
:param field: field to check
|
||||
:type field: Type["BaseField"]
|
||||
:type field: "BaseField"
|
||||
:return: result of the check
|
||||
:rtype: bool
|
||||
"""
|
||||
@ -298,7 +298,7 @@ def populate_meta_sqlalchemy_table_if_required(meta: "ModelMeta") -> None:
|
||||
|
||||
|
||||
def update_column_definition(
|
||||
model: Union[Type["Model"], Type["NewBaseModel"]], field: Type["ForeignKeyField"]
|
||||
model: Union[Type["Model"], Type["NewBaseModel"]], field: "ForeignKeyField"
|
||||
) -> None:
|
||||
"""
|
||||
Updates a column with a new type column based on updated parameters in FK fields.
|
||||
@ -306,7 +306,7 @@ def update_column_definition(
|
||||
:param model: model on which columns needs to be updated
|
||||
:type model: Type["Model"]
|
||||
:param field: field with column definition that requires update
|
||||
:type field: Type[ForeignKeyField]
|
||||
:type field: ForeignKeyField
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
@ -20,7 +20,7 @@ if TYPE_CHECKING: # pragma no cover
|
||||
from ormar import Model
|
||||
|
||||
|
||||
def check_if_field_has_choices(field: Type[BaseField]) -> bool:
|
||||
def check_if_field_has_choices(field: BaseField) -> bool:
|
||||
"""
|
||||
Checks if given field has choices populated.
|
||||
A if it has one, a validator for this field needs to be attached.
|
||||
@ -34,7 +34,7 @@ def check_if_field_has_choices(field: Type[BaseField]) -> bool:
|
||||
|
||||
|
||||
def convert_choices_if_needed( # noqa: CCR001
|
||||
field: Type["BaseField"], value: Any
|
||||
field: "BaseField", value: Any
|
||||
) -> Tuple[Any, List]:
|
||||
"""
|
||||
Converts dates to isoformat as fastapi can check this condition in routes
|
||||
@ -47,7 +47,7 @@ def convert_choices_if_needed( # noqa: CCR001
|
||||
Converts decimal to float with given scale.
|
||||
|
||||
:param field: ormar field to check with choices
|
||||
:type field: Type[BaseField]
|
||||
:type field: BaseField
|
||||
:param values: current values of the model to verify
|
||||
:type values: Dict
|
||||
:return: value, choices list
|
||||
@ -77,13 +77,13 @@ def convert_choices_if_needed( # noqa: CCR001
|
||||
return value, choices
|
||||
|
||||
|
||||
def validate_choices(field: Type["BaseField"], value: Any) -> None:
|
||||
def validate_choices(field: "BaseField", value: Any) -> None:
|
||||
"""
|
||||
Validates if given value is in provided choices.
|
||||
|
||||
:raises ValueError: If value is not in choices.
|
||||
:param field:field to validate
|
||||
:type field: Type[BaseField]
|
||||
:type field: BaseField
|
||||
:param value: value of the field
|
||||
:type value: Any
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user