Database¶
A plethora, a cornucopia, a totally ridiculous number of models, fields, and other resources that may be used as a starting point for your database.
Version: 0.4.0-d
Name |
Version |
Stage |
Maintainer |
---|---|---|---|
archived |
0.10.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
audit |
0.11.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
calculated |
0.6.0-p |
planning |
Shawn Davis <shawn@superdjango.com> |
completed |
0.11.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
datetime |
0.8.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
default |
0.6.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
displayed |
0.4.0-a |
alpha |
Shawn Davis <shawn@superdjango.com> |
eav |
0.6.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
expiration |
0.7.0-p |
planning |
Shawn Davis <shawn@superdjango.com> |
history |
0.7.0-p |
planning |
Shawn Davis <shawn@superdjango.com> |
locked |
0.7.1-p |
planning |
Shawn Davis <shawn@superdjango.com> |
lookups |
0.9.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
owned |
0.12.1-d |
development |
Shawn Davis <shawn@superdjango.com> |
parent |
0.7.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
polymorphic |
0.4.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
primary |
0.7.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
published |
0.10.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
random |
0.6.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
resolved |
0.3.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
reviewed |
0.3.0-d |
development |
Shawn Davis <shawn@superdjango.com> |
revised |
0.2.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
slug |
0.4.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
sorted |
0.7.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
timed |
0.6.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
trashed |
0.6.1-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
utils |
0.1.0-x |
experimental |
Shawn Davis <shawn@superdjango.com> |
The resources provided by SuperDjango DB general consist of abstract models that may be used for various common (and some not so common) purposes.
Note
SuperDjango DB does not (and will never) provide concrete models.
Archived Models¶
Version: 0.10.0-d
Provides support for a simple archive workflow.
Developer Reference: Archived Models
Provides
Usage¶
from superdjango.db.archived.managers import ArchivedManager
from superdjango.db.archived.models import ArchivedByModel
class StrategicPlan(ArchivedByModel):
objects = ArchivedManager()
archived_plans = StrategicPlan.objects.archived()
unarchived_plans = StrategicPlan.objects.unarchived()
Audit Models¶
Version: 0.11.0-d
Adds support for added by/modified by/viewed by (and added/modified/viewed date/time) to a model.
Developer Reference: Audit Models
Provides
Calculated Fields¶
Version: 0.6.0-p
Provides support for standard calculated fields as well as creating your own calculated fields.
Developer Reference: Calculated Fields
Provides
Models : field mixins, fields
Abstract¶
Calculated fields can be useful when aggregating data or connecting (concatenating) strings. This library provides various fields for use in automatic calculation on save.
Completed Models¶
Version: 0.11.0-d
Provides the ability to mark a record as complete.
Developer Reference: Completed Models
Provides
Abstract¶
A completion workflow is often needed for tasks, projects, and other common types of web application records. This library provides support for such a workflow.
Usage¶
from superdjango.db.completed.managers import CompletedManager
from superdjango.db.completed.models import CompletedByModel
class Task(CompletedByModel):
objects = CompletedManager()
completed_tasks = Task.objects.complete()
incomplete_tasks = Task.objects.incomplete()
Date/Time Models¶
Version: 0.8.0-d
Fields and abstract models for working with dates and datetimes.
Developer Reference: Date/Time Models
Provides
Models : fields, abstract
Default Models¶
Version: 0.6.0-x
Provides the ability to mark a record as the default of it’s type.
Developer Reference: Default Models
Provides
Abstract¶
Records that are identified as “the default” are useful for establishing intelligent defaults for things like configuration options and lookup (validation) data.
Usage¶
Support you have an AddressType
lookup and that only one address type may be the default for new records that refer
to address type.
# myapp/models.py
from django.db import models
from superdjango.db.default.managers import DefaultManager
from superdjango.db.default.models import DefaultModel
from superdjango.db.lookups.models import StringLookupModel
from django.db.models.signals import pre_save
class AddressType(DefaultModel, StringLookupModel):
objects = DefaultManager()
# ...
Set the required receiver:
# myapp/receivers.py
from .models import AddressType
pre_save.connect(
AddressType.allow_one_default,
AddressType,
dispatch_uid="addresstype_allow_one_default"
)
To require that a default address type always exists, use the require_one_default
instead:
# Or to require a default record.
pre_save.connect(
AddressType.require_one_default,
AddressType,
dispatch_uid="addresstype_require_one_default"
)
Load receivers in your apps.py
file:
from django.apps import AppConfig
class DefaultConfig(AppConfig):
name = 'myapp'
label = 'myapp'
def ready(self):
from . import receivers
To implement the default in a form:
from django import forms
class EmployeeAddress(forms.ModelForm):
class Meta:
model = EmployeeAddress
fields = [
"address_type",
# ...
]
def __init__(*args, **kwargs):
super(EmployeeForm, self).__init__(*args, **kwargs)
self.fields['address_type'].initial = AddressType.objects.default()
Displayed Models¶
Version: 0.4.0-a
Provides a consistent means of acquiring the human friendly name of a model instance.
Developer Reference: Displayed Models
Provides
Models : abstract, mixins
Abstract¶
What is a display name? A display name is a proper name, label, or title for a specific model instance. Django models
already have a mechanism for providing this representation by defining the __str__()
method.
Why use the displayed
mixin or model, then? The superdjango.db.displayed.mixins.DisplayNameMixin
formalizes a simple API for acquiring the proper name of a record. The __str__()
method defaults to
get_display_name()
, but may be overridden to provide something different if desired.
The displayed
package also defines get_choice_name()
which allows the proper name to be different when the
record is displayed as a choice.
Note
Certain components of SuperDjango UI utilize a model’s implementation of both get_choice_name()
and
get_display_name()
. The superdjango.db.displayed.mixins.DisplayNameMixin
provides the basis for this
functionality.
Usage¶
Simply extend superdjango.db.displayed.mixins.DisplayNameMixin
and implement get_display_name()
or
alternatively extend superdjango.db.displayed.models.DisplayNameModel
to also cache the the choice and
display name values on save()
.
EAV Models¶
Version: 0.6.0-x
Support for the Entity Attribute Value (EAV) approach to adding custom fields.
Developer Reference: EAV Models
Provides
Abstract¶
The Entity Attribute Value model (EAV) is a means of adding custom attributes to an existing model in a dynamic fashion. This can be useful for creating user-defined fields without interfering with core data models.
Usage¶
In the examples that follow, we implement a user profile model to which we wish to attach custom fields using the EAV pattern.
# myapp/models.py
from superdjango.db.eav.models import AttributeModel, ValueModel
class Profile(models.Model):
user = models.OneToOneField(AUTH_USER_MODEL, related_name="profile")
# ... additional "hard coded" fields as desired ...
class ExtraAttribute(AttributeModel):
pass
class ExtraAttributeValue(ValueModel):
attribute = models.ForeignKey(ExtraAttribute, related_name="values")
profile = models.ForeignKey(Profile, related_name="attributes")
def get_attribute(self):
return self.attribute
ExtraAttribute
defines the available attributes that may be populated with actual values in ExtraAttributeValue
.
# myapp/forms.py
from superdjango.forms import EAVModelForm
from .models import Profile, ExtraAttribute, ExtraAttributeValue
class ProfileForm(EAVModelForm):
attribute_model = ExtraAttribute
entity_name = "profile"
value_model = ExtraAttributeValue
# ... add fields and meta as usual ...
Defining the attribute and value models, as well as the entity name is required. The optional attribute_name
defaults to “attribute” which is what we used in ExtraAttributeValue
to define the attribute model to which the
value is connected.
Expiration Models¶
Version: 0.7.0-p
Work with records that have an expiration date and time.
Developer Reference: Expiration Models
Provides
Abstract¶
Some records represent a time-limited scope for their availability or use. The expiration library provides support for an expiration workflow.
Usage¶
Suppose you have a proposal model that needs to expire after a certain date and time.
# myapp/models.py
from superdjango.db.expiration.managers import ExpirationManager
from superdjango.db.expiration.models import ExpirationModel
class Proposal(ExpirationModel):
objects = ExpirationManager()
# ...
In the list view (for example, as displayed to clients), you may utilize the unexpired
method on the manager to
display only proposals that are current:
from superdjango.views import ListView
from .models import Proposal
class ProposalList(ListView):
model = Proposal
def get_queryset(self):
return self.model.objects.unexpired()
A management command could be created to check expiration and update the expired models.
# myapp/management/commands/update_expired_proposals.py
from django.core.management.base import BaseCommand
from myapp.models import Proposal
class Command(BaseCommand):
def handle(self, *args, **options):
qs = Proposal.objects.filter(has_expired__is_null=True)
for row in qs:
if row.is_past_expiration():
row.has_expired = True
row.save()
History Models¶
Version: 0.7.0-p
Abstract model for implementing audit history on models.
Developer Reference: History Models
Provides
Abstract¶
The history package provides an abstract model for implementing a log of historical activity on other models. For a
practical implementation, see superdjango.contrib.history
.
Usage¶
Implementing Audit History¶
You may create your own history by extending superdjango.db.history.models.HistoryModel
.
# myapp/models.py
from superdjango.db.history.models import HistoryModel
class History(HistoryModel):
class Meta:
get_latest_by = "added_dt"
ordering = ["-added_dt"]
verbose_name = _("Log Entry")
verbose_name_plural = _("Log Entries")
See the admin
and ui
modules of this package for implementing Django Admin and SuperDjango UI user interfaces.
Creating an Audit Trail¶
Your view must call the log
method:
# myapp/views.py
from .models import History
class CreateTodo(CreateView):
...
def form_valid(self, form):
self.object = form.save()
History.log(self.object, self.request.user, History.CREATE)
...
Tracking Changes to Fields¶
The superdjango.db.history.utils.FieldChange
may be used to assist with tracking changes to fields. The
superdjango.db.history.utils.get_field_changes()
is also provided as a shortcut for creating FieldChange
instances.
# myapp/models.py
from superdjango.db.history.models import HistoryModel
class History(HistoryModel):
field_changes = models.TextField(
blank=True,
null=True
)
class Meta:
get_latest_by = "added_dt"
ordering = ["-added_dt"]
verbose_name = _("Log Entry")
verbose_name_plural = _("Log Entries")
@classmethod
def log_field_changes(cls, instance, verb, fields=None):
if fields is None:
return
a = list()
for change in fields:
a.append(str(change))
instance.field_changes = "\n".join(a)
# myapp/views.py
from superdjango.db.history.utils import get_field_changes
from .models import History
class UpdateTodo(UpdateView):
...
def form_valid(self, form):
self.object = form.save()
field_changes = get_field_changes(form, self.model, record=self.object)
History.log(self.object, self.request.user, History.UPDATE, fields=field_changes)
...
You could also implement a separate model to record each field change and connect it to the history record.
# myapp/models.py
from superdjango.db.history.models import HistoryModel
class History(HistoryModel):
...
@classmethod
def log_field_changes(cls, instance, verb, fields=None):
if fields is None:
return
a = list()
for change in fields:
field_history = FieldHistory(
field_label=change.field_label,
field_name=change.field_name
history=instance,
new_value=change.new_value,
old_value=change.old_value,
)
field_history.save()
class FieldHistory(models.Model):
field_label = models.CharField(
max_length=256
)
field_name = models.CharField(
max_length=256
)
history = models.ForeignKey(
History,
on_delete=models.CASCADE,
related_name="field_changes",
verbose_name=_("History")
)
new_value = models.TextField(
blank=True,
null=True
)
old_value = models.TextField(
blank=True,
null=True
)
class Meta:
ordering = ["field_label"]
verbose_name = _("Field History")
verbose_name_plural = _("Field Histories")
def __str__(self):
return "%s: %s -> %s" % (self.field_label, self.old_value, self.new_value)
Note that custom views or UI would be required to display the field history records.
Locked Models¶
Version: 0.7.1-p
Work with records that have been locked from update or delete.
Developer Reference: Locked Models
Provides
Abstract¶
Record locking prevents delete or update actions. This library provides model-level support for locked records.
Usage¶
Supporting Record Locking¶
While the superdjango.db.locked.models.LockedModel
provides support for locking a record, additional work
is required in the UI to prevent changes from occurring.
SuperDjango UI supports locked models in the check_lock()
and check_permission()
methods of
superdjango.ui.options.interfaces.BaseModelUI
. Also, the provided
superdjango.db.locked.admin.BaseLockedModelAdmin
provides built-in support for the Django Admin.
Note
In both of the implementations above, the super user always retains the permission to delete and update locked records.
Custom views, however, will need to implement support for checking and dealing with locks.
Record Lock or Unlock Permissions¶
The provided resources assume that a super user can always lock or unlock records, and may work with records regardless of their locked status. Although it requires additional customization, you may implement custom permissions that allow authorized users to work with record locking.
# myapp/models.py
from superdjango.db.locked.models import LockedModel
class Employee(LockedModel):
# ...
class Meta:
permissions = [
("can_deleted_locked_employee", "Can delete a locked employee record."),
("can_lock_employee", "Can lock an employee record."),
("can_unlock_employee", "Can unlock an employee record."),
("can_update_locked_employee", "Can update a locked employee record."),
]
With these permissions in place you would need to potentially do the following depending on your needs:
Override the
check_lock()
method ofsuperdjango.ui.options.interfaces.BaseModelUI
to check the custom permissions.Override the
has_delete_permission()
andhas_change_permission()
methods ofsuperdjango.db.locked.admin.BaseLockedModelAdmin
to check custom permissions.Deal with these permissions in any custom views you have created.
Lookup Models¶
Version: 0.9.0-d
Provides pre-defined models for managing lookup (aka validation) data.
Developer Reference: Lookup Models
Provides
Abstract¶
The need for lookup data (also known as validation data) is common to perhaps all Web applications. Handling such data in a consistent manager can be very beneficial to a project – there is no need to guess as to the available fields on a lookup.
Owned Models¶
Version: 0.12.1-d
Provides a random character field.
Developer Reference: Owned Models
Provides
Parent-Tree Models¶
Version: 0.7.0-x
Provides a simple model for implementing parent-child-sibling relationships.
Developer Reference: Parent-Tree Models
Provides
Compat
Models : abstract
Utilities
Dependencies
anytree (optional) Required to use the diagramming functionality.
This is a simplistic implementation of tree-like functionality using only a parent
field that refers to self
.
It performs well for a relatively small number of records. For thousands records, you may wish to review the following
resources:
Graphing¶
Parent-tree provides a utility for creating a visual graph of a given record and all of its children.
Important
The anytree
package is required to utilize this functionality.
The superdjango.db.parent.utils.Diagram
class may be used to create an image. Suppose you have an HR tool
and you want to present the structure of an organization:
from django.conf import settings
import os
from superdjango.db.parent.utils import Diagram
from hr.organizations.models import Organization
# Load the graphing utility.
org = Organization.objects.get(pk=1)
diagram = Diagram(org)
# Output the image.
graph = diagram.to_graph()
path = os.path.join(settings.MEDIA_ROOT, "hr", "orgs", "%s.jpg" % org.pk)
graph.to_picture(path)
Polymorphic Models¶
Version: 0.4.0-x
Managers and mixins for polymorphic behavior.
Developer Reference: Polymorphic Models
Provides
Models : managers, mixins
Utilities
Provides assistance with managing Multi-table inheritance in Django.
from superdjango.polymophric import PolymorphicManager, PolymorphicMixin
class Project(models.Model):
objects = PolymorphicManager()
# ...
class MobileProject(PolymorphicMixin, Project):
# ...
class WebSiteProject(PolymorphicMixin, Project):
# ...
projects = Project.objects.all().select_subclasses()
for project in projects:
# project will be a specific instance of Project, MobileProject, or WebSiteProject.
print(project)
Primary Models¶
Version: 0.7.0-x
Provides support for a publishing workflow.
Developer Reference: Primary Models
Provides
Published Models¶
Version: 0.10.0-d
Provides support for a publishing workflow.
Developer Reference: Published Models
Provides
Random Models¶
Version: 0.6.0-x
Provides a random character field.
Developer Reference: Random Models
Resolved Models¶
Version: 0.3.0-d
Provides support for a resolution workflow.
Developer Reference: Resolved Models
Provides
Reviewed Models¶
Version: 0.3.0-d
Provides support for a review workflow.
Developer Reference: Reviewed Models
Provides
Revised Models¶
Version: 0.2.0-x
A simple package that allows saving revisions of a record.
Developer Reference: Revised Models
Provides
Abstract¶
Record revision means creating a new (or latest) revision of a record whilst saving past revisions of the same record. This package supports a simple record revision system.
We are fully aware of the sundry tools for managing versioned model data. Many of these bring great functionality to the table, and you are encouraged to check these out as an alternative to this package.
Usage¶
After extending superdjango.db.revised.models.RevisedModel
, you may create a new revision of the current
record using the save_revision()
method.
Sorted Models¶
Version: 0.7.0-x
A model and utilities for implementing record sortation.
Developer Reference: Sorted Models
Provides
Models : abstract
Utilities
Slug Fields¶
Version: 0.4.0-x
Provides support for a automatic slug field.
Developer Reference: Slug Fields
Provides
Models : fields
Utilities
Abstract¶
Support for automatic slug fields.
Usage¶
The automatic slug field will by default create a slug using Django’s slugify()
utility. You may provide your own
callback function to use for providing the slug.
# myapp/models.py
superdjango.db.slug.fields import AutoSlugField
function underscores_and_lower_case(value):
return value.replace(" ", "_").lower()
class UploadFile(models.Model):
file_name = AutoSlugField(from_field="title", slug_using=underscores_and_lower_case)
title = models.CharField(max_length=128)
# ...
Timed Models¶
Version: 0.6.0-x
Create records that incorporate start/stop timing functionality.
Developer Reference: Timed Models
Provides
Models : abstract
Trashed Models¶
Version: 0.6.1-x
Provides a workflow for trashed, but not deleted, models.
Developer Reference: Trashed Models
Provides
Abstract¶
A trashed flag allows a single record to be marked as being removed by a user, but not yet removed from the database.