merge from master, simplify props in meta inheritance
This commit is contained in:
@ -8,7 +8,7 @@ import sqlalchemy as sa
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError
|
||||
from ormar import ModelDefinitionError, property_field
|
||||
from ormar.exceptions import ModelError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
@ -24,6 +24,10 @@ class AuditModel(ormar.Model):
|
||||
created_by: str = ormar.String(max_length=100)
|
||||
updated_by: str = ormar.String(max_length=100, default="Sam")
|
||||
|
||||
@property_field
|
||||
def audit(self): # pragma: no cover
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
class DateFieldsModelNoSubclass(ormar.Model):
|
||||
class Meta:
|
||||
@ -41,6 +45,7 @@ class DateFieldsModel(ormar.Model):
|
||||
abstract = True
|
||||
metadata = metadata
|
||||
database = db
|
||||
constraints = [ormar.UniqueColumns("created_date", "updated_date")]
|
||||
|
||||
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
|
||||
@ -49,11 +54,20 @@ class DateFieldsModel(ormar.Model):
|
||||
class Category(DateFieldsModel, AuditModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
tablename = "categories"
|
||||
constraints = [ormar.UniqueColumns("name", "code")]
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50, unique=True, index=True)
|
||||
code: int = ormar.Integer()
|
||||
|
||||
@property_field
|
||||
def code_name(self):
|
||||
return f"{self.code}:{self.name}"
|
||||
|
||||
@property_field
|
||||
def audit(self):
|
||||
return f"{self.created_by} {self.updated_by}"
|
||||
|
||||
|
||||
class Subject(DateFieldsModel):
|
||||
class Meta(ormar.ModelMeta):
|
||||
@ -99,6 +113,13 @@ def test_model_subclassing_non_abstract_raises_error():
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
|
||||
|
||||
def test_params_are_inherited():
|
||||
assert Category.Meta.metadata == metadata
|
||||
assert Category.Meta.database == db
|
||||
assert len(Category.Meta.constraints) == 2
|
||||
assert len(Category.Meta.property_fields) == 2
|
||||
|
||||
|
||||
def round_date_to_seconds(
|
||||
date: datetime.datetime,
|
||||
) -> datetime.datetime: # pragma: no cover
|
||||
@ -132,7 +153,9 @@ async def test_fields_inherited_from_mixin():
|
||||
inspector = sa.inspect(engine)
|
||||
assert "categories" in inspector.get_table_names()
|
||||
table_columns = [x.get("name") for x in inspector.get_columns("categories")]
|
||||
assert all(col in table_columns for col in mixin_columns) # + mixin2_columns)
|
||||
assert all(
|
||||
col in table_columns for col in mixin_columns
|
||||
) # + mixin2_columns)
|
||||
|
||||
assert "subjects" in inspector.get_table_names()
|
||||
table_columns = [x.get("name") for x in inspector.get_columns("subjects")]
|
||||
|
||||
@ -7,7 +7,7 @@ from fastapi import FastAPI
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.test_inheritance_concrete import Category, Subject, metadata
|
||||
from tests.test_inheritance_concrete import Category, Subject, metadata # type: ignore
|
||||
|
||||
app = FastAPI()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
@ -53,25 +53,25 @@ def test_read_main():
|
||||
test_category = dict(name="Foo", code=123, created_by="Sam", updated_by="Max")
|
||||
test_subject = dict(name="Bar")
|
||||
|
||||
response = client.post(
|
||||
"/categories/", json=test_category
|
||||
)
|
||||
response = client.post("/categories/", json=test_category)
|
||||
assert response.status_code == 200
|
||||
cat = Category(**response.json())
|
||||
assert cat.name == 'Foo'
|
||||
assert cat.created_by == 'Sam'
|
||||
assert cat.name == "Foo"
|
||||
assert cat.created_by == "Sam"
|
||||
assert cat.created_date is not None
|
||||
assert cat.id == 1
|
||||
|
||||
cat_dict = cat.dict()
|
||||
cat_dict['updated_date'] = cat_dict['updated_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
cat_dict['created_date'] = cat_dict['created_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
test_subject['category'] = cat_dict
|
||||
response = client.post(
|
||||
"/subjects/", json=test_subject
|
||||
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
cat_dict["created_date"] = cat_dict["created_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
test_subject["category"] = cat_dict
|
||||
response = client.post("/subjects/", json=test_subject)
|
||||
assert response.status_code == 200
|
||||
sub = Subject(**response.json())
|
||||
assert sub.name == 'Bar'
|
||||
assert sub.name == "Bar"
|
||||
assert sub.category.pk == cat.pk
|
||||
assert isinstance(sub.updated_date, datetime.datetime)
|
||||
|
||||
@ -7,7 +7,7 @@ from fastapi import FastAPI
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
from tests.test_inheritance_mixins import Category, Subject, metadata
|
||||
from tests.test_inheritance_mixins import Category, Subject, metadata # type: ignore
|
||||
|
||||
app = FastAPI()
|
||||
database = databases.Database(DATABASE_URL, force_rollback=True)
|
||||
@ -53,25 +53,25 @@ def test_read_main():
|
||||
test_category = dict(name="Foo", code=123, created_by="Sam", updated_by="Max")
|
||||
test_subject = dict(name="Bar")
|
||||
|
||||
response = client.post(
|
||||
"/categories/", json=test_category
|
||||
)
|
||||
response = client.post("/categories/", json=test_category)
|
||||
assert response.status_code == 200
|
||||
cat = Category(**response.json())
|
||||
assert cat.name == 'Foo'
|
||||
assert cat.created_by == 'Sam'
|
||||
assert cat.name == "Foo"
|
||||
assert cat.created_by == "Sam"
|
||||
assert cat.created_date is not None
|
||||
assert cat.id == 1
|
||||
|
||||
cat_dict = cat.dict()
|
||||
cat_dict['updated_date'] = cat_dict['updated_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
cat_dict['created_date'] = cat_dict['created_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
test_subject['category'] = cat_dict
|
||||
response = client.post(
|
||||
"/subjects/", json=test_subject
|
||||
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
cat_dict["created_date"] = cat_dict["created_date"].strftime(
|
||||
"%Y-%m-%d %H:%M:%S.%f"
|
||||
)
|
||||
test_subject["category"] = cat_dict
|
||||
response = client.post("/subjects/", json=test_subject)
|
||||
assert response.status_code == 200
|
||||
sub = Subject(**response.json())
|
||||
assert sub.name == 'Bar'
|
||||
assert sub.name == "Bar"
|
||||
assert sub.category.pk == cat.pk
|
||||
assert isinstance(sub.updated_date, datetime.datetime)
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
import asyncio
|
||||
from datetime import date
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
import ormar
|
||||
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class MainMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
|
||||
|
||||
class Role(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
name: str = ormar.Text(primary_key=True)
|
||||
order: int = ormar.Integer(default=0)
|
||||
description: str = ormar.Text()
|
||||
|
||||
|
||||
class Company(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
name: str = ormar.Text(primary_key=True)
|
||||
|
||||
|
||||
class UserRoleCompany(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
registrationnumber: str = ormar.Text(primary_key=True)
|
||||
company: Company = ormar.ForeignKey(Company)
|
||||
name: str = ormar.Text()
|
||||
role: Optional[Role] = ormar.ForeignKey(Role)
|
||||
roleforcompanies: Optional[Union[Company, List[Company]]] = ormar.ManyToMany(Company, through=UserRoleCompany)
|
||||
lastupdate: date = ormar.DateTime(server_default=sqlalchemy.func.now())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_primary_models():
|
||||
async with database:
|
||||
print("adding role")
|
||||
role_0 = await Role.objects.create(name="user", order=0, description="no administration right")
|
||||
role_1 = await Role.objects.create(name="admin", order=1, description="standard administration right")
|
||||
role_2 = await Role.objects.create(name="super_admin", order=2, description="super administration right")
|
||||
assert await Role.objects.count() == 3
|
||||
|
||||
print("adding company")
|
||||
company_0 = await Company.objects.create(name="Company")
|
||||
company_1 = await Company.objects.create(name="Subsidiary Company 1")
|
||||
company_2 = await Company.objects.create(name="Subsidiary Company 2")
|
||||
company_3 = await Company.objects.create(name="Subsidiary Company 3")
|
||||
assert await Company.objects.count() == 4
|
||||
|
||||
print("adding user")
|
||||
user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1)
|
||||
assert await User.objects.count() == 1
|
||||
|
||||
print("removing user")
|
||||
await user.delete()
|
||||
assert await User.objects.count() == 0
|
||||
|
||||
print("adding user with company-role")
|
||||
companies: List[Company] = [company_1, company_2]
|
||||
# user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1, roleforcompanies=companies)
|
||||
user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1)
|
||||
# print(User.__fields__)
|
||||
await user.roleforcompanies.add(company_1)
|
||||
await user.roleforcompanies.add(company_2)
|
||||
|
||||
users = await User.objects.select_related("roleforcompanies").all()
|
||||
# print(jsonpickle.encode(jsonable_encoder(users), unpicklable=False, keys=True))
|
||||
|
||||
"""
|
||||
|
||||
This is the request generated:
|
||||
'SELECT
|
||||
users.registrationnumber as registrationnumber,
|
||||
users.company as company,
|
||||
users.name as name, users.role as role,
|
||||
users.lastupdate as lastupdate,
|
||||
cy24b4_userrolecompanys.id as cy24b4_id,
|
||||
cy24b4_userrolecompanys.company as cy24b4_company,
|
||||
cy24b4_userrolecompanys.user as cy24b4_user,
|
||||
jn50a4_companys.name as jn50a4_name \n
|
||||
FROM users
|
||||
LEFT OUTER JOIN userrolecompanys cy24b4_userrolecompanys ON cy24b4_userrolecompanys.user=users.id
|
||||
LEFT OUTER JOIN companys jn50a4_companys ON jn50a4_companys.name=cy24b4_userrolecompanys.company
|
||||
ORDER BY users.registrationnumber, jn50a4_companys.name'
|
||||
|
||||
There is an error in the First LEFT OUTER JOIN generated:
|
||||
... companys.user=users.id
|
||||
should be:
|
||||
... companys.user=users.registrationnumber
|
||||
|
||||
There is also a \n in the midle of the string...
|
||||
|
||||
The execution produce the error: column users.id does not exist
|
||||
"""
|
||||
@ -102,7 +102,7 @@ async def test_model_multiple_instances_of_same_table_in_schema():
|
||||
async with database.transaction(force_rollback=True):
|
||||
await create_data()
|
||||
classes = await SchoolClass.objects.select_related(
|
||||
["teachers__category", "students"]
|
||||
["teachers__category", "students__schoolclass"]
|
||||
).all()
|
||||
assert classes[0].name == "Math"
|
||||
assert classes[0].students[0].name == "Jane"
|
||||
|
||||
@ -56,8 +56,7 @@ class SecondaryModel(ormar.Model):
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=100)
|
||||
primary_model: PrimaryModel = ormar.ForeignKey(
|
||||
PrimaryModel,
|
||||
related_name="secondary_models",
|
||||
PrimaryModel, related_name="secondary_models",
|
||||
)
|
||||
|
||||
|
||||
@ -74,7 +73,8 @@ async def test_create_primary_models():
|
||||
("Primary 7", "Some text 7", "Some other text 7"),
|
||||
("Primary 8", "Some text 8", "Some other text 8"),
|
||||
("Primary 9", "Some text 9", "Some other text 9"),
|
||||
("Primary 10", "Some text 10", "Some other text 10")]:
|
||||
("Primary 10", "Some text 10", "Some other text 10"),
|
||||
]:
|
||||
await PrimaryModel(
|
||||
name=name, some_text=some_text, some_other_text=some_other_text
|
||||
).save()
|
||||
|
||||
130
tests/test_select_related_with_m2m_and_pk_name_set.py
Normal file
130
tests/test_select_related_with_m2m_and_pk_name_set.py
Normal file
@ -0,0 +1,130 @@
|
||||
# type: ignore
|
||||
from datetime import date
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from ormar import ModelDefinitionError
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class MainMeta(ormar.ModelMeta):
|
||||
metadata = metadata
|
||||
database = database
|
||||
|
||||
|
||||
class Role(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
name: str = ormar.String(primary_key=True, max_length=1000)
|
||||
order: int = ormar.Integer(default=0, name="sort_order")
|
||||
description: str = ormar.Text()
|
||||
|
||||
|
||||
class Company(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
name: str = ormar.String(primary_key=True, max_length=1000)
|
||||
|
||||
|
||||
class UserRoleCompany(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
registrationnumber: str = ormar.String(primary_key=True, max_length=1000)
|
||||
company: Company = ormar.ForeignKey(Company)
|
||||
company2: Company = ormar.ForeignKey(Company, related_name="secondary_users")
|
||||
name: str = ormar.Text()
|
||||
role: Optional[Role] = ormar.ForeignKey(Role)
|
||||
roleforcompanies: Optional[Union[Company, List[Company]]] = ormar.ManyToMany(
|
||||
Company, through=UserRoleCompany, related_name="role_users"
|
||||
)
|
||||
lastupdate: date = ormar.DateTime(server_default=sqlalchemy.func.now())
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
def test_wrong_model():
|
||||
with pytest.raises(ModelDefinitionError):
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta(MainMeta):
|
||||
pass
|
||||
|
||||
registrationnumber: str = ormar.Text(primary_key=True)
|
||||
company: Company = ormar.ForeignKey(Company)
|
||||
company2: Company = ormar.ForeignKey(Company)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_primary_models():
|
||||
async with database:
|
||||
await Role.objects.create(
|
||||
name="user", order=0, description="no administration right"
|
||||
)
|
||||
role_1 = await Role.objects.create(
|
||||
name="admin", order=1, description="standard administration right"
|
||||
)
|
||||
await Role.objects.create(
|
||||
name="super_admin", order=2, description="super administration right"
|
||||
)
|
||||
assert await Role.objects.count() == 3
|
||||
|
||||
company_0 = await Company.objects.create(name="Company")
|
||||
company_1 = await Company.objects.create(name="Subsidiary Company 1")
|
||||
company_2 = await Company.objects.create(name="Subsidiary Company 2")
|
||||
company_3 = await Company.objects.create(name="Subsidiary Company 3")
|
||||
assert await Company.objects.count() == 4
|
||||
|
||||
user = await User.objects.create(
|
||||
registrationnumber="00-00000", company=company_0, name="admin", role=role_1
|
||||
)
|
||||
assert await User.objects.count() == 1
|
||||
|
||||
await user.delete()
|
||||
assert await User.objects.count() == 0
|
||||
|
||||
user = await User.objects.create(
|
||||
registrationnumber="00-00000",
|
||||
company=company_0,
|
||||
company2=company_3,
|
||||
name="admin",
|
||||
role=role_1,
|
||||
)
|
||||
await user.roleforcompanies.add(company_1)
|
||||
await user.roleforcompanies.add(company_2)
|
||||
|
||||
users = await User.objects.select_related(
|
||||
["company", "company2", "roleforcompanies"]
|
||||
).all()
|
||||
assert len(users) == 1
|
||||
assert len(users[0].roleforcompanies) == 2
|
||||
assert len(users[0].roleforcompanies[0].role_users) == 1
|
||||
assert users[0].company.name == "Company"
|
||||
assert len(users[0].company.users) == 1
|
||||
assert users[0].company2.name == "Subsidiary Company 3"
|
||||
assert len(users[0].company2.secondary_users) == 1
|
||||
|
||||
users = await User.objects.select_related("roleforcompanies").all()
|
||||
assert len(users) == 1
|
||||
assert len(users[0].roleforcompanies) == 2
|
||||
93
tests/test_selecting_proper_table_prefix.py
Normal file
93
tests/test_selecting_proper_table_prefix.py
Normal file
@ -0,0 +1,93 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import databases
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import ormar
|
||||
from tests.settings import DATABASE_URL
|
||||
|
||||
database = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
tablename = "test_users"
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=50)
|
||||
|
||||
|
||||
class Signup(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
tablename = "test_signup"
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
|
||||
|
||||
class Session(ormar.Model):
|
||||
class Meta:
|
||||
metadata = metadata
|
||||
database = database
|
||||
tablename = "test_sessions"
|
||||
|
||||
id: int = ormar.Integer(primary_key=True)
|
||||
name: str = ormar.String(max_length=255, index=True)
|
||||
some_text: str = ormar.Text()
|
||||
some_other_text: Optional[str] = ormar.Text(nullable=True)
|
||||
students: Optional[List[User]] = ormar.ManyToMany(User, through=Signup)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def create_test_database():
|
||||
engine = create_engine(DATABASE_URL)
|
||||
metadata.create_all(engine)
|
||||
yield
|
||||
metadata.drop_all(engine)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_sessions_for_user():
|
||||
async with database:
|
||||
for user_id in [1, 2, 3, 4, 5]:
|
||||
await User.objects.create(name=f"User {user_id}")
|
||||
|
||||
for name, some_text, some_other_text in [
|
||||
("Session 1", "Some text 1", "Some other text 1"),
|
||||
("Session 2", "Some text 2", "Some other text 2"),
|
||||
("Session 3", "Some text 3", "Some other text 3"),
|
||||
("Session 4", "Some text 4", "Some other text 4"),
|
||||
("Session 5", "Some text 5", "Some other text 5"),
|
||||
]:
|
||||
await Session(
|
||||
name=name, some_text=some_text, some_other_text=some_other_text
|
||||
).save()
|
||||
|
||||
s1 = await Session.objects.get(pk=1)
|
||||
s2 = await Session.objects.get(pk=2)
|
||||
|
||||
users = {}
|
||||
for i in range(1, 6):
|
||||
user = await User.objects.get(pk=i)
|
||||
users[f"user_{i}"] = user
|
||||
if i % 2 == 0:
|
||||
await s1.students.add(user)
|
||||
else:
|
||||
await s2.students.add(user)
|
||||
|
||||
assert len(s1.students) == 2
|
||||
assert len(s2.students) == 3
|
||||
|
||||
assert [x.pk for x in s1.students] == [2, 4]
|
||||
assert [x.pk for x in s2.students] == [1, 3, 5]
|
||||
|
||||
user = await User.objects.select_related("sessions").get(pk=1)
|
||||
|
||||
assert user.sessions is not None
|
||||
assert len(user.sessions) > 0
|
||||
Reference in New Issue
Block a user