@ -1,3 +1,12 @@
|
|||||||
|
# 0.10.15
|
||||||
|
|
||||||
|
## 🐛 Fixes
|
||||||
|
|
||||||
|
* Fix generating pydantic models tree with nested models (by @pawamoy - thanks!) [#278](https://github.com/collerek/ormar/issues/278)
|
||||||
|
* Fix missing f-string in warning about missing primary key field [#274](https://github.com/collerek/ormar/issues/274)
|
||||||
|
* Fix passing foreign key value as relation (additional guard, fixed already in the latest release) [#270](https://github.com/collerek/ormar/issues/270)
|
||||||
|
|
||||||
|
|
||||||
# 0.10.14
|
# 0.10.14
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class UndefinedType: # pragma no cover
|
|||||||
|
|
||||||
Undefined = UndefinedType()
|
Undefined = UndefinedType()
|
||||||
|
|
||||||
__version__ = "0.10.14"
|
__version__ = "0.10.15"
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Integer",
|
"Integer",
|
||||||
"BigInteger",
|
"BigInteger",
|
||||||
|
|||||||
@ -152,7 +152,7 @@ def sqlalchemy_columns_from_model_fields(
|
|||||||
if len(model_fields.keys()) == 0:
|
if len(model_fields.keys()) == 0:
|
||||||
model_fields["id"] = ormar.Integer(name="id", primary_key=True)
|
model_fields["id"] = ormar.Integer(name="id", primary_key=True)
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Table {table_name} had no fields so auto "
|
f"Table {new_model.Meta.tablename} had no fields so auto "
|
||||||
"Integer primary key named `id` created."
|
"Integer primary key named `id` created."
|
||||||
)
|
)
|
||||||
validate_related_names_in_relations(model_fields, new_model)
|
validate_related_names_in_relations(model_fields, new_model)
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class PydanticMixin(RelationMixin):
|
|||||||
include=cls._skip_ellipsis(include, name),
|
include=cls._skip_ellipsis(include, name),
|
||||||
exclude=cls._skip_ellipsis(exclude, name),
|
exclude=cls._skip_ellipsis(exclude, name),
|
||||||
relation_map=cls._skip_ellipsis(
|
relation_map=cls._skip_ellipsis(
|
||||||
relation_map, field, default_return=dict()
|
relation_map, name, default_return=dict()
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if field.is_multi or field.virtual:
|
if field.is_multi or field.virtual:
|
||||||
|
|||||||
@ -121,7 +121,7 @@ class SavePrepareMixin(RelationMixin, AliasMixin):
|
|||||||
f"model without pk set!"
|
f"model without pk set!"
|
||||||
)
|
)
|
||||||
model_dict[field] = pk_value
|
model_dict[field] = pk_value
|
||||||
elif field_value: # nested dict
|
elif isinstance(field_value, (list, dict)) and field_value:
|
||||||
if isinstance(field_value, list):
|
if isinstance(field_value, list):
|
||||||
model_dict[field] = [
|
model_dict[field] = [
|
||||||
target.get(target_pkname) for target in field_value
|
target.get(target_pkname) for target in field_value
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
import databases
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
|
import ormar
|
||||||
|
from tests.settings import DATABASE_URL
|
||||||
|
|
||||||
|
metadata = sqlalchemy.MetaData()
|
||||||
|
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMeta(ormar.ModelMeta):
|
||||||
|
metadata = metadata
|
||||||
|
database = database
|
||||||
|
|
||||||
|
|
||||||
|
class Library(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
name: str = ormar.String(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class Package(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
library: Library = ormar.ForeignKey(Library, related_name="packages")
|
||||||
|
version: str = ormar.String(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class Ticket(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
number: int = ormar.Integer()
|
||||||
|
status: str = ormar.String(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class TicketPackage(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
status: str = ormar.String(max_length=100)
|
||||||
|
ticket: Ticket = ormar.ForeignKey(Ticket, related_name="packages")
|
||||||
|
package: Package = ormar.ForeignKey(Package, related_name="tickets")
|
||||||
|
|
||||||
|
|
||||||
|
def test_have_proper_children():
|
||||||
|
TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"})
|
||||||
|
assert "package" in TicketPackageOut.__fields__
|
||||||
|
PydanticPackage = TicketPackageOut.__fields__["package"].type_
|
||||||
|
assert "library" in PydanticPackage.__fields__
|
||||||
|
|
||||||
|
|
||||||
|
def test_casts_properly():
|
||||||
|
payload = {
|
||||||
|
"id": 0,
|
||||||
|
"status": "string",
|
||||||
|
"ticket": {"id": 0, "number": 0, "status": "string"},
|
||||||
|
"package": {
|
||||||
|
"version": "string",
|
||||||
|
"id": 0,
|
||||||
|
"library": {"id": 0, "name": "string"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
test_package = TicketPackage(**payload)
|
||||||
|
TicketPackageOut = TicketPackage.get_pydantic(exclude={"ticket"})
|
||||||
|
parsed = TicketPackageOut(**test_package.dict()).dict()
|
||||||
|
assert "ticket" not in parsed
|
||||||
|
assert "package" in parsed
|
||||||
|
assert "library" in parsed.get("package")
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
import uuid
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
import databases
|
||||||
|
import pytest
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
|
import ormar
|
||||||
|
from tests.settings import DATABASE_URL
|
||||||
|
|
||||||
|
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||||
|
metadata = sqlalchemy.MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMeta(ormar.ModelMeta):
|
||||||
|
metadata = metadata
|
||||||
|
database = database
|
||||||
|
|
||||||
|
|
||||||
|
class PageLink(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
tablename = "pagelinks"
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
value: str = ormar.String(max_length=2048)
|
||||||
|
country: str = ormar.String(max_length=1000)
|
||||||
|
|
||||||
|
|
||||||
|
class Post(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
tablename = "posts"
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
title: str = ormar.String(max_length=500)
|
||||||
|
link: PageLink = ormar.ForeignKey(
|
||||||
|
PageLink, related_name="posts", ondelete="CASCADE"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Department(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4())
|
||||||
|
name: str = ormar.String(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class Course(ormar.Model):
|
||||||
|
class Meta(BaseMeta):
|
||||||
|
pass
|
||||||
|
|
||||||
|
id: int = ormar.Integer(primary_key=True)
|
||||||
|
name: str = ormar.String(max_length=100)
|
||||||
|
completed: bool = ormar.Boolean(default=False)
|
||||||
|
department: Optional[Department] = ormar.ForeignKey(Department)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True, scope="module")
|
||||||
|
def create_test_database():
|
||||||
|
engine = sqlalchemy.create_engine(DATABASE_URL)
|
||||||
|
metadata.create_all(engine)
|
||||||
|
yield
|
||||||
|
metadata.drop_all(engine)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pass_int_values_as_fk():
|
||||||
|
async with database:
|
||||||
|
async with database.transaction(force_rollback=True):
|
||||||
|
link = await PageLink(id=1, value="test", country="USA").save()
|
||||||
|
await Post.objects.create(title="My post", link=link.id)
|
||||||
|
post_check = await Post.objects.select_related("link").get()
|
||||||
|
assert post_check.link == link
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pass_uuid_value_as_fk():
|
||||||
|
async with database:
|
||||||
|
async with database.transaction(force_rollback=True):
|
||||||
|
dept = await Department(name="Department test").save()
|
||||||
|
await Course(name="Test course", department=dept.id).save()
|
||||||
Reference in New Issue
Block a user