To Object or Not to Object?
English is Confusing
English can be a confusing language. When I say "object" I mean a Python object and not to object to something. Of course, the reader may object to the content of this article, but that is beside the point.
But I digress.
Defining Options
When building extensible applications in Python, we often have to answer the question of how best to allow a developer to customize the functionality.
Consider this hypothetical example for defining options for a list view:
class ListOptions(object):
def __init__(search_enabled=False, search_fields=None, search_minimum_length=3):
# ...
There are numerous parameters beginning with search_
. One solution might be to pass a dictionary instead.
search_params = {
'search_enabled': True,
'search_fields': ("title", "description"),
'search_minimum_length': 3,
}
options = ListOptions(**search_params)
This is perhaps better, but it's still sort of messy.
Using Objects as Configuration
Another way would be to define a search class:
class Search(object):
def __init__(*fields, enabled=True, length=3):
# ...
options = ListOptions(search=Search("title", "description"))
While this approach proliferates the number of classes, it is much cleaner and also easier for a developer to use. Code completion provides information and the style is expressive and closer to natural language.
Additionally, using classes and their instances for configuration provides a kind of data structure that makes the whole system more extensible.
These are the principles upon which SuperDjango UI hangs its development practices.
# projects/ui.py
from superdjango import ui
from .models import Project
class ProjectUI(ui.ModelUI):
model = Project
list_options = ui.ListOptions(
"title",
"owner",
"start_dt",
"end_dt",
"priority",
filtering=ui.Filtering("priority", "owner"),
ordering=ui.Ordering("start_dt", "end_dt", "priority")
)
The example above supplies two configuration instances to ListOptions
to indicate how the list may be filtered and ordered.