pytoolbox.django.models.mixins module

Mix-ins for building your own models.

Recommended sub-classing order:

  • BetterUniquenessErrorsMixin

  • AutoForceInsertMixin

  • CallFieldsPreSaveMixin

  • AutoUpdateFieldsMixin

  • AlwaysUpdateFieldsMixin

  • AutoRemovePKFromUpdateFieldsMixin

  • ValidateOnSaveMixin (will defeat the detection method of AutoUpdateFieldsMixin if put before it)

  • UpdatePreconditionsMixin

  • StateTransitionPreconditionMixin

  • StateTransitionEventsMixin

Order for these does not matter:

  • PublicMetaMixin

  • RelatedModelMixin

  • ReloadMixin

  • SaveInstanceFilesMixin

class pytoolbox.django.models.mixins.AutoUpdateFieldsMixin(*args, **kwargs)[source]

Bases: object

Keep track of what fields were set in order to make UPDATE queries lighter.

This mix-in comes with the following features:

  • Foreign keys and the mutable types are correctly handled.

  • Models with a primary key preset to a value before being saved in database are correctly handled.

  • You can specify the value for force_update if it is None with default_force_update.

However this low-memory footprint mix-in also comes with some limitations, it does not:

  • Store old fields values - you cannot know if the fields are really modified or not.

  • Watch for background modifications of the mutable fields - it can drives you crazy, sometimes.

  • Detect fields updated by the field’s pre_save - CallFieldsPreSaveMixin before this mix-in.

  • Filter the primary key from the list of fields to update - AutoRemovePKFromUpdateFieldsMixin after this mix-in.

default_force_update = False
__init__(*args, **kwargs)[source]
save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.StateTransitionEventsMixin(*args, **kwargs)[source]

Bases: object

__init__(*args, **kwargs)[source]
on_post_state_transition(args, kwargs)[source]
save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.AutoForceInsertMixin[source]

Bases: object

save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.AlwaysUpdateFieldsMixin[source]

Bases: object

Ensure fields listed in the attribute self.always_update_fields are always updated by self.save(). Makes the usage of self.save(update_fields=...) cleaner.

save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.StateTransitionPreconditionMixin[source]

Bases: UpdatePreconditionsMixin

check_state = True
invalid_state_error_class

alias of InvalidStateError

transition_not_allowed_error_class

alias of TransitionNotAllowedError

can_transit_to(state, fail=False, noop_skip=False)[source]

Helper that return the following:

  • True if transition to state is allowed.

  • False if fail is set to False or noop_skip is set to True and state is unchanged.

  • Else raise a transition not allowed error.

check_state_in(states, fail=False)[source]
pop_preconditions(*args, **kwargs)[source]

Add state precondition if state will be saved and state is not enforced by preconditions.

class pytoolbox.django.models.mixins.FasterValidateOnSaveMixin[source]

Bases: ValidateOnSaveMixin

Do not validate uniqueness nor relation fields on save to prevent excessive SELECT queries.

validate_on_save_kwargs
class pytoolbox.django.models.mixins.AutoRemovePKFromUpdateFieldsMixin(*args, **kwargs)[source]

Bases: object

If the primary key is set but unchanged, then remove the primary key from the list of fields to update. This fix an issue when saving, ValueError: The following fields do not exist in this model or are m2m fields: id.. This check is probably implemented by Django developers to protect from unintentional data overwrite.

If the primary key is set to a new value, then the intention of the developer is probably to duplicate the model by saving it with a new primary key. So the mix-in let Django save with its own default options for save.

__init__(*args, **kwargs)[source]
save(**kwargs)[source]
class pytoolbox.django.models.mixins.SaveInstanceFilesMixin[source]

Bases: object

Overrides saves() with a method that saves the instance first and then the instance’s file fields this ensure that the upload_path method will get a valid instance id / private key.

save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.CallFieldsPreSaveMixin[source]

Bases: object

If you wanna be sure the fields pre_save method are called, now you can!

For more information see: https://code.djangoproject.com/ticket/25363

save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.BetterUniquenessErrorsMixin[source]

Bases: object

Hide some fields from the unique-together errors. Convert uniqueness integrity errors to validation errors.

Use cases

Case: Your model have some non editable fields that are included in a uniqueness constraint. Issue: The uniqueness errors shown in your forms includes the name of the hidden fields. Solution: Exclude the name of the hidden fields from the error messages. Implementation: Set unique_together_hide_fields to the name of those hidden fields.

Case: Sometimes the form submit may raise an integrity error (concurrency, [yes] crazy

unexpected usage of Django).

Issue: Those integrity errors are unfortunately returned as Internal Server Error (HTTP 500). Solution: Convert the uniqueness integrity errors to validation errors and return an awesome

form with errors.

Implementation: Set unique_from_integrity_error to True. And subclass pytoolbox.django.views.mixins.ValidationErrorsMixin in your edit views.

unique_from_integrity_error = True
unique_together_hide_fields = ()
save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.ReloadMixin[source]

Bases: object

reload()[source]
class pytoolbox.django.models.mixins.ValidateOnSaveMixin[source]

Bases: object

validate_on_save = True
validate_on_save_kwargs = {}
save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.UpdatePreconditionsMixin[source]

Bases: object

precondition_error_class

alias of DatabaseUpdatePreconditionsError

apply_preconditions(base_qs, using, pk_val, values, update_fields, force_update)[source]
pop_preconditions(*args, **kwargs)[source]
save(*args, **kwargs)[source]
class pytoolbox.django.models.mixins.PublicMetaMixin[source]

Bases: object

Make _meta public in templates through a class method called meta.

classmethod meta()[source]
class pytoolbox.django.models.mixins.RelatedModelMixin[source]

Bases: object