Skip to main content
Glama
dmmeteo

Django Styleguide MCP Server

by dmmeteo
example-class-based-service.md5.74 kB
### Example - class-based service **Additionally, we can have "class-based" services**, which is a fancy way of saying - wrap the logic in a class. 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 # 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. Meaning, we use the class here for: 1. The namespace 2. The ability to reuse `_infer_file_name_and_type` (which can also be an util) """ def __init__(self, user: BaseUser, file_obj): self.user = user self.file_obj = file_obj def _infer_file_name_and_type(self, file_name: str = "", file_type: str = "") -> Tuple[str, str]: file_name = file_name or self.file_obj.name if not file_type: guessed_file_type, encoding = mimetypes.guess_type(file_name) file_type = guessed_file_type or "" return file_name, file_type @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( file=self.file_obj, original_file_name=file_name, file_name=file_generate_name(file_name), file_type=file_type, uploaded_by=self.user, upload_finished_at=timezone.now() ) obj.full_clean() obj.save() return obj @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 file.original_file_name = file_name file.file_name = file_generate_name(file_name) file.file_type = file_type file.uploaded_by = self.user file.upload_finished_at = timezone.now() file.full_clean() file.save() return file ``` As stated in the comment, we are using this approach for 2 main reasons: 1. **Namespace.** We have a single namespace for our create & update. 1. **Reuse** of the `_infer_file_name_and_type` logic. Here's how this service is used: ```python # https://github.com/HackSoftware/Django-Styleguide-Example/blob/master/styleguide_example/files/apis.py class FileDirectUploadApi(ApiAuthMixin, APIView): def post(self, request): service = FileDirectUploadService( user=request.user, file_obj=request.FILES["file"] ) file = service.create() return Response(data={"id": file.id}, status=status.HTTP_201_CREATED) ``` And ```python @admin.register(File) class FileAdmin(admin.ModelAdmin): # ... other code here ... # https://github.com/HackSoftware/Django-Styleguide-Example/blob/master/styleguide_example/files/admin.py def save_model(self, request, obj, form, change): try: cleaned_data = form.cleaned_data service = FileDirectUploadService( file_obj=cleaned_data["file"], user=cleaned_data["uploaded_by"] ) if change: service.update(file=obj) else: service.create() except ValidationError as exc: self.message_user(request, str(exc), messages.ERROR) ``` Additionally, using class-based services is a good idea for "flows" - things that go through 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 ```

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dmmeteo/django-styleguide-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server