djblets.db.fields.relation_counter_field¶
- class InstanceState(model_instance)[source]¶
Tracks state for a RelationCounterField instance assocation.
State instances are bound to the lifecycle of a model instance. They’re a type of weak reference for model instances that contain additional state needed for the tracking and update process.
These are used for looking up the proper instance and RelationCounterFields on the other end of a reverse relation, given a model, relation name, and IDs, through the
RelationCounterField._saved_instance_states
orRelationCounterField._unsaved_instance_states
or dictionaries.Instance states can either represent saved instances or unsaved instances. Unsaved instance states represent instances that haven’t yet been saved to the database (with a primary key of
None
). While saved instance states exist per-instance/relation name, there’s only one unsaved instance state per instance.Once an unsaved instance is saved, new instance states will be stored for each field associated (which many turn into multiple states, as there’s one per relation name). The old unsaved instance state is then discarded.
- property model_instance[source]¶
The model instance being tracked.
This will be
None
if the instance has been destroyed.
- track_field(field)[source]¶
Track information on a field referencing this state.
- Parameters
field (django.db.models.Field) – The field to track.
- class RelationTracker(model_cls, rel_field_name)[source]¶
Tracks relations and updates state for all affected CounterFields.
This class is responsible for all the hard work of updating RelationCounterFields refererring to a relation, based on updates to that relation. It’s really the meat of RelationCounterField.
Each RelationTracker is responsible for a given model/relation name pairing, across all instances of a model and across all RelationCounterFields following that relation name.
The main reason the code lives here instead of in each RelationCounterField is to keep state better in sync and to ensure we’re only ever dealing with one set of queries per relation name. We’re also simplifying signal registration, helping to make things less error-prone.
- class RelationCounterField(rel_field_name=None, *args, **kwargs)[source]¶
A field that provides an atomic count of a relation.
RelationCounterField is a specialization of CounterField that tracks how many objects there are on the other side of a ManyToManyField or ForeignKey relation.
RelationCounterField takes the name of a relation (either a field name, for a forward ManyToManyField relation, or the “related_name” for the reverse relation of another model’s ForeignKey or ManyToManyField. (Note that using a forward ForeignKey relation is considered invalid, as the count can only be 1 or 0.)
The counter will be initialized with the number of objects on the other side of the relation, and this will be kept updated so long as all updates to the table are made using standard create/save/delete operations on models.
Note that updating a relation outside of a model’s regular API (such as through raw SQL or something like an update() call) will cause the counters to get out of sync. They would then need to be reset using
reinit_{field_name}
.- classmethod has_tracked_states()[source]¶
Return whether there are currently any states being tracked.
This will begin by cleaning up any expired states whose instances have been destroyed, if there are any. Then it will check if there are any remaining states still being tracked and return a result.
- Returns
True
if there are any states still being tracked.False
if not.- Return type