work on docs in queries

This commit is contained in:
collerek
2021-01-28 17:48:32 +01:00
parent b710ed9780
commit 2f8645b1a2
10 changed files with 766 additions and 91 deletions

View File

@ -65,7 +65,7 @@ await track.update(name='The Bird Strikes Again')
`upsert(**kwargs) -> self` `upsert(**kwargs) -> self`
It's an proxy to either `save()` or `update(**kwargs)` methods described above. It's a proxy to either `save()` or `update(**kwargs)` methods described above.
If the primary key is set -> the `update` method will be called. If the primary key is set -> the `update` method will be called.

View File

View File

@ -1,11 +1,23 @@
# Create / Insert data into database # Insert data into database
* `create(**kwargs): -> Model` Following methods allow you to insert data into the database.
* `create(**kwargs) -> Model`
* `get_or_create(**kwargs) -> Model` * `get_or_create(**kwargs) -> Model`
* `update_or_create(**kwargs) -> Model` * `update_or_create(**kwargs) -> Model`
* `bulk_create(objects: List[Model]) -> None` * `bulk_create(objects: List[Model]) -> None`
* `Model.save()` method
* `Model.upsert()` method
* `Model`
* `Model.save()` method
* `Model.upsert()` method
* `Model.save_related()` method
* `QuerysetProxy`
* `QuerysetProxy.create(**kwargs)` method
* `QuerysetProxy.get_or_create(**kwargs)` method
* `QuerysetProxy.update_or_create(**kwargs)` method
## create ## create
@ -16,6 +28,17 @@ Creates the model instance, saves it in a database and returns the updates model
The allowed kwargs are `Model` fields names and proper value types. The allowed kwargs are `Model` fields names and proper value types.
```python
class Album(ormar.Model):
class Meta:
tablename = "album"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
```
```python ```python
malibu = await Album.objects.create(name="Malibu") malibu = await Album.objects.create(name="Malibu")
await Track.objects.create(album=malibu, title="The Bird", position=1) await Track.objects.create(album=malibu, title="The Bird", position=1)
@ -28,7 +51,8 @@ malibu = Album(name="Malibu")
await malibu.save() await malibu.save()
``` ```
!!!tip Check other `Model` methods in [models][models] !!!tip
Check other `Model` methods in [models][models]
## get_or_create ## get_or_create
@ -39,6 +63,17 @@ Combination of create and get methods.
Tries to get a row meeting the criteria and if `NoMatch` exception is raised it creates Tries to get a row meeting the criteria and if `NoMatch` exception is raised it creates
a new one with given kwargs. a new one with given kwargs.
```python
class Album(ormar.Model):
class Meta:
tablename = "album"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
```
```python ```python
album = await Album.objects.get_or_create(name='The Cat') album = await Album.objects.get_or_create(name='The Cat')
# object is created as it does not exist # object is created as it does not exist
@ -47,13 +82,15 @@ assert album == album2
# return True as the same db row is returned # return True as the same db row is returned
``` ```
!!!warning Despite being a equivalent row from database the `album` and `album2` in !!!warning
example above are 2 different python objects! Despite being a equivalent row from database the `album` and `album2` in
Updating one of them will not refresh the second one until you excplicitly load() the example above are 2 different python objects!
fresh data from db. Updating one of them will not refresh the second one until you excplicitly load() the
fresh data from db.
!!!note Note that if you want to create a new object you either have to pass pk column !!!note
value or pk column has to be set as autoincrement Note that if you want to create a new object you either have to pass pk column
value or pk column has to be set as autoincrement
## update_or_create ## update_or_create
@ -65,8 +102,9 @@ Updates the model, or in case there is no match in database creates a new one.
--8<-- "../docs_src/queries/docs003.py" --8<-- "../docs_src/queries/docs003.py"
``` ```
!!!note Note that if you want to create a new object you either have to pass pk column !!!note
value or pk column has to be set as autoincrement Note that if you want to create a new object you either have to pass pk column
value or pk column has to be set as autoincrement
## bulk_create ## bulk_create
@ -80,4 +118,68 @@ A valid list of `Model` objects needs to be passed.
--8<-- "../docs_src/queries/docs004.py" --8<-- "../docs_src/queries/docs004.py"
``` ```
## Model method ## Model methods
Each model instance have a set of methods to `save`, `update` or `load` itself.
###save
You can create new models by using `QuerySet.create()` method or by initializing your model as a normal pydantic model
and later calling `save()` method.
!!!tip
Read more about `save()` method in [models-save][models-save]
###upsert
It's a proxy to either `save()` or `update(**kwargs)` methods of a Model.
If the pk is not set the `save()` method will be called.
!!!tip
Read more about `upsert()` method in [models-upsert][models-upsert]
###save_related
Method goes through all relations of the `Model` on which the method is called,
and calls `upsert()` method on each model that is **not** saved.
!!!tip
Read more about `save_related()` method in [models-save-related][models-save-related]
## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey` returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create, select related etc related models directly from parent model.
### create
Works exactly the same as [create](./#create) function above but allows you to create related objects
from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### get_or_create
Works exactly the same as [get_or_create](./#get_or_create) function above but allows you to query or create related objects
from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### update_or_create
Works exactly the same as [update_or_create](./#update_or_create) function above but allows you to update or create related objects
from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
[models]: ../models/methods.md
[models-save]: ../models/methods.md#save
[models-upsert]: ../models/methods.md#upsert
[models-save-related]: ../models/methods.md#save_related
[querysetproxy]: ../relations/queryset-proxy.md

View File

@ -1,7 +1,17 @@
# Delete/ remove data from database # Delete data from database
Following methods allow you to delete data from the database.
* `delete(each: bool = False, **kwargs) -> int` * `delete(each: bool = False, **kwargs) -> int`
* `Model.delete()` method
* `Model`
* `Model.delete()` method
* `QuerysetProxy`
* `QuerysetProxy.remove()` method
* `QuerysetProxy.clear()` method
## delete ## delete
@ -20,4 +30,122 @@ Return number of rows deleted.
--8<-- "../docs_src/queries/docs005.py" --8<-- "../docs_src/queries/docs005.py"
``` ```
## Model method ## Model methods
Each model instance have a set of methods to `save`, `update` or `load` itself.
### delete
You can delete model instance by calling `delete()` method on it.
!!!tip
Read more about `delete()` method in [models methods](../models/methods.md#delete)
## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey`
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create,
select related etc related models directly from parent model.
### remove
Removal of the related model one by one.
Removes the relation in the database.
If you specify the keep_reversed flag to `False` `ormar` will also delete the related model from the database.
```python
class Album(ormar.Model):
class Meta:
tablename = "albums"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_best_seller: bool = ormar.Boolean(default=False)
class Track(ormar.Model):
class Meta:
tablename = "tracks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
play_count: int = ormar.Integer(nullable=True)
```
```python
album = await Album(name="Malibu").save()
track1 = await Track(
album=album, title="The Bird", position=1, play_count=30,
).save()
# remove through proxy from reverse side of relation
await album.tracks.remove(track1, keep_reversed=False)
# the track was also deleted
tracks = await Track.objects.all()
assert len(tracks) == 0
```
### clear
Removal of all related models in one call.
Removes also the relation in the database.
If you specify the keep_reversed flag to `False` `ormar` will also delete the related model from the database.
```python
class Album(ormar.Model):
class Meta:
tablename = "albums"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_best_seller: bool = ormar.Boolean(default=False)
class Track(ormar.Model):
class Meta:
tablename = "tracks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
play_count: int = ormar.Integer(nullable=True)
```
```python
album = await Album(name="Malibu").save()
track1 = await Track(
album=album,
title="The Bird",
position=1,
play_count=30,
).save()
track2 = await Track(
album=album,
title="Heart don't stand a chance",
position=2,
play_count=20,
).save()
# removes the relation only -> clears foreign keys on tracks
await album.tracks.clear()
# removes also the tracks
await album.tracks.clear(keep_reversed=False)
```
[querysetproxy]: ../relations/queryset-proxy.md

View File

@ -1,8 +1,26 @@
# Filtering and sorting data # Filtering and sorting data
You can use following methods to filter the data (sql where clause).
* `filter(**kwargs) -> QuerySet` * `filter(**kwargs) -> QuerySet`
* `exclude(**kwargs) -> QuerySet` * `exclude(**kwargs) -> QuerySet`
* `get(**kwargs) -> Model`
* `get_or_create(**kwargs) -> Model`
* `all(**kwargs) -> List[Optional[Model]]`
* `QuerysetProxy`
* `QuerysetProxy.filter(**kwargs)` method
* `QuerysetProxy.exclude(**kwargs)` method
* `QuerysetProxy.get(**kwargs)` method
* `QuerysetProxy.get_or_create(**kwargs)` method
* `QuerysetProxy.all(**kwargs)` method
And following methods to sort the data (sql order by clause).
* `order_by(columns:Union[List, str]) -> QuerySet` * `order_by(columns:Union[List, str]) -> QuerySet`
* `QuerysetProxy`
* `QuerysetProxy.order_by(columns:Union[List, str])` method
## filter ## filter
@ -36,18 +54,20 @@ You can use special filter suffix to change the filter operands:
* endswith - like `album__name__endswith='ibu'` (exact end match) * endswith - like `album__name__endswith='ibu'` (exact end match)
* iendswith - like `album__name__iendswith='IBU'` (exact end match case insensitive) * iendswith - like `album__name__iendswith='IBU'` (exact end match case insensitive)
!!!note All methods that do not return the rows explicitly returns a QueySet instance so !!!note
you can chain them together All methods that do not return the rows explicitly returns a QueySet instance so
you can chain them together
So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained. So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained.
Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()` Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`
!!!warning Note that you do not have to specify the `%` wildcard in contains and other !!!warning
filters, it's added for you. If you include `%` in your search value it will be escaped Note that you do not have to specify the `%` wildcard in contains and other
and treated as literal percentage sign inside the text. filters, it's added for you. If you include `%` in your search value it will be escaped
and treated as literal percentage sign inside the text.
### exclude ## exclude
`exclude(**kwargs) -> QuerySet` `exclude(**kwargs) -> QuerySet`
@ -67,7 +87,41 @@ notes = await Track.objects.exclude(position_gt=3).all()
# returns all tracks with position < 3 # returns all tracks with position < 3
``` ```
### order_by ## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey`
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create,
select related etc related models directly from parent model.
### get
Works exactly the same as [get](./#get) function above but allows you to fetch related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### get_or_create
Works exactly the same as [get_or_create](./#get_or_create) function above but allows
you to query or create related objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### all
Works exactly the same as [all](./#all) function above but allows you to query related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
## order_by
`order_by(columns: Union[List, str]) -> QuerySet` `order_by(columns: Union[List, str]) -> QuerySet`
@ -78,12 +132,14 @@ You can provide a string with field name or list of strings with different field
Ordering in sql will be applied in order of names you provide in order_by. Ordering in sql will be applied in order of names you provide in order_by.
!!!tip By default if you do not provide ordering `ormar` explicitly orders by all !!!tip
primary keys By default if you do not provide ordering `ormar` explicitly orders by all
primary keys
!!!warning If you are sorting by nested models that causes that the result rows are !!!warning
unsorted by the main model If you are sorting by nested models that causes that the result rows are
`ormar` will combine those children rows into one main model. unsorted by the main model
`ormar` will combine those children rows into one main model.
Sample raw database rows result (sort by child model desc): Sample raw database rows result (sort by child model desc):
``` ```
@ -103,7 +159,7 @@ unsorted by the main model
Given sample Models like following: Given sample Models like following:
```python ```python
--8 < -- "../docs_src/queries/docs007.py" --8 < -- "../../docs_src/queries/docs007.py"
``` ```
To order by main model field just provide a field name To order by main model field just provide a field name
@ -142,10 +198,12 @@ assert owner.toys[0].name == "Toy 4"
assert owner.toys[1].name == "Toy 1" assert owner.toys[1].name == "Toy 1"
``` ```
!!!note All methods that do not return the rows explicitly returns a QueySet instance so !!!note
you can chain them together All methods that do not return the rows explicitly returns a QueySet instance so
you can chain them together
So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained. So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained.
Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()` Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`
[querysetproxy]: ../relations/queryset-proxy.md

View File

@ -8,8 +8,9 @@ and it's options.
Most of the methods are also available through many to many relations and on reverse Most of the methods are also available through many to many relations and on reverse
foreign key relations through `QuerysetProxy` interface. foreign key relations through `QuerysetProxy` interface.
!!!info To see which one are supported and how to construct relations !!!info
visit [relations][relations]. To see which relations are supported and how to construct relations
visit [relations][relations].
For simplicity available methods to fetch and save the data into the database are For simplicity available methods to fetch and save the data into the database are
divided into categories according to the function they fulfill. divided into categories according to the function they fulfill.
@ -20,7 +21,7 @@ For complicity also Models and relations methods are listed.
To read more about any specific section or function please refer to the details subpage. To read more about any specific section or function please refer to the details subpage.
### Create ###[Insert data into database](./create.md)
* `create(**kwargs) -> Model` * `create(**kwargs) -> Model`
* `get_or_create(**kwargs) -> Model` * `get_or_create(**kwargs) -> Model`
@ -39,7 +40,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.get_or_create(**kwargs)` method * `QuerysetProxy.get_or_create(**kwargs)` method
* `QuerysetProxy.update_or_create(**kwargs)` method * `QuerysetProxy.update_or_create(**kwargs)` method
### Read ### [Read data from database](./read.md)
* `get(**kwargs) -> Model` * `get(**kwargs) -> Model`
* `get_or_create(**kwargs) -> Model` * `get_or_create(**kwargs) -> Model`
@ -57,7 +58,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.first()` method * `QuerysetProxy.first()` method
* `QuerysetProxy.all(**kwargs)` method * `QuerysetProxy.all(**kwargs)` method
### Update ### [Update data in database](./update.md)
* `update(each: bool = False, **kwargs) -> int` * `update(each: bool = False, **kwargs) -> int`
* `update_or_create(**kwargs) -> Model` * `update_or_create(**kwargs) -> Model`
@ -73,7 +74,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy` * `QuerysetProxy`
* `QuerysetProxy.update_or_create(**kwargs)` method * `QuerysetProxy.update_or_create(**kwargs)` method
### Delete ### [Delete data from database](./delete.md)
* `delete(each: bool = False, **kwargs) -> int` * `delete(each: bool = False, **kwargs) -> int`
@ -86,7 +87,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.remove()` method * `QuerysetProxy.remove()` method
* `QuerysetProxy.clear()` method * `QuerysetProxy.clear()` method
### Joins and subqueries ### [Joins and subqueries](./joins-and-subqueries.md)
* `select_related(related: Union[List, str]) -> QuerySet` * `select_related(related: Union[List, str]) -> QuerySet`
* `prefetch_related(related: Union[List, str]) -> QuerySet` * `prefetch_related(related: Union[List, str]) -> QuerySet`
@ -100,7 +101,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.select_related(related: Union[List, str])` method * `QuerysetProxy.select_related(related: Union[List, str])` method
* `QuerysetProxy.prefetch_related(related: Union[List, str])` method * `QuerysetProxy.prefetch_related(related: Union[List, str])` method
### Filtering and sorting ### [Filtering and sorting](./filter-and-sort.md)
* `filter(**kwargs) -> QuerySet` * `filter(**kwargs) -> QuerySet`
* `exclude(**kwargs) -> QuerySet` * `exclude(**kwargs) -> QuerySet`
@ -118,7 +119,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.get_or_create(**kwargs)` method * `QuerysetProxy.get_or_create(**kwargs)` method
* `QuerysetProxy.all(**kwargs)` method * `QuerysetProxy.all(**kwargs)` method
### Selecting columns ### [Selecting columns](./select-columns.md)
* `fields(columns: Union[List, str, set, dict]) -> QuerySet` * `fields(columns: Union[List, str, set, dict]) -> QuerySet`
* `exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet` * `exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet`
@ -128,7 +129,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.fields(columns: Union[List, str, set, dict])` method * `QuerysetProxy.fields(columns: Union[List, str, set, dict])` method
* `QuerysetProxy.exclude_fields(columns: Union[List, str, set, dict])` method * `QuerysetProxy.exclude_fields(columns: Union[List, str, set, dict])` method
### Pagination and rows number ### [Pagination and rows number](./pagination-and-rows-number.md)
* `paginate(page: int) -> QuerySet` * `paginate(page: int) -> QuerySet`
* `limit(limit_count: int) -> QuerySet` * `limit(limit_count: int) -> QuerySet`
@ -142,7 +143,7 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.limit(limit_count: int)` method * `QuerysetProxy.limit(limit_count: int)` method
* `QuerysetProxy.offset(offset: int)` method * `QuerysetProxy.offset(offset: int)` method
### Aggregated functions ### [Aggregated functions](./aggregations.md)
* `count() -> int` * `count() -> int`
* `exists() -> bool` * `exists() -> bool`
@ -153,4 +154,4 @@ To read more about any specific section or function please refer to the details
* `QuerysetProxy.exists()` method * `QuerysetProxy.exists()` method
[relations]: ./relations/index.md [relations]: ../relations/index.md

View File

@ -1,6 +1,18 @@
# Joins and subqueries # Joins and subqueries
To join one table to another, so load also related models you can use following methods.
* `select_related(related: Union[List, str]) -> QuerySet`
* `prefetch_related(related: Union[List, str]) -> QuerySet`
* `Model`
* `Model.load()` method
* `QuerysetProxy`
* `QuerysetProxy.select_related(related: Union[List, str])` method
* `QuerysetProxy.prefetch_related(related: Union[List, str])` method
## select_related ## select_related
@ -30,6 +42,30 @@ To chain related `Models` relation use double underscores between names.
!!!tip !!!tip
To control order of models (both main or nested) use `order_by()` method. To control order of models (both main or nested) use `order_by()` method.
```python
class Album(ormar.Model):
class Meta:
tablename = "albums"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_best_seller: bool = ormar.Boolean(default=False)
class Track(ormar.Model):
class Meta:
tablename = "tracks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
play_count: int = ormar.Integer(nullable=True)
```
```python ```python
album = await Album.objects.select_related("tracks").all() album = await Album.objects.select_related("tracks").all()
# will return album will all columns tracks # will return album will all columns tracks
@ -37,6 +73,52 @@ album = await Album.objects.select_related("tracks").all()
You can provide a string or a list of strings You can provide a string or a list of strings
```python
class SchoolClass(ormar.Model):
class Meta:
tablename = "schoolclasses"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
department: Optional[Department] = ormar.ForeignKey(Department, nullable=False)
class Category(ormar.Model):
class Meta:
tablename = "categories"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Student(ormar.Model):
class Meta:
tablename = "students"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(SchoolClass)
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
class Teacher(ormar.Model):
class Meta:
tablename = "teachers"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(SchoolClass)
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
```
```python ```python
classes = await SchoolClass.objects.select_related( classes = await SchoolClass.objects.select_related(
["teachers__category", "students"]).all() ["teachers__category", "students"]).all()
@ -81,12 +163,82 @@ To chain related `Models` relation use double underscores between names.
!!!tip !!!tip
To control order of models (both main or nested) use `order_by()` method. To control order of models (both main or nested) use `order_by()` method.
```python
class Album(ormar.Model):
class Meta:
tablename = "albums"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_best_seller: bool = ormar.Boolean(default=False)
class Track(ormar.Model):
class Meta:
tablename = "tracks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
play_count: int = ormar.Integer(nullable=True)
```
```python ```python
album = await Album.objects.prefetch_related("tracks").all() album = await Album.objects.prefetch_related("tracks").all()
# will return album will all columns tracks # will return album will all columns tracks
``` ```
You can provide a string or a list of strings You can provide a string, or a list of strings
```python
class SchoolClass(ormar.Model):
class Meta:
tablename = "schoolclasses"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
department: Optional[Department] = ormar.ForeignKey(Department, nullable=False)
class Category(ormar.Model):
class Meta:
tablename = "categories"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Student(ormar.Model):
class Meta:
tablename = "students"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(SchoolClass)
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
class Teacher(ormar.Model):
class Meta:
tablename = "teachers"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
schoolclass: Optional[SchoolClass] = ormar.ForeignKey(SchoolClass)
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
```
```python ```python
classes = await SchoolClass.objects.prefetch_related( classes = await SchoolClass.objects.prefetch_related(
@ -221,3 +373,44 @@ That means that in `prefetch_related` example above if there are 3 distinct mode
table B and 2 in table C, there will be only 5 children nested models shared between all table B and 2 in table C, there will be only 5 children nested models shared between all
model A instances. That also means that if you update any attribute it will be updated model A instances. That also means that if you update any attribute it will be updated
on all parents as they share the same child object. on all parents as they share the same child object.
## Model methods
Each model instance have a set of methods to `save`, `update` or `load` itself.
### load
You can load the `ForeignKey` related model by calling `load()` method.
`load()` can be used to refresh the model from the database (if it was changed by some other process).
!!!tip
Read more about `load()` method in [models methods](../models/methods.md#load)
## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey`
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create,
select related etc related models directly from parent model.
### select_related
Works exactly the same as [select_related](./#select_related) function above but allows you to fetch related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### prefetch_related
Works exactly the same as [prefetch_related](./#prefetch_related) function above but allows you to fetch related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
[querysetproxy]: ../relations/queryset-proxy.md

View File

@ -1,29 +1,57 @@
# Read/ Load data from database # Read data from database
* `get(**kwargs): -> Model` Following methods allow you to load data from the database.
* `get(**kwargs) -> Model`
* `get_or_create(**kwargs) -> Model` * `get_or_create(**kwargs) -> Model`
* `first(): -> Model` * `first() -> Model`
* `all(**kwargs) -> List[Optional[Model]]` * `all(**kwargs) -> List[Optional[Model]]`
* `Model.load() method`
* `Model`
* `Model.load()` method
* `QuerysetProxy`
* `QuerysetProxy.get(**kwargs)` method
* `QuerysetProxy.get_or_create(**kwargs)` method
* `QuerysetProxy.first()` method
* `QuerysetProxy.all(**kwargs)` method
## get ## get
`get(**kwargs): -> Model` `get(**kwargs) -> Model`
Get's the first row from the db meeting the criteria set by kwargs. Get's the first row from the db meeting the criteria set by kwargs.
If no criteria set it will return the last row in db sorted by pk. If no criteria set it will return the last row in db sorted by pk column.
Passing a criteria is actually calling filter(**kwargs) method described below. Passing a criteria is actually calling filter(**kwargs) method described below.
```python
class Track(ormar.Model):
class Meta:
tablename = "track"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
name: str = ormar.String(max_length=100)
position: int = ormar.Integer()
```
```python ```python
track = await Track.objects.get(name='The Bird') track = await Track.objects.get(name='The Bird')
# note that above is equivalent to await Track.objects.filter(name='The Bird').get() # note that above is equivalent to await Track.objects.filter(name='The Bird').get()
track2 = track = await Track.objects.get() track2 = track = await Track.objects.get()
track == track2 # True since it's the only row in db in our example track == track2
# True since it's the only row in db in our example
# and get without arguments return first row by pk column desc
``` ```
!!!warning If no row meets the criteria `NoMatch` exception is raised. !!!warning
If no row meets the criteria `NoMatch` exception is raised.
If there are multiple rows meeting the criteria the `MultipleMatches` exception is raised. If there are multiple rows meeting the criteria the `MultipleMatches` exception is raised.
@ -36,6 +64,17 @@ Combination of create and get methods.
Tries to get a row meeting the criteria and if `NoMatch` exception is raised it creates Tries to get a row meeting the criteria and if `NoMatch` exception is raised it creates
a new one with given kwargs. a new one with given kwargs.
```python
class Album(ormar.Model):
class Meta:
tablename = "album"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
```
```python ```python
album = await Album.objects.get_or_create(name='The Cat') album = await Album.objects.get_or_create(name='The Cat')
# object is created as it does not exist # object is created as it does not exist
@ -44,20 +83,41 @@ assert album == album2
# return True as the same db row is returned # return True as the same db row is returned
``` ```
!!!warning Despite being a equivalent row from database the `album` and `album2` in !!!warning
example above are 2 different python objects! Despite being an equivalent row from database the `album` and `album2` in
Updating one of them will not refresh the second one until you excplicitly load() the example above are 2 different python objects!
fresh data from db. Updating one of them will not refresh the second one until you excplicitly load() the
fresh data from db.
!!!note Note that if you want to create a new object you either have to pass pk column !!!note
value or pk column has to be set as autoincrement Note that if you want to create a new object you either have to pass pk column
value or pk column has to be set as autoincrement
## first ## first
`first(): -> Model` `first() -> Model`
Gets the first row from the db ordered by primary key column ascending. Gets the first row from the db ordered by primary key column ascending.
```python
class Album(ormar.Model):
class Meta:
tablename = "album"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
```
```python
await Album.objects.create(name='The Cat')
await Album.objects.create(name='The Dog')
album = await Album.objects.first()
# first row by primary_key column asc
assert album.name == 'The Cat'
```
## all ## all
`all(**kwargs) -> List[Optional["Model"]]` `all(**kwargs) -> List[Optional["Model"]]`
@ -69,12 +129,90 @@ Passing kwargs is a shortcut and equals to calling `filter(**kwrags).all()`.
If there are no rows meeting the criteria an empty list is returned. If there are no rows meeting the criteria an empty list is returned.
```python ```python
tracks = await Track.objects.select_related("album").all(title='Sample') class Album(ormar.Model):
# will return a list of all Tracks with title Sample class Meta:
tablename = "album"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Track(ormar.Model):
class Meta:
tablename = "track"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
```
```python
tracks = await Track.objects.select_related("album").all(album__title='Sample')
# will return a list of all Tracks for album Sample
# for more on joins visit joining and subqueries section
tracks = await Track.objects.all() tracks = await Track.objects.all()
# will return a list of all Tracks in database # will return a list of all Tracks in database
``` ```
## Model method ## Model methods
Each model instance have a set of methods to `save`, `update` or `load` itself.
### load
You can load the `ForeignKey` related model by calling `load()` method.
`load()` can be used to refresh the model from the database (if it was changed by some other process).
!!!tip
Read more about `load()` method in [models methods](../models/methods.md#load)
## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey`
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create,
select related etc related models directly from parent model.
### get
Works exactly the same as [get](./#get) function above but allows you to fetch related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### get_or_create
Works exactly the same as [get_or_create](./#get_or_create) function above but allows
you to query or create related objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### first
Works exactly the same as [first](./#first) function above but allows you to query
related objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
### all
Works exactly the same as [all](./#all) function above but allows you to query related
objects from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
[querysetproxy]: ../relations/queryset-proxy.md

View File

@ -1,11 +1,20 @@
# Update # Update data in database
Following methods and functions allow updating existing data in the database.
* `update(each: bool = False, **kwargs) -> int` * `update(each: bool = False, **kwargs) -> int`
* `update_or_create(**kwargs) -> Model` * `update_or_create(**kwargs) -> Model`
* `bulk_update(objects: List[Model], columns: List[str] = None) -> None` * `bulk_update(objects: List[Model], columns: List[str] = None) -> None`
* `Model.update() method`
* `Model.upsert() method`
* `Model.save_related() method` * `Model`
* `Model.update()` method
* `Model.upsert()` method
* `Model.save_related()` method
* `QuerysetProxy`
* `QuerysetProxy.update_or_create(**kwargs)` method
## update ## update
@ -24,8 +33,8 @@ Return number of rows updated.
--8<-- "../docs_src/queries/docs002.py" --8<-- "../docs_src/queries/docs002.py"
``` ```
!!!warning Queryset needs to be filtered before updating to prevent accidental !!!warning
overwrite. Queryset needs to be filtered before updating to prevent accidental overwrite.
To update whole database table `each=True` needs to be provided as a safety switch To update whole database table `each=True` needs to be provided as a safety switch
@ -39,8 +48,9 @@ Updates the model, or in case there is no match in database creates a new one.
--8<-- "../docs_src/queries/docs003.py" --8<-- "../docs_src/queries/docs003.py"
``` ```
!!!note Note that if you want to create a new object you either have to pass pk column !!!note
value or pk column has to be set as autoincrement Note that if you want to create a new object you either have to pass pk column
value or pk column has to be set as autoincrement
## bulk_update ## bulk_update
@ -67,5 +77,50 @@ completed = await ToDo.objects.filter(completed=False).all()
assert len(completed) == 3 assert len(completed) == 3
``` ```
## Model method ## Model methods
Each model instance have a set of methods to `save`, `update` or `load` itself.
###update
You can update models by updating your model attributes (fields) and calling `update()` method.
If you try to update a model without a primary key set a `ModelPersistenceError` exception will be thrown.
!!!tip
Read more about `update()` method in [models-update](../models/methods.md#update)
###upsert
It's a proxy to either `save()` or `update(**kwargs)` methods of a Model.
If the pk is set the `update()` method will be called.
!!!tip
Read more about `upsert()` method in [models-upsert][models-upsert]
###save_related
Method goes through all relations of the `Model` on which the method is called,
and calls `upsert()` method on each model that is **not** saved.
!!!tip
Read more about `save_related()` method in [models-save-related][models-save-related]
## QuerysetProxy methods
When access directly the related `ManyToMany` field as well as `ReverseForeignKey` returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create, select related etc related models directly from parent model.
### update_or_create
Works exactly the same as [update_or_create](./#update_or_create) function above but allows you to update or create related objects
from other side of the relation.
!!!tip
To read more about `QuerysetProxy` visit [querysetproxy][querysetproxy] section
[querysetproxy]: ../relations/queryset-proxy.md
[models-upsert]: ../models/methods.md#upsert
[models-save-related]: ../models/methods.md#save_related

View File

@ -84,9 +84,9 @@ nav:
- Exceptions: api/exceptions.md - Exceptions: api/exceptions.md
repo_name: collerek/ormar repo_name: collerek/ormar
repo_url: https://github.com/collerek/ormar repo_url: https://github.com/collerek/ormar
google_analytics: #google_analytics:
- UA-72514911-3 # - UA-72514911-3
- auto # - auto
theme: theme:
name: material name: material
highlightjs: true highlightjs: true