add more test with inheritance, fix ordering of subquery in first and get, regenerate api docs with only documented items

This commit is contained in:
collerek
2021-01-06 14:35:18 +01:00
parent bca77a3687
commit e42bf110cd
28 changed files with 139 additions and 437 deletions

View File

@ -68,13 +68,6 @@ Raised for errors in query definition:
* using Queryset.update() without filter and setting each flag to True
* using Queryset.delete() without filter and setting each flag to True
<a name="exceptions.RelationshipInstanceError"></a>
## RelationshipInstanceError Objects
```python
class RelationshipInstanceError(AsyncOrmException)
```
<a name="exceptions.ModelPersistenceError"></a>
## ModelPersistenceError Objects

View File

@ -16,60 +16,6 @@ All values are kept as class variables, ormar Fields are never instantiated.
Subclasses pydantic.FieldInfo to keep the fields related
to pydantic field types like ConstrainedStr
<a name="fields.base.BaseField.__type__"></a>
#### \_\_type\_\_
<a name="fields.base.BaseField.related_name"></a>
#### related\_name
<a name="fields.base.BaseField.column_type"></a>
#### column\_type
<a name="fields.base.BaseField.constraints"></a>
#### constraints
<a name="fields.base.BaseField.name"></a>
#### name
<a name="fields.base.BaseField.alias"></a>
#### alias
<a name="fields.base.BaseField.primary_key"></a>
#### primary\_key
<a name="fields.base.BaseField.autoincrement"></a>
#### autoincrement
<a name="fields.base.BaseField.nullable"></a>
#### nullable
<a name="fields.base.BaseField.index"></a>
#### index
<a name="fields.base.BaseField.unique"></a>
#### unique
<a name="fields.base.BaseField.pydantic_only"></a>
#### pydantic\_only
<a name="fields.base.BaseField.virtual"></a>
#### virtual
<a name="fields.base.BaseField.choices"></a>
#### choices
<a name="fields.base.BaseField.to"></a>
#### to
<a name="fields.base.BaseField.through"></a>
#### through
<a name="fields.base.BaseField.default"></a>
#### default
<a name="fields.base.BaseField.server_default"></a>
#### server\_default
<a name="fields.base.BaseField.is_valid_uni_relation"></a>
#### is\_valid\_uni\_relation

View File

@ -67,15 +67,6 @@ class ForeignKeyConstraint()
Internal container to store ForeignKey definitions used later
to produce sqlalchemy.ForeignKeys
<a name="fields.foreign_key.ForeignKeyConstraint.name"></a>
#### name
<a name="fields.foreign_key.ForeignKeyConstraint.ondelete"></a>
#### ondelete
<a name="fields.foreign_key.ForeignKeyConstraint.onupdate"></a>
#### onupdate
<a name="fields.foreign_key.ForeignKey"></a>
#### ForeignKey
@ -116,18 +107,6 @@ class ForeignKeyField(BaseField)
Actual class returned from ForeignKey function call and stored in model_fields.
<a name="fields.foreign_key.ForeignKeyField.to"></a>
#### to
<a name="fields.foreign_key.ForeignKeyField.name"></a>
#### name
<a name="fields.foreign_key.ForeignKeyField.related_name"></a>
#### related\_name
<a name="fields.foreign_key.ForeignKeyField.virtual"></a>
#### virtual
<a name="fields.foreign_key.ForeignKeyField._extract_model_from_sequence"></a>
#### \_extract\_model\_from\_sequence

View File

@ -1,9 +1,6 @@
<a name="fields.many_to_many"></a>
# fields.many\_to\_many
<a name="fields.many_to_many.REF_PREFIX"></a>
#### REF\_PREFIX
<a name="fields.many_to_many.ManyToMany"></a>
#### ManyToMany
@ -40,9 +37,6 @@ class ManyToManyField(ForeignKeyField, ormar.QuerySetProtocol, ormar.RelationP
Actual class returned from ManyToMany function call and stored in model_fields.
<a name="fields.many_to_many.ManyToManyField.through"></a>
#### through
<a name="fields.many_to_many.ManyToManyField.default_target_field_name"></a>
#### default\_target\_field\_name

View File

@ -48,19 +48,6 @@ class ModelFieldFactory()
Default field factory that construct Field classes and populated their values.
<a name="fields.model_fields.ModelFieldFactory._bases"></a>
#### \_bases
<a name="fields.model_fields.ModelFieldFactory._type"></a>
#### \_type
<a name="fields.model_fields.ModelFieldFactory.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *args: Any, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.ModelFieldFactory.get_column_type"></a>
#### get\_column\_type
@ -103,16 +90,6 @@ class String(ModelFieldFactory, str)
String field factory that construct Field classes and populated their values.
<a name="fields.model_fields.String._type"></a>
#### \_type
<a name="fields.model_fields.String.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, allow_blank: bool = True, strip_whitespace: bool = False, min_length: int = None, max_length: int = None, curtail_length: int = None, regex: str = None, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.String.get_column_type"></a>
#### get\_column\_type
@ -155,16 +132,6 @@ class Integer(ModelFieldFactory, int)
Integer field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Integer._type"></a>
#### \_type
<a name="fields.model_fields.Integer.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, minimum: int = None, maximum: int = None, multiple_of: int = None, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.Integer.get_column_type"></a>
#### get\_column\_type
@ -193,16 +160,6 @@ class Text(ModelFieldFactory, str)
Text field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Text._type"></a>
#### \_type
<a name="fields.model_fields.Text.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, allow_blank: bool = True, strip_whitespace: bool = False, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.Text.get_column_type"></a>
#### get\_column\_type
@ -231,16 +188,6 @@ class Float(ModelFieldFactory, float)
Float field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Float._type"></a>
#### \_type
<a name="fields.model_fields.Float.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, minimum: float = None, maximum: float = None, multiple_of: int = None, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.Float.get_column_type"></a>
#### get\_column\_type
@ -269,9 +216,6 @@ class DateTime(ModelFieldFactory, datetime.datetime)
DateTime field factory that construct Field classes and populated their values.
<a name="fields.model_fields.DateTime._type"></a>
#### \_type
<a name="fields.model_fields.DateTime.get_column_type"></a>
#### get\_column\_type
@ -300,9 +244,6 @@ class Date(ModelFieldFactory, datetime.date)
Date field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Date._type"></a>
#### \_type
<a name="fields.model_fields.Date.get_column_type"></a>
#### get\_column\_type
@ -331,9 +272,6 @@ class Time(ModelFieldFactory, datetime.time)
Time field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Time._type"></a>
#### \_type
<a name="fields.model_fields.Time.get_column_type"></a>
#### get\_column\_type
@ -362,9 +300,6 @@ class JSON(ModelFieldFactory, pydantic.Json)
JSON field factory that construct Field classes and populated their values.
<a name="fields.model_fields.JSON._type"></a>
#### \_type
<a name="fields.model_fields.JSON.get_column_type"></a>
#### get\_column\_type
@ -393,16 +328,6 @@ class BigInteger(Integer, int)
BigInteger field factory that construct Field classes and populated their values.
<a name="fields.model_fields.BigInteger._type"></a>
#### \_type
<a name="fields.model_fields.BigInteger.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, minimum: int = None, maximum: int = None, multiple_of: int = None, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.BigInteger.get_column_type"></a>
#### get\_column\_type
@ -431,16 +356,6 @@ class Decimal(ModelFieldFactory, decimal.Decimal)
Decimal field factory that construct Field classes and populated their values.
<a name="fields.model_fields.Decimal._type"></a>
#### \_type
<a name="fields.model_fields.Decimal.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, minimum: float = None, maximum: float = None, multiple_of: int = None, precision: int = None, scale: int = None, max_digits: int = None, decimal_places: int = None, **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.Decimal.get_column_type"></a>
#### get\_column\_type
@ -483,16 +398,6 @@ class UUID(ModelFieldFactory, uuid.UUID)
UUID field factory that construct Field classes and populated their values.
<a name="fields.model_fields.UUID._type"></a>
#### \_type
<a name="fields.model_fields.UUID.__new__"></a>
#### \_\_new\_\_
```python
| __new__(cls, *, uuid_format: str = "hex", **kwargs: Any) -> Type[BaseField]
```
<a name="fields.model_fields.UUID.get_column_type"></a>
#### get\_column\_type

View File

@ -1,9 +1,6 @@
<a name="models.helpers.relations"></a>
# models.helpers.relations
<a name="models.helpers.relations.alias_manager"></a>
#### alias\_manager
<a name="models.helpers.relations.register_relation_on_build"></a>
#### register\_relation\_on\_build

View File

@ -1,59 +1,6 @@
<a name="models.metaclass"></a>
# models.metaclass
<a name="models.metaclass.PARSED_FIELDS_KEY"></a>
#### PARSED\_FIELDS\_KEY
<a name="models.metaclass.CONFIG_KEY"></a>
#### CONFIG\_KEY
<a name="models.metaclass.ModelMeta"></a>
## ModelMeta Objects
```python
class ModelMeta()
```
Class used for type hinting.
Users can subclass this one for convenience but it's not required.
The only requirement is that ormar.Model has to have inner class with name Meta.
<a name="models.metaclass.ModelMeta.tablename"></a>
#### tablename
<a name="models.metaclass.ModelMeta.table"></a>
#### table
<a name="models.metaclass.ModelMeta.metadata"></a>
#### metadata
<a name="models.metaclass.ModelMeta.database"></a>
#### database
<a name="models.metaclass.ModelMeta.columns"></a>
#### columns
<a name="models.metaclass.ModelMeta.constraints"></a>
#### constraints
<a name="models.metaclass.ModelMeta.pkname"></a>
#### pkname
<a name="models.metaclass.ModelMeta.model_fields"></a>
#### model\_fields
<a name="models.metaclass.ModelMeta.alias_manager"></a>
#### alias\_manager
<a name="models.metaclass.ModelMeta.property_fields"></a>
#### property\_fields
<a name="models.metaclass.ModelMeta.signals"></a>
#### signals
<a name="models.metaclass.ModelMeta.abstract"></a>
#### abstract
<a name="models.metaclass.check_if_field_has_choices"></a>
#### check\_if\_field\_has\_choices
@ -233,6 +180,33 @@ Updates Meta parameters in child from parent if needed.
- `attrs (Dict)`: new namespace for class being constructed
- `model_fields (Dict[str, BaseField])`: ormar fields in defined in current class
<a name="models.metaclass.copy_and_replace_m2m_through_model"></a>
#### copy\_and\_replace\_m2m\_through\_model
```python
copy_and_replace_m2m_through_model(field: Type[ManyToManyField], field_name: str, table_name: str, parent_fields: Dict, attrs: Dict, meta: ModelMeta) -> None
```
Clones class with Through model for m2m relations, appends child name to the name
of the cloned class.
Clones non foreign keys fields from parent model, the same with database columns.
Modifies related_name with appending child table name after '_'
For table name, the table name of child is appended after '_'.
Removes the original sqlalchemy table from metadata if it was not removed.
**Arguments**:
- `field (Type[ManyToManyField])`: field with relations definition
- `field_name (str)`: name of the relation field
- `table_name (str)`: name of the table
- `parent_fields (Dict)`: dictionary of fields to copy to new models from parent
- `attrs (Dict)`: new namespace for class being constructed
- `meta (ModelMeta)`: metaclass of currently created model
<a name="models.metaclass.copy_data_from_parent_model"></a>
#### copy\_data\_from\_parent\_model
@ -296,6 +270,18 @@ If the class is a ormar.Model it is skipped.
`(Tuple[Dict, Dict])`: updated attrs and model_fields
<a name="models.metaclass.ModelMeta"></a>
## ModelMeta Objects
```python
class ModelMeta()
```
Class used for type hinting.
Users can subclass this one for convenience but it's not required.
The only requirement is that ormar.Model has to have inner class with name Meta.
<a name="models.metaclass.ModelMetaclass"></a>
## ModelMetaclass Objects

View File

@ -24,9 +24,6 @@ will become:
`(Dict[str, List])`: list converted to dictionary to avoid repetition and group nested models
<a name="models.model.T"></a>
#### T
<a name="models.model.Model"></a>
## Model Objects
@ -34,16 +31,6 @@ will become:
class Model(NewBaseModel)
```
<a name="models.model.Model.__abstract__"></a>
#### \_\_abstract\_\_
<a name="models.model.Model.__repr__"></a>
#### \_\_repr\_\_
```python
| __repr__() -> str
```
<a name="models.model.Model.from_row"></a>
#### from\_row
@ -271,7 +258,7 @@ Sets model save status to True.
**Raises**:
- `ModelPersistenceError`: If the pk column is not set will throw ModelPersistenceError
- `ModelPersistenceError`: If the pk column is not set
**Arguments**:
@ -315,7 +302,7 @@ Does NOT refresh the related models fields if they were loaded before.
**Raises**:
- `NoMatch`: If given pk is not found in database the NoMatch exception is raised.
- `NoMatch`: If given pk is not found in database.
**Returns**:

View File

@ -15,9 +15,6 @@ Constructed with ModelMetaclass which in turn also inherits pydantic metaclass.
Abstracts away all internals and helper functions, so final Model class has only
the logic concerned with database connection and data persistance.
<a name="models.newbasemodel.NewBaseModel.__slots__"></a>
#### \_\_slots\_\_
<a name="models.newbasemodel.NewBaseModel.__init__"></a>
#### \_\_init\_\_

View File

@ -1,12 +1,6 @@
<a name="queryset.clause"></a>
# queryset.clause
<a name="queryset.clause.FILTER_OPERATORS"></a>
#### FILTER\_OPERATORS
<a name="queryset.clause.ESCAPE_CHARACTERS"></a>
#### ESCAPE\_CHARACTERS
<a name="queryset.clause.QueryClause"></a>
## QueryClause Objects
@ -16,13 +10,6 @@ class QueryClause()
Constructs where clauses from strings passed as arguments
<a name="queryset.clause.QueryClause.__init__"></a>
#### \_\_init\_\_
```python
| __init__(model_cls: Type["Model"], filter_clauses: List, select_related: List) -> None
```
<a name="queryset.clause.QueryClause.filter"></a>
#### filter

View File

@ -10,13 +10,6 @@ class FilterQuery()
Modifies the select query with given list of where/filter clauses.
<a name="queryset.filter_query.FilterQuery.__init__"></a>
#### \_\_init\_\_
```python
| __init__(filter_clauses: List, exclude: bool = False) -> None
```
<a name="queryset.filter_query.FilterQuery.apply"></a>
#### apply

View File

@ -10,18 +10,6 @@ class JoinParameters(NamedTuple)
Named tuple that holds set of parameters passed during join construction.
<a name="queryset.join.JoinParameters.prev_model"></a>
#### prev\_model
<a name="queryset.join.JoinParameters.previous_alias"></a>
#### previous\_alias
<a name="queryset.join.JoinParameters.from_table"></a>
#### from\_table
<a name="queryset.join.JoinParameters.model_cls"></a>
#### model\_cls
<a name="queryset.join.SqlJoin"></a>
## SqlJoin Objects
@ -29,13 +17,6 @@ Named tuple that holds set of parameters passed during join construction.
class SqlJoin()
```
<a name="queryset.join.SqlJoin.__init__"></a>
#### \_\_init\_\_
```python
| __init__(used_aliases: List, select_from: sqlalchemy.sql.select, columns: List[sqlalchemy.Column], fields: Optional[Union[Set, Dict]], exclude_fields: Optional[Union[Set, Dict]], order_columns: Optional[List], sorted_orders: OrderedDict) -> None
```
<a name="queryset.join.SqlJoin.alias_manager"></a>
#### alias\_manager

View File

@ -10,13 +10,6 @@ class LimitQuery()
Modifies the select query with limit clause.
<a name="queryset.limit_query.LimitQuery.__init__"></a>
#### \_\_init\_\_
```python
| __init__(limit_count: Optional[int]) -> None
```
<a name="queryset.limit_query.LimitQuery.apply"></a>
#### apply

View File

@ -10,13 +10,6 @@ class OffsetQuery()
Modifies the select query with offset if set
<a name="queryset.offset_query.OffsetQuery.__init__"></a>
#### \_\_init\_\_
```python
| __init__(query_offset: Optional[int]) -> None
```
<a name="queryset.offset_query.OffsetQuery.apply"></a>
#### apply

View File

@ -10,13 +10,6 @@ class OrderQuery()
Modifies the select query with given list of order_by clauses.
<a name="queryset.order_query.OrderQuery.__init__"></a>
#### \_\_init\_\_
```python
| __init__(sorted_orders: Dict) -> None
```
<a name="queryset.order_query.OrderQuery.apply"></a>
#### apply

View File

@ -77,13 +77,6 @@ Query used to fetch related models in subsequent queries.
Each model is fetched only ones by the name of the relation.
That means that for each prefetch_related entry next query is issued to database.
<a name="queryset.prefetch_query.PrefetchQuery.__init__"></a>
#### \_\_init\_\_
```python
| __init__(model_cls: Type["Model"], fields: Optional[Union[Dict, Set]], exclude_fields: Optional[Union[Dict, Set]], prefetch_related: List, select_related: List, orders_by: List) -> None
```
<a name="queryset.prefetch_query.PrefetchQuery.prefetch_related"></a>
#### prefetch\_related

View File

@ -10,20 +10,6 @@ class QuerySet()
Main class to perform database queries, exposed on each model as objects attribute.
<a name="queryset.queryset.QuerySet.__init__"></a>
#### \_\_init\_\_
```python
| __init__(model_cls: Type["Model"] = None, filter_clauses: List = None, exclude_clauses: List = None, select_related: List = None, limit_count: int = None, offset: int = None, columns: Dict = None, exclude_columns: Dict = None, order_bys: List = None, prefetch_related: List = None, limit_raw_sql: bool = False) -> None
```
<a name="queryset.queryset.QuerySet.__get__"></a>
#### \_\_get\_\_
```python
| __get__(instance: Optional[Union["QuerySet", "QuerysetProxy"]], owner: Union[Type["Model"], Type["QuerysetProxy"]]) -> "QuerySet"
```
<a name="queryset.queryset.QuerySet.model_meta"></a>
#### model\_meta

View File

@ -8,13 +8,6 @@
class Query()
```
<a name="queryset.query.Query.__init__"></a>
#### \_\_init\_\_
```python
| __init__(model_cls: Type["Model"], filter_clauses: List, exclude_clauses: List, select_related: List, limit_count: Optional[int], offset: Optional[int], fields: Optional[Union[Dict, Set]], exclude_fields: Optional[Union[Dict, Set]], order_bys: Optional[List], limit_raw_sql: bool) -> None
```
<a name="queryset.query.Query._init_sorted_orders"></a>
#### \_init\_sorted\_orders

View File

@ -27,13 +27,6 @@ class AliasManager()
Keep all aliases of relations between different tables.
One global instance is shared between all models.
<a name="relations.alias_manager.AliasManager.__init__"></a>
#### \_\_init\_\_
```python
| __init__() -> None
```
<a name="relations.alias_manager.AliasManager.prefixed_columns"></a>
#### prefixed\_columns

View File

@ -11,13 +11,6 @@ class QuerysetProxy(ormar.QuerySetProtocol)
Exposes QuerySet methods on relations, but also handles creating and removing
of through Models for m2m relations.
<a name="relations.querysetproxy.QuerysetProxy.__init__"></a>
#### \_\_init\_\_
```python
| __init__(relation: "Relation", type_: "RelationType", qryset: "QuerySet" = None) -> None
```
<a name="relations.querysetproxy.QuerysetProxy.queryset"></a>
#### queryset

View File

@ -10,13 +10,6 @@ class RelationsManager()
Manages relations on a Model, each Model has it's own instance.
<a name="relations.relation_manager.RelationsManager.__init__"></a>
#### \_\_init\_\_
```python
| __init__(related_fields: List[Type[ForeignKeyField]] = None, owner: "NewBaseModel" = None) -> None
```
<a name="relations.relation_manager.RelationsManager._get_relation_type"></a>
#### \_get\_relation\_type

View File

@ -10,13 +10,6 @@ class RelationProxy(list)
Proxy of the Relation that is a list with special methods.
<a name="relations.relation_proxy.RelationProxy.__init__"></a>
#### \_\_init\_\_
```python
| __init__(relation: "Relation", type_: "RelationType", field_name: str, data_: Any = None) -> None
```
<a name="relations.relation_proxy.RelationProxy.related_field_name"></a>
#### related\_field\_name

View File

@ -14,15 +14,6 @@ Different types of relations supported by ormar:
* reverse ForeignKey = REVERSE
* ManyToMany = MULTIPLE
<a name="relations.relation.RelationType.PRIMARY"></a>
#### PRIMARY
<a name="relations.relation.RelationType.REVERSE"></a>
#### REVERSE
<a name="relations.relation.RelationType.MULTIPLE"></a>
#### MULTIPLE
<a name="relations.relation.Relation"></a>
## Relation Objects
@ -119,10 +110,3 @@ Return the related model or models from RelationProxy.
`(Optional[Union[List[Model], Model]])`: related model/models if set
<a name="relations.relation.Relation.__repr__"></a>
#### \_\_repr\_\_
```python
| __repr__() -> str
```

View File

@ -1,12 +1,3 @@
<a name="signals"></a>
# signals
Signals and SignalEmitter that gathers the signals on models Meta.
Used to signal receivers functions about events, i.e. post_save, pre_delete etc.
<a name="signals.__all__"></a>
#### \_\_all\_\_
<a name="signals.signal"></a>
# signals.signal
@ -54,13 +45,6 @@ class Signal()
Signal that notifies all receiver functions.
In ormar used by models to send pre_save, post_save etc. signals.
<a name="signals.signal.Signal.__init__"></a>
#### \_\_init\_\_
```python
| __init__() -> None
```
<a name="signals.signal.Signal.connect"></a>
#### connect
@ -120,24 +104,3 @@ class SignalEmitter()
Emitter that registers the signals in internal dictionary.
If signal with given name does not exist it's auto added on access.
<a name="signals.signal.SignalEmitter.__init__"></a>
#### \_\_init\_\_
```python
| __init__() -> None
```
<a name="signals.signal.SignalEmitter.__getattr__"></a>
#### \_\_getattr\_\_
```python
| __getattr__(item: str) -> Signal
```
<a name="signals.signal.SignalEmitter.__setattr__"></a>
#### \_\_setattr\_\_
```python
| __setattr__(key: str, value: Any) -> None
```

View File

@ -88,9 +88,9 @@ class Query:
for clause in self.order_columns:
if "__" not in clause:
text_clause = (
text(f"{self.alias(clause[1:])} desc")
text(f"{self.table.name}.{self.alias(clause[1:])} desc")
if clause.startswith("-")
else text(self.alias(clause))
else text(f"{self.table.name}.{self.alias(clause)}")
)
self.sorted_orders[clause] = text_clause
else:
@ -202,11 +202,7 @@ class Query:
for filter_clause in self.exclude_clauses
if filter_clause.text.startswith(f"{self.table.name}.")
]
sorts_to_use = {
k: v
for k, v in self.sorted_orders.items()
if k.startswith(f"{self.table.name}.")
}
sorts_to_use = {k: v for k, v in self.sorted_orders.items() if "__" not in k}
expr = FilterQuery(filter_clauses=filters_to_use).apply(expr)
expr = FilterQuery(filter_clauses=excludes_to_use, exclude=True).apply(expr)
expr = OrderQuery(sorted_orders=sorts_to_use).apply(expr)

View File

@ -658,7 +658,7 @@ class QuerySet:
return await self.filter(**kwargs).first()
expr = self.build_select_expression(
limit=1, order_bys=[f"{self.model.Meta.pkname}"]
limit=1, order_bys=[f"{self.model.Meta.pkname}"] + self.order_bys
)
rows = await self.database.fetch_all(expr)
processed_rows = self._process_query_result_rows(rows)
@ -687,7 +687,7 @@ class QuerySet:
if not self.filter_clauses:
expr = self.build_select_expression(
limit=1, order_bys=[f"-{self.model.Meta.pkname}"]
limit=1, order_bys=[f"-{self.model.Meta.pkname}"] + self.order_bys
)
else:
expr = self.build_select_expression()

View File

@ -4,7 +4,7 @@ loaders:
search_path: [ormar/]
processors:
- type: filter
documented_only: false
documented_only: true
skip_empty_modules: false
exclude_private: false
exclude_special: false

View File

@ -369,6 +369,10 @@ async def test_inheritance_with_multi_relation():
).save()
await truck.co_owners.add(joe)
await truck.co_owners.add(alex)
bus3 = await Bus2(name="Unicorn 3", max_persons=30, owner=joe).save()
await bus3.co_owners.add(sam)
bus = await Bus2(name="Unicorn 2", max_persons=50, owner=sam).save()
await bus.co_owners.add(joe)
await bus.co_owners.add(alex)
@ -380,13 +384,35 @@ async def test_inheritance_with_multi_relation():
assert len(shelby.co_owners) == 2
assert shelby.max_capacity == 1400
unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get()
unicorn = await Bus2.objects.select_related(["owner", "co_owners"]).get(
name="Unicorn 2"
)
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name == "Sam"
assert unicorn.co_owners[0].name == "Joe"
assert len(unicorn.co_owners) == 2
assert unicorn.max_persons == 50
unicorn = (
await Bus2.objects.select_related(["owner", "co_owners"])
.order_by("-co_owners__name")
.get()
)
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name == "Sam"
assert len(unicorn.co_owners) == 2
assert unicorn.co_owners[0].name == "Joe"
unicorn = (
await Bus2.objects.select_related(["owner", "co_owners"])
.order_by("co_owners__name")
.get()
)
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name == "Sam"
assert len(unicorn.co_owners) == 2
assert unicorn.co_owners[0].name == "Alex"
joe_check = await Person.objects.select_related(
["coowned_trucks2", "coowned_buses2"]
).get(name="Joe")
@ -411,3 +437,68 @@ async def test_inheritance_with_multi_relation():
assert joe_check.coowned_trucks2[0].created_date is None
assert joe_check.coowned_buses2[0] == unicorn
assert joe_check.coowned_buses2[0].created_date is None
await shelby.co_owners.remove(joe)
await shelby.co_owners.remove(alex)
await Truck2.objects.delete(name="Shelby wanna be 2")
unicorn = (
await Bus2.objects.select_related(["owner", "co_owners"])
.filter(co_owners__name="Joe")
.get()
)
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name == "Sam"
assert unicorn.co_owners[0].name == "Joe"
assert len(unicorn.co_owners) == 1
assert unicorn.max_persons == 50
unicorn = (
await Bus2.objects.select_related(["owner", "co_owners"])
.exclude(co_owners__name="Joe")
.get()
)
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name == "Sam"
assert unicorn.co_owners[0].name == "Alex"
assert len(unicorn.co_owners) == 1
assert unicorn.max_persons == 50
unicorn = await Bus2.objects.get()
assert unicorn.name == "Unicorn 2"
assert unicorn.owner.name is None
assert len(unicorn.co_owners) == 0
await unicorn.co_owners.all()
assert len(unicorn.co_owners) == 2
assert unicorn.co_owners[0].name == "Joe"
await unicorn.owner.load()
assert unicorn.owner.name == "Sam"
unicorns = (
await Bus2.objects.select_related(["owner", "co_owners"])
.filter(name__contains="Unicorn")
.order_by("-name")
.all()
)
assert unicorns[0].name == "Unicorn 3"
assert unicorns[0].owner.name == "Joe"
assert len(unicorns[0].co_owners) == 1
assert unicorns[0].co_owners[0].name == "Sam"
assert unicorns[1].name == "Unicorn 2"
assert unicorns[1].owner.name == "Sam"
assert len(unicorns[1].co_owners) == 2
assert unicorns[1].co_owners[0].name == "Joe"
unicorns = (
await Bus2.objects.select_related(["owner", "co_owners"])
.filter(name__contains="Unicorn")
.order_by("-name")
.limit(2, limit_raw_sql=True)
.all()
)
assert len(unicorns) == 2
assert unicorns[1].name == "Unicorn 2"
assert len(unicorns[1].co_owners) == 1