Package reference
bdmodels.models
- class bdmodels.models.BrokenDownModel(*args, **kwargs)
Bases:
Model
Base class to replace
models.Model
for broken-down models.When using it, make sure to make it the first base-class of your model, so that its modified metaclass replaces the regular Model metaclass.
It also specifies its own Manager,
BrokenDownManager
; if you have custom managers on your model, use that as your base manager.Some
Model
methods are overridden just to change their implementation; notably, some checks are reimplemented and some checks are added.The methods documented here are those which add functionality.
- refresh_from_db(using=None, fields=None, *, all_parents: bool = False)
This method is overridden for two purposes.
One is to make sure fetching any parent attribute fetches the whole parent.
The other is to add the
all_parents
argument, which can be used to reload the object in full, canceling deferrals. Sinceall_parents
makes the model load all the fields, using it together withfields
makes no sense and is an error.
- getattr_if_loaded(attr: str, default=None)
Access an attribute (field), only if set specifically for the instance. This allows querying fields without causing unnecessary database round-trips.
- class bdmodels.models.BrokenDownManager(*args, **kwargs)
Basic Manager for broken-down models.
Connects the model to a
BrokenDownQuerySet
(and inherits its methods, as it is built from it).
- class bdmodels.models.BrokenDownQuerySet(*args, **kwargs)
Bases:
QuerySet
Special queryset for use with broken-down models.
Fix
select_related()
for correct handling of parent deferrals.Note
Of necessity, this means that if a parent is select_related, previous “only” is overridden and ignored. We make no effort to distinguish between deferrals created manually by the user, and those created automatically to defer parents.
- fetch_all_parents()
Select all fields in the model for immediate fetching, as if this was not a broken-down model.
This will make the query join all the parent tables.
- bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
Insert each of the instances into the database. Do not call save() on each of the instances, do not send any pre/post_save signals.
Setting the primary key attribute, if it is not set, is required for broken-down models; so if the PK is an autoincrement field, the database feature
can_return_rows_from_bulk_insert
(can_return_ids_from_bulk_insert
on older Django versions) is required.The parameters
update_conflicts
,update_fields
andunique_fields
are present in order to match the API of Django>=4.1, but updating on conflicts in bulk creation is currently not supported.
bdmodels.fields
- class bdmodels.fields.VirtualForeignKey(to, from_field, on_delete, related_name=None, related_query_name=None, limit_choices_to=None, parent_link=False, to_field=None, db_constraint=False, **kwargs)
Bases:
ForeignKey
A reference to a foreign object, based on an existing field
This is just like a
ForeignKey
with the exception that, rather than creating a related*_id
field to hold the id of the referenced object, it uses one of the existing fields of the model.The name of the field to be used is given as the required parameter
from_field
.Since the assumption is that the existing field serves other purposes (either it is interesting in itself, or the id it holds references more than one object), we limit changes through this field. Thus, Attempts to change the field’s value are blocked. Accordingly, it must be non-editable, and its
on_delete
rule must not change the field’s value. Similarly, a default does not make sense.Adding constraints would make sense – but this is currently not supported.
If an index is needed, it should be defined on the concrete field.
- class bdmodels.fields.VirtualOneToOneField(to, from_field, on_delete, to_field=None, **kwargs)
Bases:
OneToOneField
,VirtualForeignKey
One-to-one relationship based on existing field
This field is to a
OneToOneField
as aVirtualForeignKey
is to aForeignKey
, and vice versa – it is also toVirtualForeignKey
as aOneToOneField
is to aForeignKey
.
- class bdmodels.fields.VirtualParentLink(to, from_field='id', on_delete=<function CASCADE>, to_field=None, **kwargs)
Bases:
VirtualOneToOneField
A
VirtualOneToOneField
that is also a parent linkThe most common use for
VirtualOneToOneField
while breaking down models is for a field that is also a link to a parent model, and whose base field is the model’s primary key.This is mostly a shorthand for this use-case – the
parent_link
attribute is set toTrue
, and thefrom_field
has a default of'id'
(using the model’s actual PK is more involved, and is left for the future).
bdmodels.migration_ops
- bdmodels.migration_ops.AddVirtualField(*, model_name: str, name: str, field)
A thin wrapper – limit
AddField
to act on the model and not on the database.- Parameters
model_name – The model where the field is to be added
name – The name of the field to be added
field – The (virtual) field to be added
- class bdmodels.migration_ops.CopyDataToPartial(*args, **kwargs)
A migration operation for moving data from a complete model, to a model which has some of the complete model’s fields, efficiently.
This is useful when breaking down a large model to parts.
This is a data operation – it moves data, does not change schema; the kind of operation typically written as a
RunPython
operation.- Implementation
The forwards direction of the operation uses SQL
INSERT-SELECT
to create the rows in the table of the partial model. The backwards side usesUPDATE
with a join to copy data from the partial model’s table into (existing) rows of the complete model’s table.- Compatibility
While
INSERT-SELECT
is standard SQL,UPDATE
with a join (A.K.AUPDATE-FROM
) is not. The library currently uses the PostgreSQL syntax, which is also supported by SQLite >= 3.3.0; for this reason, the backwards side of this migration operation only works with these database backends. Until this is fixed, users who need this operation with other backends can write it as aRunSQL
operation.The SQLite documentation reviews support of this feature in different systems, see there for details.
- __init__(full_model_name: str, part_model_name: str, elidable: bool = True)
- Parameters
full_model_name – The name of the full model (which at this point has all the fields)
part_model_name – The name of the partial model (whose fields are a PK and some fields copied from the full model)
elidable – Specifies if this operation can be elided when migrations are squashed