renames etc.

This commit is contained in:
collerek
2020-08-14 19:36:50 +02:00
parent 0ebecc8610
commit 062d35168f
50 changed files with 398 additions and 299 deletions

BIN
.coverage

Binary file not shown.

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ p38venv
*.pyc
*.log
test.db
dist

View File

@ -7,8 +7,8 @@
<a href="https://codecov.io/gh/collerek/async-orm">
<img src="https://codecov.io/gh/collerek/async-orm/branch/master/graph/badge.svg" alt="Coverage">
</a>
<a href="https://www.codefactor.io/repository/github/collerek/async-orm">
<img src="https://www.codefactor.io/repository/github/collerek/async-orm/badge" alt="CodeFactor" />
<a href="https://www.codefactor.io/repository/github/collerek/ormar">
<img src="https://www.codefactor.io/repository/github/collerek/ormar/badge" alt="CodeFactor" />
</a>
<a href="https://app.codacy.com/manual/collerek/async-orm?utm_source=github.com&utm_medium=referral&utm_content=collerek/async-orm&utm_campaign=Badge_Grade_Dashboard">
<img src="https://api.codacy.com/project/badge/Grade/62568734f70f49cd8ea7a1a0b2d0c107" alt="Codacy" />
@ -35,22 +35,22 @@ The encode package was too simple (i.e. no ability to join two times to the same
```python
import databases
import orm
import ormar
import sqlalchemy
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Note(orm.Model):
class Note(ormar.Model):
__tablename__ = "notes"
__database__ = database
__metadata__ = metadata
# primary keys of type int by dafault are set to autoincrement
id = orm.Integer(primary_key=True)
text = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
text = ormar.String(length=100)
completed = ormar.Boolean(default=False)
# Create the database
engine = sqlalchemy.create_engine(str(database.url))
@ -88,31 +88,31 @@ ORM supports loading and filtering across foreign keys...
```python
import databases
import orm
import ormar
import sqlalchemy
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album)
title = ormar.String(length=100)
position = ormar.Integer()
# Create some records to work with.

View File

@ -199,7 +199,7 @@ But you can overwrite this name by providing `related_name` parameter like below
Since related models are coming from Relationship Manager the reverse relation on access returns list of `wekref.proxy` to avoid circular references.
!!!info
All relations are stored in lists, but when you access parent `Model` the ORM is unpacking the value for you.
All relations are stored in lists, but when you access parent `Model` the ormar is unpacking the value for you.
Read more in [relations][relations].
[relations]: ./relations.md

View File

@ -1,4 +1,4 @@
# Async-ORM
# ORMar
<p>
<a href="https://travis-ci.com/collerek/async-orm">
@ -15,42 +15,42 @@
</a>
</p>
The `async-orm` package is an async ORM for Python, with support for Postgres,
MySQL, and SQLite. ORM is built with:
The `ormar` package is an async ORM for Python, with support for Postgres,
MySQL, and SQLite. Ormar is built with:
* [`SQLAlchemy core`][sqlalchemy-core] for query building.
* [`databases`][databases] for cross-database async support.
* [`pydantic`][pydantic] for data validation.
Because ORM is built on SQLAlchemy core, you can use [`alembic`][alembic] to provide
Because ormar is built on SQLAlchemy core, you can use [`alembic`][alembic] to provide
database migrations.
The goal was to create a simple orm that can be used directly with [`fastapi`][fastapi] that bases it's data validation on pydantic.
The goal was to create a simple ORM that can be used directly with [`fastapi`][fastapi] that bases it's data validation on pydantic.
Initial work was inspired by [`encode/orm`][encode/orm].
The encode package was too simple (i.e. no ability to join two times to the same table) and used typesystem for data checks.
**async-orm is still under development:** We recommend pinning any dependencies with `aorm~=0.0.1`
**ormar is still under development:** We recommend pinning any dependencies with `ormar~=0.0.1`
**Note**: Use `ipython` to try this from the console, since it supports `await`.
```python
import databases
import orm
import ormar
import sqlalchemy
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Note(orm.Model):
class Note(ormar.Model):
__tablename__ = "notes"
__database__ = database
__metadata__ = metadata
# primary keys of type int by dafault are set to autoincrement
id = orm.Integer(primary_key=True)
text = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
text = ormar.String(length=100)
completed = ormar.Boolean(default=False)
# Create the database
engine = sqlalchemy.create_engine(str(database.url))
@ -84,35 +84,35 @@ note = await Note.objects.get(pk=2)
note.pk # 2
```
ORM supports loading and filtering across foreign keys...
Ormar supports loading and filtering across foreign keys...
```python
import databases
import orm
import ormar
import sqlalchemy
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album)
title = ormar.String(length=100)
position = ormar.Integer()
# Create some records to work with.
@ -187,17 +187,17 @@ All fields are required unless one of the following is set:
### Fields Types
* `orm.String(length)`
* `orm.Text()`
* `orm.Boolean()`
* `orm.Integer()`
* `orm.Float()`
* `orm.Date()`
* `orm.Time()`
* `orm.DateTime()`
* `orm.JSON()`
* `orm.BigInteger()`
* `orm.Decimal(lenght, precision)`
* `String(length)`
* `Text()`
* `Boolean()`
* `Integer()`
* `Float()`
* `Date()`
* `Time()`
* `DateTime()`
* `JSON()`
* `BigInteger()`
* `Decimal(lenght, precision)`
[sqlalchemy-core]: https://docs.sqlalchemy.org/en/latest/core/
[databases]: https://github.com/encode/databases

View File

@ -1,17 +1,20 @@
# Models
## Defining models
By defining an orm Model you get corresponding **Pydantic model** as well as **Sqlalchemy table** for free.
By defining an ormar Model you get corresponding **Pydantic model** as well as **Sqlalchemy table** for free.
They are being managed in the background and you do not have to create them on your own.
### Model Class
To build an ORM model you simply need to inherit a `orm.Model` class.
To build an ormar model you simply need to inherit a `ormar.Model` class.
```Python hl_lines="10"
--8<-- "../docs_src/models/docs001.py"
```
### Defining Fields
Next assign one or more of the [Fields][fields] as a class level variables.
Each table **has to** have a primary key column, which you specify by setting `primary_key=True` on selected field.
@ -31,17 +34,18 @@ By default if you assign primary key to `Integer` field, the `autoincrement` opt
You can disable by passing `autoincremant=False`.
```Python
id = orm.Integer(primary_key=True, autoincrement=False)
id = ormar.Integer(primary_key=True, autoincrement=False)
```
Names of the fields will be used for both the underlying `pydantic` model and `sqlalchemy` table.
### Dependencies
Since orm depends on [`databases`][databases] and [`sqlalchemy-core`][sqlalchemy-core] for database connection
Since ormar depends on [`databases`][databases] and [`sqlalchemy-core`][sqlalchemy-core] for database connection
and table creation you need to assign each `Model` with two special parameters.
#### Databases
One is `Database` instance created with your database url in [sqlalchemy connection string][sqlalchemy connection string] format.
Created instance needs to be passed to every `Model` with `__database__` parameter.
@ -55,6 +59,7 @@ Created instance needs to be passed to every `Model` with `__database__` paramet
You can create several ones if you want to use multiple databases.
#### Sqlalchemy
Second dependency is sqlalchemy `MetaData` instance.
Created instance needs to be passed to every `Model` with `__metadata__` parameter.
@ -123,6 +128,7 @@ The fields and relations are not stored on the `Model` itself
Apart from special parameters defined in the `Model` during definition (tablename, metadata etc.) the `Model` provides you with useful internals.
### Pydantic Model
To access auto created pydantic model you can use `Model.__pydantic_model__` parameter
For example to list model fields you can:
@ -138,6 +144,7 @@ For example to list model fields you can:
For more options visit official [pydantic][pydantic] documentation.
### Sqlalchemy Table
To access auto created sqlalchemy table you can use `Model.__table__` parameter
For example to list table columns you can:
@ -153,7 +160,8 @@ For example to list table columns you can:
For more options visit official [sqlalchemy-metadata][sqlalchemy-metadata] documentation.
### Fields Definition
To access orm `Fields` you can use `Model.__model_fields__` parameter
To access ormar `Fields` you can use `Model.__model_fields__` parameter
For example to list table model fields you can:

View File

@ -30,7 +30,7 @@ await malibu.save()
### load()
By default when you query a table without prefetching related models, the orm will still construct
By default when you query a table without prefetching related models, the ormar will still construct
your related models, but populate them only with the pk value.
```python

View File

@ -74,7 +74,7 @@ classes = await SchoolClass.objects.select_related(
Since you join two times to the same table (categories) it won't work by default -> you would need to use aliases for category tables and columns.
But don't worry - orm can handle situations like this, as it uses the Relationship Manager which has it's aliases defined for all relationships.
But don't worry - ormar can handle situations like this, as it uses the Relationship Manager which has it's aliases defined for all relationships.
Each class is registered with the same instance of the RelationshipManager that you can access like this:
@ -110,7 +110,7 @@ print(Teacher._orm_relationship_manager.resolve_relation_join(
### Query automatic construction
Orm is using those aliases during queries to both construct a meaningful and valid sql,
Ormar is using those aliases during queries to both construct a meaningful and valid sql,
as well as later use it to extract proper columns for proper nested models.
Running a previously mentioned query to select school classes and related teachers and students:

View File

@ -1,28 +1,28 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Department(orm.Model):
class Department(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
department = orm.ForeignKey(Department)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
department = ormar.ForeignKey(Department)
department = Department(name='Science')

View File

@ -1,28 +1,28 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Department(orm.Model):
class Department(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
department = orm.ForeignKey(Department, related_name="my_courses")
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
department = ormar.ForeignKey(Department, related_name="my_courses")
department = Department(name='Science')
course = Course(name='Math', completed=False, department=department)

View File

@ -1,4 +1,4 @@
import orm
import ormar
import databases
import sqlalchemy
@ -6,24 +6,24 @@ database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album, nullable=False)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album, nullable=False)
title = ormar.String(length=100)
position = ormar.Integer()
album = await Album.objects.create(name="Brooklyn")

View File

@ -1,16 +1,16 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)

View File

@ -1,19 +1,19 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
# if you omit this parameter it will be created automatically
# as class.__name__.lower()+'s' -> "courses" in this example
__tablename__ = "my_courses"
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)

View File

@ -1,19 +1,19 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
print(Course.__pydantic_model__.__fields__)
"""

View File

@ -1,19 +1,19 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
print(Course.__table__.columns)
"""

View File

@ -1,19 +1,19 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
print(Course.__model_fields__)
"""

View File

@ -1,28 +1,28 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Department(orm.Model):
class Department(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
department = orm.ForeignKey(Department)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
department = ormar.ForeignKey(Department)
department = Department(name="Science")

View File

@ -1,19 +1,19 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Course(orm.Model):
class Course(ormar.Model):
__database__ = database
__metadata__ = metadata
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
completed = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
completed = ormar.Boolean(default=False)
course = Course(name="Painting for dummies", completed=False)

View File

@ -1,4 +1,4 @@
import orm
import ormar
import databases
import sqlalchemy
@ -6,21 +6,21 @@ database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album)
title = ormar.String(length=100)
position = ormar.Integer()

View File

@ -1,4 +1,4 @@
import orm
import ormar
import databases
import sqlalchemy
@ -6,24 +6,24 @@ database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album)
title = ormar.String(length=100)
position = ormar.Integer()
print(Track.__table__.columns['album'].__repr__())

View File

@ -1,44 +1,44 @@
import databases
import sqlalchemy
import orm
import ormar
database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()
class SchoolClass(orm.Model):
class SchoolClass(ormar.Model):
__tablename__ = "schoolclasses"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Category(orm.Model):
class Category(ormar.Model):
__tablename__ = "categories"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Student(orm.Model):
class Student(ormar.Model):
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
schoolclass = orm.ForeignKey(SchoolClass)
category = orm.ForeignKey(Category)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
schoolclass = ormar.ForeignKey(SchoolClass)
category = ormar.ForeignKey(Category)
class Teacher(orm.Model):
class Teacher(ormar.Model):
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
schoolclass = orm.ForeignKey(SchoolClass)
category = orm.ForeignKey(Category)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
schoolclass = ormar.ForeignKey(SchoolClass)
category = ormar.ForeignKey(Category)

View File

@ -1,4 +0,0 @@
from orm.models.fakepydantic import FakePydantic
from orm.models.model import Model
__all__ = ["FakePydantic", "Model"]

View File

@ -1,3 +0,0 @@
from orm.queryset.queryset import QuerySet
__all__ = ["QuerySet"]

View File

@ -1,5 +1,5 @@
from orm.exceptions import ModelDefinitionError, ModelNotSet, MultipleMatches, NoMatch
from orm.fields import (
from ormar.exceptions import ModelDefinitionError, ModelNotSet, MultipleMatches, NoMatch
from ormar.fields import (
BigInteger,
Boolean,
Date,
@ -13,9 +13,9 @@ from orm.fields import (
Text,
Time,
)
from orm.models import Model
from ormar.models import Model
__version__ = "0.0.1"
__version__ = "0.1.0"
__all__ = [
"Integer",
"BigInteger",

View File

@ -1,6 +1,6 @@
from orm.fields.base import BaseField
from orm.fields.foreign_key import ForeignKey
from orm.fields.model_fields import (
from ormar.fields.base import BaseField
from ormar.fields.foreign_key import ForeignKey
from ormar.fields.model_fields import (
BigInteger,
Boolean,
Date,

View File

@ -2,10 +2,10 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING
import sqlalchemy
from orm import ModelDefinitionError # noqa I101
from ormar import ModelDefinitionError # noqa I101
if TYPE_CHECKING: # pragma no cover
from orm.models import Model
from ormar.models import Model
class BaseField:

View File

@ -1,9 +1,9 @@
from typing import Any, TYPE_CHECKING, Type
from orm import ModelDefinitionError
from ormar import ModelDefinitionError
if TYPE_CHECKING: # pragma no cover
from orm.fields import BaseField
from ormar.fields import BaseField
class RequiredParams:

View File

@ -3,12 +3,12 @@ from typing import Any, List, Optional, TYPE_CHECKING, Type, Union
import sqlalchemy
from pydantic import BaseModel
import orm # noqa I101
from orm.exceptions import RelationshipInstanceError
from orm.fields.base import BaseField
import ormar # noqa I101
from ormar.exceptions import RelationshipInstanceError
from ormar.fields.base import BaseField
if TYPE_CHECKING: # pragma no cover
from orm.models import Model
from ormar.models import Model
def create_dummy_instance(fk: Type["Model"], pk: Any = None) -> "Model":

View File

@ -4,8 +4,8 @@ import decimal
import sqlalchemy
from pydantic import Json
from orm.fields.base import BaseField # noqa I101
from orm.fields.decorators import RequiredParams
from ormar.fields.base import BaseField # noqa I101
from ormar.fields.decorators import RequiredParams
@RequiredParams("length")

4
ormar/models/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from ormar.models.fakepydantic import FakePydantic
from ormar.models.model import Model
__all__ = ["FakePydantic", "Model"]

View File

@ -19,13 +19,13 @@ import pydantic
import sqlalchemy
from pydantic import BaseModel
import orm # noqa I100
from orm.fields import BaseField
from orm.models.metaclass import ModelMetaclass
from orm.relations import RelationshipManager
import ormar # noqa I100
from ormar.fields import BaseField
from ormar.models.metaclass import ModelMetaclass
from ormar.relations import RelationshipManager
if TYPE_CHECKING: # pragma no cover
from orm.models.model import Model
from ormar.models.model import Model
class FakePydantic(list, metaclass=ModelMetaclass):
@ -194,10 +194,10 @@ class FakePydantic(list, metaclass=ModelMetaclass):
def merge_two_instances(cls, one: "Model", other: "Model") -> "Model":
for field in one.__model_fields__.keys():
if isinstance(getattr(one, field), list) and not isinstance(
getattr(one, field), orm.Model
getattr(one, field), ormar.Model
):
setattr(other, field, getattr(one, field) + getattr(other, field))
elif isinstance(getattr(one, field), orm.Model):
elif isinstance(getattr(one, field), ormar.Model):
if getattr(one, field).pk == getattr(other, field).pk:
setattr(
other,

View File

@ -5,12 +5,12 @@ import sqlalchemy
from pydantic import BaseConfig, create_model
from pydantic.fields import ModelField
from orm import ForeignKey, ModelDefinitionError # noqa I100
from orm.fields import BaseField
from orm.relations import RelationshipManager
from ormar import ForeignKey, ModelDefinitionError # noqa I100
from ormar.fields import BaseField
from ormar.relations import RelationshipManager
if TYPE_CHECKING: # pragma no cover
from orm import Model
from ormar import Model
relationship_manager = RelationshipManager()

View File

@ -2,14 +2,14 @@ from typing import Any, List
import sqlalchemy
import orm.queryset # noqa I100
from orm.models import FakePydantic # noqa I100
import ormar.queryset # noqa I100
from ormar.models import FakePydantic # noqa I100
class Model(FakePydantic):
__abstract__ = True
objects = orm.queryset.QuerySet()
objects = ormar.queryset.QuerySet()
@classmethod
def from_row(

View File

@ -0,0 +1,3 @@
from ormar.queryset.queryset import QuerySet
__all__ = ["QuerySet"]

View File

@ -3,11 +3,11 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, Union
import sqlalchemy
from sqlalchemy import text
import orm # noqa I100
from orm.exceptions import QueryDefinitionError
import ormar # noqa I100
from ormar.exceptions import QueryDefinitionError
if TYPE_CHECKING: # pragma no cover
from orm import Model
from ormar import Model
FILTER_OPERATORS = {
"exact": "__eq__",
@ -75,7 +75,7 @@ class QueryClause:
value, has_escaped_character = self._escape_characters_in_clause(op, value)
if isinstance(value, orm.Model):
if isinstance(value, ormar.Model):
value = value.pk
op_attr = FILTER_OPERATORS[op]
@ -147,7 +147,7 @@ class QueryClause:
if op not in ["contains", "icontains"]:
return value, has_escaped_character
if isinstance(value, orm.Model):
if isinstance(value, ormar.Model):
raise QueryDefinitionError(
"You cannot use contains and icontains with instance of the Model"
)

View File

@ -3,12 +3,12 @@ from typing import List, NamedTuple, TYPE_CHECKING, Tuple, Type
import sqlalchemy
from sqlalchemy import text
import orm # noqa I100
from orm import ForeignKey
from orm.fields import BaseField
import ormar # noqa I100
from ormar import ForeignKey
from ormar.fields import BaseField
if TYPE_CHECKING: # pragma no cover
from orm import Model
from ormar import Model
class JoinParameters(NamedTuple):
@ -53,7 +53,7 @@ class Query:
if (
not self.model_cls.__model_fields__[key].nullable
and isinstance(
self.model_cls.__model_fields__[key], orm.fields.ForeignKey,
self.model_cls.__model_fields__[key], ormar.fields.ForeignKey,
)
and key not in self._select_related
):

View File

@ -3,13 +3,13 @@ from typing import Any, List, TYPE_CHECKING, Tuple, Type, Union
import databases
import sqlalchemy
import orm # noqa I100
from orm import MultipleMatches, NoMatch
from orm.queryset.clause import QueryClause
from orm.queryset.query import Query
import ormar # noqa I100
from ormar import MultipleMatches, NoMatch
from ormar.queryset.clause import QueryClause
from ormar.queryset.query import Query
if TYPE_CHECKING: # pragma no cover
from orm import Model
from ormar import Model
class QuerySet:

View File

@ -5,10 +5,10 @@ from random import choices
from typing import List, TYPE_CHECKING, Union
from weakref import proxy
from orm import ForeignKey
from ormar import ForeignKey
if TYPE_CHECKING: # pragma no cover
from orm.models import FakePydantic, Model
from ormar.models import FakePydantic, Model
def get_table_alias() -> str:

2
scripts/clean.sh Normal file → Executable file
View File

@ -1,5 +1,5 @@
#!/bin/sh -e
PACKAGE="orm"
PACKAGE="ormar"
if [ -d 'dist' ] ; then
rm -r dist
fi

23
scripts/publish.sh Normal file
View File

@ -0,0 +1,23 @@
#!/bin/sh -e
PACKAGE="ormar"
PREFIX=""
if [ -d 'venv' ] ; then
PREFIX="venv/bin/"
fi
VERSION=`cat ${PACKAGE}/__init__.py | grep __version__ | sed "s/__version__ = //" | sed "s/'//g"`
set -x
scripts/clean.sh
${PREFIX}python setup.py sdist
${PREFIX}twine upload dist/*
echo "You probably want to also tag the version now:"
echo "git tag -a ${VERSION} -m 'version ${VERSION}'"
echo "git push --tags"
scripts/clean.sh

View File

@ -1,6 +1,6 @@
#!/bin/sh -e
PACKAGE="orm"
PACKAGE="ormar"
PREFIX=""
if [ -d 'venv' ] ; then

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[metadata]
description-file = README.md

67
setup.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import re
from setuptools import setup
PACKAGE = "ormar"
URL = "https://github.com/collerek/ormar"
def get_version(package):
"""
Return package version as listed in `__version__` in `init.py`.
"""
with open(os.path.join(package, "__init__.py")) as f:
return re.search("__version__ = ['\"]([^'\"]+)['\"]", f.read()).group(1)
def get_long_description():
"""
Return the README.
"""
with open("README.md", encoding="utf8") as f:
return f.read()
def get_packages(package):
"""
Return root package and all sub-packages.
"""
return [
dirpath
for dirpath, dirnames, filenames in os.walk(package)
if os.path.exists(os.path.join(dirpath, "__init__.py"))
]
setup(
name=PACKAGE,
version=get_version(PACKAGE),
url=URL,
license="MIT",
description="An simple async ORM with Fastapi in mind.",
long_description=get_long_description(),
long_description_content_type="text/markdown",
keywords=['ORM', 'sqlalchemy', 'fastapi', 'pydantic', 'databases'],
author="Radosław Drążkiewicz",
author_email="collerek@gmail.com",
packages=get_packages(PACKAGE),
package_data={PACKAGE: ["py.typed"]},
data_files=[("", ["LICENSE.md"])],
install_requires=["databases", "pydantic", "sqlalchemy"],
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Topic :: Internet :: WWW/HTTP",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
],
)

View File

@ -4,7 +4,7 @@ import databases
import pytest
import sqlalchemy
import orm
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
@ -15,18 +15,18 @@ def time():
return datetime.datetime.now().time()
class Example(orm.Model):
class Example(ormar.Model):
__tablename__ = "example"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
created = orm.DateTime(default=datetime.datetime.now)
created_day = orm.Date(default=datetime.date.today)
created_time = orm.Time(default=time)
description = orm.Text(nullable=True)
value = orm.Float(nullable=True)
data = orm.JSON(default={})
id = ormar.Integer(primary_key=True)
created = ormar.DateTime(default=datetime.datetime.now)
created_day = ormar.Date(default=datetime.date.today)
created_time = ormar.Time(default=time)
description = ormar.Text(nullable=True)
value = ormar.Float(nullable=True)
data = ormar.JSON(default={})
@pytest.fixture(autouse=True, scope="module")

View File

@ -3,8 +3,7 @@ import sqlalchemy
from fastapi import FastAPI
from fastapi.testclient import TestClient
import orm
import orm.fields.foreign_key
import ormar
from tests.settings import DATABASE_URL
app = FastAPI()
@ -13,23 +12,23 @@ database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Category(orm.Model):
class Category(ormar.Model):
__tablename__ = "categories"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Item(orm.Model):
class Item(ormar.Model):
__tablename__ = "items"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
category = orm.fields.foreign_key.ForeignKey(Category, nullable=True)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
category = ormar.ForeignKey(Category, nullable=True)
@app.post("/items/", response_model=Item)

View File

@ -2,71 +2,71 @@ import databases
import pytest
import sqlalchemy
import orm
from orm.exceptions import NoMatch, MultipleMatches, RelationshipInstanceError
import ormar
from ormar.exceptions import NoMatch, MultipleMatches, RelationshipInstanceError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Album(orm.Model):
class Album(ormar.Model):
__tablename__ = "album"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Track(orm.Model):
class Track(ormar.Model):
__tablename__ = "track"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album)
title = orm.String(length=100)
position = orm.Integer()
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album)
title = ormar.String(length=100)
position = ormar.Integer()
class Cover(orm.Model):
class Cover(ormar.Model):
__tablename__ = "covers"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
album = orm.ForeignKey(Album, related_name='cover_pictures')
title = orm.String(length=100)
id = ormar.Integer(primary_key=True)
album = ormar.ForeignKey(Album, related_name='cover_pictures')
title = ormar.String(length=100)
class Organisation(orm.Model):
class Organisation(ormar.Model):
__tablename__ = "org"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
ident = orm.String(length=100)
id = ormar.Integer(primary_key=True)
ident = ormar.String(length=100)
class Team(orm.Model):
class Team(ormar.Model):
__tablename__ = "team"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
org = orm.ForeignKey(Organisation)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
org = ormar.ForeignKey(Organisation)
name = ormar.String(length=100)
class Member(orm.Model):
class Member(ormar.Model):
__tablename__ = "member"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
team = orm.ForeignKey(Team)
email = orm.String(length=100)
id = ormar.Integer(primary_key=True)
team = ormar.ForeignKey(Team)
email = ormar.String(length=100)
@pytest.fixture(autouse=True, scope="module")

View File

@ -4,9 +4,9 @@ import pydantic
import pytest
import sqlalchemy
import orm.fields as fields
from orm.exceptions import ModelDefinitionError
from orm.models import Model
import ormar.fields as fields
from ormar.exceptions import ModelDefinitionError
from ormar.models import Model
metadata = sqlalchemy.MetaData()

View File

@ -2,32 +2,32 @@ import databases
import pytest
import sqlalchemy
import orm
from orm.exceptions import QueryDefinitionError
import ormar
from ormar.exceptions import QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class User(orm.Model):
class User(ormar.Model):
__tablename__ = "users"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Product(orm.Model):
class Product(ormar.Model):
__tablename__ = "product"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
rating = orm.Integer(minimum=1, maximum=5)
in_stock = orm.Boolean(default=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
rating = ormar.Integer(minimum=1, maximum=5)
in_stock = ormar.Boolean(default=False)
@pytest.fixture(autouse=True, scope="module")
@ -40,9 +40,9 @@ def create_test_database():
def test_model_class():
assert list(User.__model_fields__.keys()) == ["id", "name"]
assert isinstance(User.__model_fields__["id"], orm.Integer)
assert isinstance(User.__model_fields__["id"], ormar.Integer)
assert User.__model_fields__["id"].primary_key is True
assert isinstance(User.__model_fields__["name"], orm.String)
assert isinstance(User.__model_fields__["name"], ormar.String)
assert User.__model_fields__["name"].length == 100
assert isinstance(User.__table__, sqlalchemy.Table)
@ -82,7 +82,7 @@ async def test_model_crud():
@pytest.mark.asyncio
async def test_model_get():
async with database:
with pytest.raises(orm.NoMatch):
with pytest.raises(ormar.NoMatch):
await User.objects.get()
user = await User.objects.create(name="Tom")
@ -90,7 +90,7 @@ async def test_model_get():
assert lookup == user
user = await User.objects.create(name="Jane")
with pytest.raises(orm.MultipleMatches):
with pytest.raises(ormar.MultipleMatches):
await User.objects.get()
same_user = await User.objects.get(pk=user.id)
@ -108,7 +108,7 @@ async def test_model_filter():
user = await User.objects.get(name="Lucy")
assert user.name == "Lucy"
with pytest.raises(orm.NoMatch):
with pytest.raises(ormar.NoMatch):
await User.objects.get(name="Jim")
await Product.objects.create(name="T-Shirt", rating=5, in_stock=True)

View File

@ -4,62 +4,61 @@ import databases
import pytest
import sqlalchemy
import orm
import orm.fields.foreign_key
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Department(orm.Model):
class Department(ormar.Model):
__tablename__ = "departments"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True, autoincrement=False)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True, autoincrement=False)
name = ormar.String(length=100)
class SchoolClass(orm.Model):
class SchoolClass(ormar.Model):
__tablename__ = "schoolclasses"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
department = orm.fields.foreign_key.ForeignKey(Department, nullable=False)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
department = ormar.ForeignKey(Department, nullable=False)
class Category(orm.Model):
class Category(ormar.Model):
__tablename__ = "categories"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
class Student(orm.Model):
class Student(ormar.Model):
__tablename__ = "students"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
schoolclass = orm.fields.foreign_key.ForeignKey(SchoolClass)
category = orm.fields.foreign_key.ForeignKey(Category, nullable=True)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
schoolclass = ormar.ForeignKey(SchoolClass)
category = ormar.ForeignKey(Category, nullable=True)
class Teacher(orm.Model):
class Teacher(ormar.Model):
__tablename__ = "teachers"
__metadata__ = metadata
__database__ = database
id = orm.Integer(primary_key=True)
name = orm.String(length=100)
schoolclass = orm.fields.foreign_key.ForeignKey(SchoolClass)
category = orm.fields.foreign_key.ForeignKey(Category, nullable=True)
id = ormar.Integer(primary_key=True)
name = ormar.String(length=100)
schoolclass = ormar.ForeignKey(SchoolClass)
category = ormar.ForeignKey(Category, nullable=True)
@pytest.fixture(scope='module')