Abstract Django base models (and model class factories) to act as building blocks for rapid development of Django database models
Project description
Django Building Blocks
Abstract Django base models (and model class factories) to act as building blocks for rapid development of Django database models
Quick start
pip install django-building-blocks
Rationale
django-building-blocks
provides common design patterns and behaviours that repeat themselves during the development of
django projects. The main aim of this package is to provide common interfaces for the development of django models. This
portion of this library is inspired by Kevin Stone's excellent blog
post Django Model Behaviors. The secondary aim of this library is
to provide interfaces and mixins for Django admin classes, so you can add functionality to your admin pages really fast,
without the need to Google solutions and look at Stackoverflow for answers.
By using this library you can create models in such a way to make their fields standard across your entire project and all your projects. For example:
class BlogPost(
HasNameFactory.as_abstract_model(),
HasDescription,
HasHTMLBody,
Publishable,
models.Model
):
pass
Note that we did not need to add anything to the body of the above model. This model is entirely composed of abstract models (and abstract model factories - more on this later). If you have another model:
class WebPage(
HasNameFactory.as_abstract_model(),
HasAutoSlugFactory.as_abstract_model(),
HasHTMLBody,
Publishable,
models.Model
):
pass
Note the similarity between the two models. Now instead of having to code the fields, associated properties and behaviors on each model individually, you can reuse them infinite times, and keep them standard across your project (and all your projects).
The admin class for BlogPost
would look something like this:
@admin.register(BlogPost)
class BlogPostAdmin(
PublishableAdmin,
admin.ModelAdmin
):
list_display = (
*HasNameAdmin.list_display,
*PublishableAdmin.list_display,
...
)
...
Notice how we have composed each element in the admin using a concept called Admin Blocks. Each of the abstract classes
in this library, have an associated Admin block class (which looks like a normal admin class, but usually isn't meant to
be inherited), that enables you to define admin for their inheritors in a standard way. For example in the case
of Publishable
, you would probably like to show the publication status and date in list_display
. Instead of having
to remember to include both fields in all your admins, you can just include the Admin block in the way showed above and
have the fields show up in the list table for all the inheritors of Publishable
.
Details and classes provided
Note: Check the docstring under each class for their documentation.
Abstract models
Django Model Behaviors describes a design pattern for developing
django models that makes them compositional. For example, your project might have the ability to post blog
posts (BlogPost
), and each post goes through 3 stages: Draft, Published, and Archived. In your project, your users
might also have the ability to post shorter status updates (StatusUpdate
), and you'd like those status updates to also
go through a similar publishing pipeline. Furthermore, both BlogPost
and StatusUpdate
are timestamped with the date
and time they are published.
As a seasoned developer, instead of coding the functionality on both models, you would create an abstract model, let's
call it Publishable
, and have both BlogPost
and StatusUpdate
inherit from it. Now you have abstracted away common
functionality between your models, into the Publishable
interface/abstract model. Not only this is DRY, but also if
you like to make updates to how your publishing pipeline works, you can just update Publishable
and both BlogPost
and StatusUpdate
would get updated with the new pipeline.
django-building-blocks
provides a number of such abstract models:
Note: if you're coming from v0.0.x, take a look at this migration file
to help you with writing migrations for your Archivable
or Publishable
models, as in v0.1.0 they have switched to
use an integer status field.
Abstract model factories
Abstract model factories enable you to create abstract models on the fly. Abstract model factories enable you to modify
the inherited fields dynamically from the same base class. For example, you might have a model that will have an email
field. You can use HasEmailFactory.as_abstract_model()
that returns an abstract model that can be inherited from. Now
say you have another model that also has a email, but the email here is an optional field (blank=True
). Instead of
creating a whole new abstract model (like HasOptionalEmail
), you can inherit
from HasEmailFactory.as_abstract_model(optional=True)
which will return an abstract model with the same email
field,
but this time the email
field is optional.
Abstract model factories provided:
HasNameFactory
HasEmailFactory
HasDescriptionFactory
HasCoverPhotoFactory
HasIconFactory
HasUserFactory
HasAutoCodeFactory
HasAutoSlugFactory
You can create your own abstract model factory by inheriting
from building_blocks.models.factories.AbstractModelFactory
. Check some of the implementations for an example.
Mixin model classes
Admin block classes
The following admins (called admin blocks) aren't usually meant to be inherited by your model's admin class. Instead, each field in the admin is used to create your desired admin class. For example:
# example/sample/admin.py
@admin.register(ArchivableHasUUID)
class ArchivableHasUUIDAdmin(
ArchivableAdmin, # Inheritable admin to add common functionality. More on this later.
admin.ModelAdmin
):
search_fields = (
*HasUUIDAdmin.search_fields, # AdminBlock to assist in shaping the admin
)
list_display = (
*HasUUIDAdmin.list_display,
*ArchivableAdmin.list_display,
)
list_filter = (
*ArchivableAdmin.list_filter,
)
readonly_fields = (
*HasUUIDAdmin.readonly_fields,
*ArchivableAdmin.readonly_fields,
)
fieldsets = (
*HasUUIDAdmin.fieldsets,
*ArchivableAdmin.fieldsets,
)
As its name suggests, the model ArchivableHasUUID
inherits from both Archivable
and HasUUID
and thus has fields
form both. With admin blocks you can create ArchivableHasUUIDAdmin
without mentioning individual fields from each
class, adding to the conciseness of your code. It'll also make it hard to miss a field since the AdminBlock has the
default and recommended fields for each admin field.
Available Admin Blocks:
HasUUIDAdmin
ArchivableAdmin
PublishableAdmin
HasInitialsAdmin
HasNameAdmin
HasEmailAdmin
HasDescriptionAdmin
HasCoverPhotoAdmin
HasIconAdmin
HasUserAdmin
HasAutoSlugAdmin
TimeStampedModelAdmin
Inheritable Admin block classes
Some Admin block classes are also meant to be inherited by your admin class. The usually provide functionality such as common admin actions to your admin.
Please note that the majority of the inheritable admins
use django-object-actions to enable admin actions on objects'
admin:change
pages. To enable this functionality add 'django_object_actions'
to your INSTALLED_APPS
so your
project can find the templates from django_object_actions
which are used in rendering the buttons for the actions.
Mixin Admin classes
EditReadonlyAdminMixin
PrepopulateSlugAdminMixin
DjangoObjectActionsPermissionsMixin
AreYouSureActionsAdminMixin
Admin inline mixins
When you need some fields on an inline admin to be readonly only for editing (equivalent of EditReadonlyAdminMixin
),
you have to split the interface into two inlines, one for adding which doesn't show any objects, and one for listing
them, which has the readonly fields defined. The following classes facilitate this design pattern:
HTML render utilities
They are used in conjunction with @admin.display
to render html such as anchor tags, or images on the admin.
Forms
UnrequiredFieldsForm
and unrequire_form
Make fields that are usually required in a model form, be not required. Used in conjunction with HasAutoFields
, since
the fields that aren't required are auto set. Also used in conjunction with EditReadonlyAdminMixin
to allow manual
setting of a field upon creation.
Fields
Development and Testing
IDE Setup
Add the example
directory to the PYTHONPATH
in your IDE to avoid seeing import warnings in the tests
modules. If
you are using PyCharm, this is already set up.
Running the Tests
Install requirements
pip install -r requirements.txt
For local environment
pytest
For all supported environments
tox
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file django-building-blocks-0.1.0rc1.tar.gz
.
File metadata
- Download URL: django-building-blocks-0.1.0rc1.tar.gz
- Upload date:
- Size: 24.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f4e52f999b3f4c88ae3bf07842510d03375cae2796c40f8afccb8e50dfd16f49 |
|
MD5 | 54aee5192eacf48fa05130add09d2f24 |
|
BLAKE2b-256 | dc51e224126984b90c4a19d8e910c8404e18504dcffffe701f4495b9bc2f6e31 |
File details
Details for the file django_building_blocks-0.1.0rc1-py3-none-any.whl
.
File metadata
- Download URL: django_building_blocks-0.1.0rc1-py3-none-any.whl
- Upload date:
- Size: 31.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bfb4e6f94e04c71fde9f8a901dc4e5c9b488fa94bf60fea0827932607b80c76e |
|
MD5 | 654aaa0b72ab5acd4f59199802842128 |
|
BLAKE2b-256 | ea06b7a54cb92ed3631465257f69619efe0925423f02333b7d148a8e103b1035 |