API
Ordered model
- class alliance_platform.ordered_model.models.OrderedModel(*args, **kwargs)[source]
OrderedModel will maintain the ordering field for you using database triggers.
Warning
As this uses database triggers only postgres is supported
Warning
Don’t add a unique constraint to the
order_field_name(orunique_togetherwhen usingorder_with_respect_to) -OrderedModelwill guarantee uniqueness for you. This is a technical limitation due to how the triggers are implemented.Guarantees that all records will have a unique value for
order_field_namewith respect toorder_with_respect_to(if specified). Whenever theorder_field_namechanges on a record all records will be updated as necessary to guarantee theirorder_field_nameis2away from each other. For example if you have 4 records then the ordering values will be[2, 4, 6, 8].This structure allows easy re-ordering by assigning an odd number to
order_field_name. eg. To move the first item between the second last and last it would be assigned to7.If a new record is created without an explicit ordering field value then it will be given the last current ordering value + 2 (ie. added to the end).
For example
Phaseis sorted on thesort_keycolumn with respect toboard.class Phase(OrderedModel): board = models.ForeignKey(Board, on_delete=models.CASCADE, related_name="phases") title = models.CharField(max_length=255) sort_key = models.PositiveIntegerField(blank=True) order_field_name = "sort_key" order_with_respect_to = ("board", )
To move a record to a new position with strict checks use
move_between(). This will validate that the relative order of the items moving between have not changed and will raise an error if they have. If strict checking isn’t desirable then you can callmove_before(),move_after(),move_start()ormove_end().When saving an
OrderedModeltheorder_field_nameis excluded by default. This is to avoid overwriting a new ordering that may have changed after the record was loaded. To explicitly save the field pass it toupdate_fieldsonsave.record.sort_key = move_after_record.sort_key + 1 record.save(update_fields=['sort_key'])
Warning
The value or
order_field_nameon a record may be inconsistent with the database value after a save due to updates caused by database triggers. If you need to read the value after an update you should callrefresh_from_dbor re-fetch the record.Bulk Updates
In some cases you may wish to defer saving individual changes to ordering and instead save the entire state in one go. You can use
bulk_update()and the trigger will happen once. Make sure to specifyupdate_fields.Shop.objects.bulk_update(shops, [Shop.order_field_name])
If you specify
batch_sizethen things won’t work properly as the trigger would run after each batch. To avoid problems with this or with saving multiple individual items you can usedefer_triggers(). This will disable the normal triggers until the end of the context block and instead update theorder_field_namemanually once at the end.NOTE: When using
order_with_respect_tothis will update all rows in the table even if they don’t require it. If usingnotify_on_reorderit will fire even if nothing has changed.with Shop.defer_triggers(): Shop.objects.bulk_update( shops_to_update, [Shop.order_field_name], batch_size=batch_size )
- classmethod defer_triggers(notification_op='UPDATE')[source]
A context manager that disables the ordering maintenance triggers and manually updates the ordering once at the end
This is useful when you need to do multiple database writes the change the
order_field_namevalue and having the triggers run each time would cause issues.Usage:
with Shop.defer_triggers(): Shop.objects.bulk_update( shops_to_update, [Shop.order_field_name], batch_size=10 )
Warning
When using
order_with_respect_toall rows in the table will be updated even if they don’t require it. If usingnotify_on_reorderit will fire even if nothing has changed and it will be fired for each unique combination oforder_with_respect_to.- Parameters:
notification_op – as it’s not possible to automatically determine what operation actually happened within the context block any notifications will have
operationset toUPDATE. If this is not correct for a particular use case passnotification_op="INSERT"ornotification_op="DELETE"instead. Only relevant whennotify_on_reorderis set.
- move_after(after)[source]
Move this item after the specified record or primary key
- Parameters:
after (Model | str | int) – Either the record or primary key of record to move this item after
- move_before(before)[source]
Move this item before the specified record or primary key
- Parameters:
before (Model | str | int) – Either the record or primary key of record to move this item before
- move_between(before, after)[source]
Insert this card between
beforeandafter_pk.Raises an error if
beforeandafterare no longer adjacent (eg. something else moved them) or the ordering of the current item has changed since it was loaded.- Parameters:
before (Model | str | int)
after (Model | str | int)
- notify_on_reorder: str | None = None[source]
When specified pg_notify will be called with
notify_on_reorderas the channel name after a reorder occurs.Notifications will occur per update. If
order_with_respect_tois set it will happen once per unique grouping (eg. if abulk_updateoccurs across different groupings there will be mulitiple notifications).Notifications won’t occur if an update happens that doesn’t change any
order_field_namevalue.Notification payload is a JSON sting that looks like:
{'operation': 'UPDATE', 'order_with_respect_to': {'plaza': 116}, 'schema': 'public', 'table': 'test_common_lib_shop', 'timestamp': '2021-06-30 00:00:53.928499+00'}
- order_field_name: str = 'sort_key'[source]
The name of the field to sort by. Your model must provide the field definition.