mirror of
https://github.com/HackSoftware/Django-Styleguide.git
synced 2024-11-28 12:33:46 +03:00
Improve examples of class-based services
This commit is contained in:
parent
9e2674b5eb
commit
ea4184d6ba
73
README.md
73
README.md
|
@ -527,7 +527,10 @@ In this example, everything related to the user creation is in one place and can
|
|||
Here's an example, taken straight from the [Django Styleguide Example](https://github.com/HackSoftware/Django-Styleguide-Example/blob/master/styleguide_example/files/services.py#L22), related to file upload:
|
||||
|
||||
```python
|
||||
class FileDirectUploadService:
|
||||
# https://github.com/HackSoftware/Django-Styleguide-Example/blob/master/styleguide_example/files/services.py
|
||||
|
||||
|
||||
class FileStandardUploadService:
|
||||
"""
|
||||
This also serves as an example of a service class,
|
||||
which encapsulates 2 different behaviors (create & update) under a namespace.
|
||||
|
@ -557,6 +560,8 @@ class FileDirectUploadService:
|
|||
|
||||
@transaction.atomic
|
||||
def create(self, file_name: str = "", file_type: str = "") -> File:
|
||||
_validate_file_size(self.file_obj)
|
||||
|
||||
file_name, file_type = self._infer_file_name_and_type(file_name, file_type)
|
||||
|
||||
obj = File(
|
||||
|
@ -575,6 +580,8 @@ class FileDirectUploadService:
|
|||
|
||||
@transaction.atomic
|
||||
def update(self, file: File, file_name: str = "", file_type: str = "") -> File:
|
||||
_validate_file_size(self.file_obj)
|
||||
|
||||
file_name, file_type = self._infer_file_name_and_type(file_name, file_type)
|
||||
|
||||
file.file = self.file_obj
|
||||
|
@ -636,6 +643,70 @@ class FileAdmin(admin.ModelAdmin):
|
|||
self.message_user(request, str(exc), messages.ERROR)
|
||||
```
|
||||
|
||||
Additionally, using class-based services is a good idea for "flows" - things that go thru multiple steps.
|
||||
|
||||
For example, this service represents a "direct file upload flow", with a `start` and `finish` (and additionally):
|
||||
|
||||
```python
|
||||
# https://github.com/HackSoftware/Django-Styleguide-Example/blob/master/styleguide_example/files/services.py
|
||||
|
||||
|
||||
class FileDirectUploadService:
|
||||
"""
|
||||
This also serves as an example of a service class,
|
||||
which encapsulates a flow (start & finish) + one-off action (upload_local) into a namespace.
|
||||
|
||||
Meaning, we use the class here for:
|
||||
|
||||
1. The namespace
|
||||
"""
|
||||
def __init__(self, user: BaseUser):
|
||||
self.user = user
|
||||
|
||||
@transaction.atomic
|
||||
def start(self, *, file_name: str, file_type: str) -> Dict[str, Any]:
|
||||
file = File(
|
||||
original_file_name=file_name,
|
||||
file_name=file_generate_name(file_name),
|
||||
file_type=file_type,
|
||||
uploaded_by=self.user,
|
||||
file=None
|
||||
)
|
||||
file.full_clean()
|
||||
file.save()
|
||||
|
||||
upload_path = file_generate_upload_path(file, file.file_name)
|
||||
|
||||
"""
|
||||
We are doing this in order to have an associated file for the field.
|
||||
"""
|
||||
file.file = file.file.field.attr_class(file, file.file.field, upload_path)
|
||||
file.save()
|
||||
|
||||
presigned_data: Dict[str, Any] = {}
|
||||
|
||||
if settings.FILE_UPLOAD_STORAGE == FileUploadStorage.S3:
|
||||
presigned_data = s3_generate_presigned_post(
|
||||
file_path=upload_path, file_type=file.file_type
|
||||
)
|
||||
|
||||
else:
|
||||
presigned_data = {
|
||||
"url": file_generate_local_upload_url(file_id=str(file.id)),
|
||||
}
|
||||
|
||||
return {"id": file.id, **presigned_data}
|
||||
|
||||
@transaction.atomic
|
||||
def finish(self, *, file: File) -> File:
|
||||
# Potentially, check against user
|
||||
file.upload_finished_at = timezone.now()
|
||||
file.full_clean()
|
||||
file.save()
|
||||
|
||||
return file
|
||||
```
|
||||
|
||||
### Naming convention
|
||||
|
||||
Naming convention depends on your taste. It pays off to have something consistent throughout a project.
|
||||
|
|
Loading…
Reference in New Issue
Block a user