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. Since all_parents makes the model load all the fields, using it together with fields 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 and unique_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 a VirtualForeignKey is to a ForeignKey, and vice versa – it is also to VirtualForeignKey as a OneToOneField is to a ForeignKey.

Bases: VirtualOneToOneField

A VirtualOneToOneField that is also a parent link

The 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 to True, and the from_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 uses UPDATE 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.A UPDATE-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 a RunSQL 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