Service Layer
On the previous page, we've learned about DAOModel methods, now let's explore how to build a service layer on top of your DAOs.
The service layer of a codebase provides functionality beyond basic CRUD. Though less useful for straightforward applications, this layer keeps your code organized and DRY. Here are examples of logic you may find within a service layer:
- Bulk operations (conducting CRUD operations on multiple records)
- CRUD requiring preceding calculations (calculating a subtotal before storing an invoice)
- Validation (ensuring a calendar date is available before finalizing a booking)
- Working with Transactions
The DAOModel library contains an extendable base for your service layer class, offering core functionality which you can build into a full-featured service.
Features
- Direct DAO Access
- Bulk Operations
- Transaction Management
- Model Merging
- Simple Service Creation
- Extendable for custom business logic
- Multi-DAO Support
Service Types
DAOModel provides two variations of the service layer base, each having their own useful shortcuts and functions.
BaseService
A standard service class having access to each of your existing DAOs.
BaseService offers:
- Access to the DAOFactory through the
daosproperty - Bulk Operations
SingleModelService
An extension of BaseService specifically designed around working with a single model type.
SingleModelService offers:
- Access to the model DAO through the
self.daoproperty - Bulk Operations
- Model Merging
Usage
Creating a Service
To create a service, you need a DAOFactory instance and, for SingleModelService, a primary model class:
# Create a multi-DAO service
multi_service = BaseService(daos)
# Create a service for a specific model class
student_service = SingleModelService(daos, Student)
Accessing the DAO
When using SingleModelService, you can access the DAO for the model through the dao property:
# Access the DAO for CRUD actions
student = service.dao.get(1)
The same DAO is accessible using the BaseService, the code is just a bit more verbose since the model must be specified:
# Access the DAO for CRUD actions
student = service.daos[Student].get(1)
Bulk Operations
The bulk_update function is used to modify multiple entries/models at once without writing any SQL:
bulk_update
bulk_update(models: List[DAOModel], **common_values: Any) -> None
Assigns values to multiple models in a single transaction.
This is particularly useful for applying batch changes to a filtered set of records.
service.bulk_update(overdue_accounts, status='suspended')
The method supports updating models of different types in a single operation.
no_longer_at_school = (school_service.daos[Student].find(graduated=True) +
school_service.daos[Staff].find(retired=True))
service.bulk_update(no_longer_at_school, status='inactive', door_code=None)
Non-applicable fields will be ignored. i.e. it doesn't matter that Students do not have a door_code column.
| Parameters: |
|
|---|
Merging Models
The SingleModelService class provides a merge method for combining two records:
merge
merge(source: DAOModel, *destination_pk_values, **conflict_resolution: Preference | Callable | Any) -> None
Merges the given source model into the specified destination.
In some cases, specify conflict_resolution to successfully merge values.
See the ChangeSet documentation for more details on conflict resolution.
| Parameters: |
|
|---|
| Raises: |
|
|---|
# Merge student1 into student2
service.merge(student1, 2)
This is particularly useful for scenarios such as:
- Resolving multiple accounts discovered for a single person
- Combining two classes into one
- Consolidating notes from different sources
When merging items, you may need to resolve conflicts between the source and destination. See Preference RulesConflict Resolution for more information.
Extending the Services
You can extend either service class to add additional functionality:
class StudentService(SingleModelService):
def __init__(self, daos):
super().__init__(daos, Student)
def promote_to_next_grade(self, student):
student.grade += 1
self.dao.commit(student)
If you find yourself writing the same function for several of your services, consider submitting a pull request to have it added to the base classes. This will reduce help improve the library for everyone while reducing the amount of code you need to write.
Next Steps
You now have a basic understanding of how to create your Models, Repository layer (DAO), and Service layer. That may be all you need for your project. If not, you likely want to continue by creating a Controller layer. If that is your next step, you will find my Fast-Controller library essential. Fast-Controller takes your DAOModels and automatically gives you a full-featured REST API. This is perfect for rounding off your backend; making it accessible as a microservice or available to a frontend such as a website/mobile app.
Otherwise, feel free to explore the advanced features of DAOModel:
- The DataLayer provides a simple way to set up your database and manage all of your Data Access Objects.
- The Model Comparison and Diffing feature allows you to compare models, track changes, and resolve conflicts.
- The Advanced Search features provide powerful search functionality beyond simple equality checks.
- The Testing Utilities makes testing your DAOModel-based applications a breeze.