change expr to sting in bulk_update, update readme, bump version
This commit is contained in:
46
README.md
46
README.md
@ -328,6 +328,52 @@ assert await Book.objects.count() == 1
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Since version >=0.3.5 Ormar supports also bulk operations -> bulk_create and bulk_update
|
||||||
|
```python
|
||||||
|
import databases
|
||||||
|
import ormar
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
|
database = databases.Database("sqlite:///db.sqlite")
|
||||||
|
metadata = sqlalchemy.MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
class ToDo(ormar.Model):
|
||||||
|
class Meta:
|
||||||
|
tablename = "todos"
|
||||||
|
metadata = metadata
|
||||||
|
database = database
|
||||||
|
|
||||||
|
id: ormar.Integer(primary_key=True)
|
||||||
|
text: ormar.String(max_length=500)
|
||||||
|
completed: ormar.Boolean(default=False)
|
||||||
|
|
||||||
|
# create multiple instances at once with bulk_create
|
||||||
|
await ToDo.objects.bulk_create(
|
||||||
|
[
|
||||||
|
ToDo(text="Buy the groceries."),
|
||||||
|
ToDo(text="Call Mum.", completed=True),
|
||||||
|
ToDo(text="Send invoices.", completed=True),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
todoes = await ToDo.objects.all()
|
||||||
|
assert len(todoes) == 3
|
||||||
|
|
||||||
|
# update objects
|
||||||
|
for todo in todoes:
|
||||||
|
todo.completed = False
|
||||||
|
|
||||||
|
# perform update of all objects at once
|
||||||
|
# objects need to have pk column set, otherwise exception is raised
|
||||||
|
await ToDo.objects.bulk_update(todoes)
|
||||||
|
|
||||||
|
completed = await ToDo.objects.filter(completed=False).all()
|
||||||
|
assert len(completed) == 3
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Data types
|
## Data types
|
||||||
|
|
||||||
The following keyword arguments are supported on all field types.
|
The following keyword arguments are supported on all field types.
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class UndefinedType: # pragma no cover
|
|||||||
|
|
||||||
Undefined = UndefinedType()
|
Undefined = UndefinedType()
|
||||||
|
|
||||||
__version__ = "0.3.4"
|
__version__ = "0.3.5"
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Integer",
|
"Integer",
|
||||||
"BigInteger",
|
"BigInteger",
|
||||||
|
|||||||
@ -2,6 +2,7 @@ from typing import Any, List, Mapping, TYPE_CHECKING, Tuple, Type, Union
|
|||||||
|
|
||||||
import databases
|
import databases
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
from sqlalchemy import bindparam
|
||||||
|
|
||||||
import ormar # noqa I100
|
import ormar # noqa I100
|
||||||
from ormar import MultipleMatches, NoMatch
|
from ormar import MultipleMatches, NoMatch
|
||||||
@ -263,7 +264,7 @@ class QuerySet:
|
|||||||
async def bulk_update(
|
async def bulk_update(
|
||||||
self, objects: List["Model"], columns: List[str] = None
|
self, objects: List["Model"], columns: List[str] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
ready_expressions = []
|
ready_objects = []
|
||||||
pk_name = self.model_cls.Meta.pkname
|
pk_name = self.model_cls.Meta.pkname
|
||||||
if not columns:
|
if not columns:
|
||||||
columns = self.model_cls.extract_db_own_fields().union(
|
columns = self.model_cls.extract_db_own_fields().union(
|
||||||
@ -281,18 +282,15 @@ class QuerySet:
|
|||||||
f"{self.model_cls.__name__} has to have {pk_name} filled."
|
f"{self.model_cls.__name__} has to have {pk_name} filled."
|
||||||
)
|
)
|
||||||
new_kwargs = self.model_cls.substitute_models_with_pks(new_kwargs)
|
new_kwargs = self.model_cls.substitute_models_with_pks(new_kwargs)
|
||||||
new_kwargs = self._populate_default_values(new_kwargs)
|
new_kwargs = {"new_" + k: v for k, v in new_kwargs.items() if k in columns}
|
||||||
new_kwargs = {k: v for k, v in new_kwargs.items() if k in columns}
|
ready_objects.append(new_kwargs)
|
||||||
expr = self.table.update().values(
|
|
||||||
**{k: v for k, v in new_kwargs.items() if k != pk_name}
|
|
||||||
)
|
|
||||||
pk_column = self.model_cls.Meta.table.c.get(pk_name)
|
|
||||||
expr = expr.where(pk_column == new_kwargs.get(pk_name))
|
|
||||||
ready_expressions.append(expr)
|
|
||||||
|
|
||||||
# databases does not bind params for where clause and values separately
|
pk_column = self.model_cls.Meta.table.c.get(pk_name)
|
||||||
# no way to pass one dict with both uses
|
expr = self.table.update().where(pk_column == bindparam("new_" + pk_name))
|
||||||
# so we need to resort to lower connection api
|
expr = expr.values(
|
||||||
async with self.model_cls.Meta.database.connection() as connection:
|
**{k: bindparam("new_" + k) for k in columns if k != pk_name}
|
||||||
for single_query in ready_expressions:
|
)
|
||||||
await connection.execute(single_query)
|
# databases bind params only where query is passed as string
|
||||||
|
# otherwise it just pases all data to values and results in unconsumed columns
|
||||||
|
expr = str(expr)
|
||||||
|
await self.database.execute_many(expr, ready_objects)
|
||||||
|
|||||||
Reference in New Issue
Block a user