Repository navigation
feat!: composite primary keys (relation keys, phase 2) - #1926
Conversation
…ro keys, release notes)
…se-2 # Conflicts: # ormar/models/descriptors/descriptors.py # tests/test_model_definition/test_primary_key.py
…N, persisted state)
…phase-2 # Conflicts: # docs/releases.md # ormar/fields/foreign_key.py # ormar/fields/many_to_many.py # ormar/models/descriptors/descriptors.py # ormar/models/helpers/sqlalchemy.py # ormar/models/mixins/save_mixin.py # ormar/models/model.py # ormar/models/newbasemodel.py # ormar/models/primary_key.py # ormar/queryset/clause.py # ormar/queryset/queryset.py # ormar/queryset/templates/writes.py # tests/test_model_definition/test_primary_key.py
Model.pk on a composite key is now a key accessor: == and in_() / << compile to the same row-value comparison as pk= / pk__in=, and asc() / desc() order by every key field. .pk also works after relations (Book.author.pk == 1) for single and composite keys.
Ordering by pk only worked in order_by() on the queried model. pk after
relations (order_by("stock__pk"), Shop.stock.pk.desc()), ormar_config
order_by=["-pk"] and relation orders_by / related_orders_by produced
invalid SQL, for single keys too. A shared order_actions_for() helper now
expands pk into the key fields of the model the chain points at, and is
used by QuerySet.order_by, model default ordering and join orderings.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will improve performance by 25.9%2 warnings, 1 note
Performance Changes
Tip Curious why performance improved? Comment Comparing |
Part of #137. Models can mark several fields with
primary_key=True; the key value is a tuple (order.pk == (1, 7)) and works withget(pk=...),filter(pk__in=...),exclude,order_by("pk"), bulk operations andupdate_or_create. Python-style filters work on composite keys too (Order.pk == (1, 7),Order.pk.in_([...]),Order.pk.desc()), and.pkworks after relations for every key (Book.author.pk == 1). ormar now remembers the key a model was loaded with, soupdate()/delete()/load()after a key change target the original row, andupsert()inserts never-saved models whose key is already set instead of silently updating nothing. Relations to composite-key models follow in the next PR. New docs page:docs/models/primary-keys.md.upsert()/ key-change semantics above;save()raisesModelPersistenceErrorfor a missing non-generated key value.pk, which produced invalid SQL everywhere:order_by("pk"), through relations (order_by("author__pk")),ormar_configorder_by=["-pk"]and relationorders_by/related_orders_by, single keys included. Also addspk__<op>lookups.test_model_definition.py::test_two_pks_in_model_definition,test_upsert.py::test_updating_selected_columns.