From 593d233a46ee3b39f5afee119fd694a6625bf586 Mon Sep 17 00:00:00 2001 From: collerek Date: Sun, 4 Apr 2021 17:27:34 +0200 Subject: [PATCH] fix too long fk names --- docs/models/methods.md | 30 ++++++++-- docs/releases.md | 6 +- .../test_nested_reverse_relations.py | 58 +++++++------------ .../test_queries/test_reverse_fk_queryset.py | 8 +-- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/docs/models/methods.md b/docs/models/methods.md index d8d25b1..9dc722b 100644 --- a/docs/models/methods.md +++ b/docs/models/methods.md @@ -10,6 +10,13 @@ Each model instance have a set of methods to `save`, `update` or `load` itself. Available methods are described below. +## `pydantic` methods + +Note that each `ormar.Model` is also a `pydantic.BaseModel`, so all `pydantic` methods are also available on a model, +especially `dict()` and `json()` methods that can also accept `exclude`, `include` and other parameters. + +To read more check [pydantic][pydantic] documentation + ## load By default when you query a table without prefetching related models, the ormar will still construct @@ -127,7 +134,7 @@ await track.delete() # will delete the model from database ## save_related -`save_related(follow: bool = False) -> None` +`save_related(follow: bool = False, save_all: bool = False, exclude=Optional[Union[Set, Dict]]) -> None` 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. @@ -138,16 +145,27 @@ By default the `save_related` method saved only models that are directly related But you can specify the `follow=True` parameter to traverse through nested models and save all of them in the relation tree. +By default save_related saves only model that has not `saved` status, meaning that they were modified in current scope. + +If you want to force saving all of the related methods use `save_all=True` flag, which will upsert all related models, regardless of their save status. + +If you want to skip saving some of the relations you can pass `exclude` parameter. + +`Exclude` can be a set of own model relations, +or it can be a dictionary that can also contain nested items. + +!!!note + Note that `exclude` parameter in `save_related` accepts only relation fields names, so + if you pass any other fields they will be saved anyway + +!!!note + To read more about the structure of possible values passed to `exclude` check `Queryset.fields` method documentation. + !!!warning To avoid circular updates with `follow=True` set, `save_related` keeps a set of already visited Models, and won't perform nested `save_related` on Models that were already visited. So if you have a diamond or circular relations types you need to perform the updates in a manual way. - - ```python - # in example like this the second Street (coming from City) won't be save_related, so ZipCode won't be updated - Street -> District -> City -> Street -> ZipCode - ``` [fields]: ../fields.md [relations]: ../relations/index.md diff --git a/docs/releases.md b/docs/releases.md index c10e7c3..5ffe249 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1,6 +1,6 @@ # 0.10.2 -## Features +## ✨ Features * `Model.save_related(follow=False)` now accept also two additional arguments: `Model.save_related(follow=False, save_all=False, exclude=None)`. * `save_all:bool` -> By default (so with `save_all=False`) `ormar` only upserts models that are not saved (so new or updated ones), @@ -19,7 +19,7 @@ * Same thing applies to `QuerysetProxy.update(each=False, **kwargs)` which also previously required that you either pass a `filter` (by `**kwargs` or as a separate `filter()` call) or set `each=True` now also accepts `exclude()` calls that generates NOT filter. So either `each=True` needs to be set to update whole table or at least one of `filter/exclude` clauses. -## Fixes +## 🐛 Fixes * Fix improper relation field resolution in `QuerysetProxy` if fk column has different database alias. * Fix hitting recursion error with very complicated models structure with loops when calling `dict()`. @@ -28,7 +28,7 @@ * Fix bug when bulk_create would try to save also `property_field` decorated methods and `pydantic` fields * Fix wrong merging of deeply nested chain of reversed relations -## Other +## 💬 Other * Performance optimizations * Split tests into packages based on tested area diff --git a/tests/test_queries/test_nested_reverse_relations.py b/tests/test_queries/test_nested_reverse_relations.py index 14b4544..32c2cde 100644 --- a/tests/test_queries/test_nested_reverse_relations.py +++ b/tests/test_queries/test_nested_reverse_relations.py @@ -20,36 +20,30 @@ class DataSource(ormar.Model): class Meta(BaseMeta): tablename = "datasources" - source_id: int = ormar.Integer(primary_key=True) + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, unique=True, index=True) class DataSourceTable(ormar.Model): class Meta(BaseMeta): - tablename = "datasource_tables" + tablename = "tables" - datasource_table_id: int = ormar.Integer(primary_key=True) + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) - data_source: Optional[DataSource] = ormar.ForeignKey( - DataSource, - name="data_source_id", - related_name="datasource_tables", - ondelete="CASCADE", + source: Optional[DataSource] = ormar.ForeignKey( + DataSource, name="source_id", related_name="tables", ondelete="CASCADE", ) class DataSourceTableColumn(ormar.Model): class Meta(BaseMeta): - tablename = "datasource_table_columns" + tablename = "columns" - datasource_table_column_id: int = ormar.Integer(primary_key=True) + id: int = ormar.Integer(primary_key=True) name: str = ormar.String(max_length=200, index=True) data_type: str = ormar.String(max_length=200) - datasource_table: Optional[DataSourceTable] = ormar.ForeignKey( - DataSourceTable, - name="datasource_table_id", - related_name="datasource_table_columns", - ondelete="CASCADE", + table: Optional[DataSourceTable] = ormar.ForeignKey( + DataSourceTable, name="table_id", related_name="columns", ondelete="CASCADE", ) @@ -69,7 +63,7 @@ async def test_double_nested_reverse_relation(): test_tables = [ { "name": "test1", - "datasource_table_columns": [ + "columns": [ {"name": "col1", "data_type": "test"}, {"name": "col2", "data_type": "test2"}, {"name": "col3", "data_type": "test3"}, @@ -77,14 +71,14 @@ async def test_double_nested_reverse_relation(): }, { "name": "test2", - "datasource_table_columns": [ + "columns": [ {"name": "col4", "data_type": "test"}, {"name": "col5", "data_type": "test2"}, {"name": "col6", "data_type": "test3"}, ], }, ] - data_source.datasource_tables = test_tables + data_source.tables = test_tables await data_source.save_related(save_all=True, follow=True) tables = await DataSourceTable.objects.all() @@ -94,24 +88,14 @@ async def test_double_nested_reverse_relation(): assert len(columns) == 6 data_source = ( - await DataSource.objects.select_related( - "datasource_tables__datasource_table_columns" - ) - .filter(datasource_tables__name__in=["test1", "test2"], name="local") + await DataSource.objects.select_related("tables__columns") + .filter(tables__name__in=["test1", "test2"], name="local") .get() ) - assert len(data_source.datasource_tables) == 2 - assert len(data_source.datasource_tables[0].datasource_table_columns) == 3 - assert ( - data_source.datasource_tables[0].datasource_table_columns[0].name == "col1" - ) - assert ( - data_source.datasource_tables[0].datasource_table_columns[2].name == "col3" - ) - assert len(data_source.datasource_tables[1].datasource_table_columns) == 3 - assert ( - data_source.datasource_tables[1].datasource_table_columns[0].name == "col4" - ) - assert ( - data_source.datasource_tables[1].datasource_table_columns[2].name == "col6" - ) + assert len(data_source.tables) == 2 + assert len(data_source.tables[0].columns) == 3 + assert data_source.tables[0].columns[0].name == "col1" + assert data_source.tables[0].columns[2].name == "col3" + assert len(data_source.tables[1].columns) == 3 + assert data_source.tables[1].columns[0].name == "col4" + assert data_source.tables[1].columns[2].name == "col6" diff --git a/tests/test_queries/test_reverse_fk_queryset.py b/tests/test_queries/test_reverse_fk_queryset.py index dd2c49b..80193bc 100644 --- a/tests/test_queries/test_reverse_fk_queryset.py +++ b/tests/test_queries/test_reverse_fk_queryset.py @@ -18,7 +18,7 @@ class Album(ormar.Model): metadata = metadata database = database - id: int = ormar.Integer(primary_key=True) + id: int = ormar.Integer(primary_key=True, name="album_id") name: str = ormar.String(max_length=100) is_best_seller: bool = ormar.Boolean(default=False) @@ -29,7 +29,7 @@ class Writer(ormar.Model): metadata = metadata database = database - id: int = ormar.Integer(primary_key=True) + id: int = ormar.Integer(primary_key=True, name="writer_id") name: str = ormar.String(max_length=100) @@ -40,11 +40,11 @@ class Track(ormar.Model): database = database id: int = ormar.Integer(primary_key=True) - album: Optional[Album] = ormar.ForeignKey(Album) + album: Optional[Album] = ormar.ForeignKey(Album, name="album_id") title: str = ormar.String(max_length=100) position: int = ormar.Integer() play_count: int = ormar.Integer(nullable=True) - written_by: Optional[Writer] = ormar.ForeignKey(Writer) + written_by: Optional[Writer] = ormar.ForeignKey(Writer, name="writer_id") async def get_sample_data():