{"id":13813615,"url":"https://github.com/mixxorz/django-service-objects","last_synced_at":"2025-05-16T16:08:35.738Z","repository":{"id":43685001,"uuid":"100189062","full_name":"mixxorz/django-service-objects","owner":"mixxorz","description":"Service objects for Django","archived":false,"fork":false,"pushed_at":"2022-12-19T18:48:31.000Z","size":93,"stargazers_count":337,"open_issues_count":7,"forks_count":29,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-10T04:33:52.039Z","etag":null,"topics":["business-logic","design-patterns","django","python","service"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mixxorz.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-13T16:16:33.000Z","updated_at":"2025-04-19T00:00:48.000Z","dependencies_parsed_at":"2023-01-29T22:31:16.321Z","dependency_job_id":null,"html_url":"https://github.com/mixxorz/django-service-objects","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2Fdjango-service-objects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2Fdjango-service-objects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2Fdjango-service-objects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2Fdjango-service-objects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mixxorz","download_url":"https://codeload.github.com/mixxorz/django-service-objects/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254564127,"owners_count":22092122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["business-logic","design-patterns","django","python","service"],"created_at":"2024-08-04T04:01:23.267Z","updated_at":"2025-05-16T16:08:35.719Z","avatar_url":"https://github.com/mixxorz.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# django-service-objects [![Latest Version][latest-version-image]][latest-version-link]\n[![Build Status][build-status-image]][build-status-link]\n[![Python Support][python-support-image]][python-support-link]\n[![PyPI - Django Version][django-version-image]][django-link]\n[![License][license-image]][license-link]\n\nService objects for Django\n\n## What?\n\nThis is a small library providing a `Service` base class to derive your service objects from. What are service objects? You can read more about the whys and hows in [this blog post](http://mitchel.me/2017/django-service-objects/), but for the most part, it encapsulates your business logic, decoupling it from your views and model methods. Put your business logic in service objects.\n\n## Installation guide\n\nInstall from pypi:\n\n`pip install django-service-objects`\n\nAdd `service_objects` to your `INSTALLED_APPS`:\n\n```python\n# settings.py\n\nINSTALLED_APPS = (\n    ...\n    'service_objects',\n    ...\n)\n```\n\n## Example\n\nLet's say you want to register new users. You could make a `CreateUser` service.\n\n```python\nfrom django import forms\n\nfrom service_objects.services import Service\n\nclass CreateUser(Service):\n    email = forms.EmailField()\n    password = forms.CharField(max_length=255)\n    subscribe_to_newsletter = forms.BooleanField(required=False)\n\n    def process(self):\n        email = self.cleaned_data['email']\n        password = self.cleaned_data['password']\n        subscribe_to_newsletter = self.cleaned_data['subscribe_to_newsletter']\n\n        self.user = User.objects.create_user(username=email, email=email, password=password)\n        self.subscribe_to_newsletter = subscribe_to_newsletter\n\n        if self.subscribe_to_newsletter:\n            newsletter = Newsletter.objects.get()\n            newsletter.subscribers.add(self.user)\n            newsletter.save()\n            \n        return self.user\n    \n    def post_process(self):\n        WelcomeEmail.send(self.user, is_subscribed=self.subsribe_to_newsletter)\n        \n        # Calling a celery task after successfully creating the user.\n        create_billing_account.delay(self.user.id)\n```\n\nNotice that it's basically a Django form but with a `process` method. This method gets called when you call `execute()` on the process. If your inputs are invalid, it raises `InvalidInputsError`.\n\nThe newly added `post_process` can also be included for running extra tasks that need to be executed after the service completes.\n\nHere's how you use it:\n\n```python\nCreateUser.execute({\n    'email': 'kvothe@edemaruh.com',\n    'password': 'doorsofstone',\n    'subscribe_to_newsletter': True,\n})\n```\n\nNow you can use it anywhere.\n\nIn your views\n\n```python\n# views.py\n\n# Function Based View\ndef create_user_view(request):\n    form = NewUserForm()\n    if request.method == 'POST':\n        form = NewUserForm(request.POST)\n\n        if form.is_valid():\n            try:\n                CreateUser.execute(request.POST)\n                return redirect('/success/')\n            except Exception:\n                form.add_error(None, 'Something went wrong')\n\n    return render(request, 'registration/new-user.html', {'form': form})\n\n\n# Class Based View\nclass CreateUserView(ServiceView):\n    form_class = NewUserForm\n    service_class = CreateUser\n    template_name = 'registration/new-user.html'\n    success_url = '/success/'\n\n```\n\nA management command\n\n```python\n# management/commands/create_user.py\n\nclass Command(BaseCommand):\n    help = \"Creates a new user\"\n\n    def add_arguments(self, parser):\n        parser.add_argument('email')\n        parser.add_argument('password')\n\n    def handle(self, *args, **options):\n        user = CreateUser.execute(options)\n        self.stdout.write(f'New user created : {user.email}')\n\n```\n\nIn your tests\n\n```python\nclass CreateUserTest(TestCase):\n\n    def test_create_user(self):\n        inputs = {\n            'email': 'kvothe@edemaruh.com',\n            'password': 'do0r$0f$stone42',\n            'subscribe_to_newsletter': True,\n        }\n\n        CreateUser.execute(inputs)\n\n        user = User.objects.get()\n        self.assertEqual(user.email, inputs['email'])\n\n        newsletter = Newsletter.objects.get()\n        self.assertIn(user, newsletter.subscribers.all())\n```\n\nAnd anywhere you want. You can even execute services inside other services. The possibilities are endless!\n\n## Documentation\n\nDocs can be found on [readthedocs](http://django-service-objects.readthedocs.io/en/stable/).\n\nIf you have any questions about service objects, you can tweet me [@mixxorz](https://twitter.com/mixxorz).\n\n[latest-version-image]: https://img.shields.io/pypi/v/django-service-objects.svg\n[latest-version-link]: https://pypi.org/project/django-service-objects/\n[build-status-image]: https://github.com/mixxorz/django-service-objects/workflows/Test/badge.svg\n[build-status-link]: https://github.com/mixxorz/django-service-objects/actions\n[python-support-image]: https://img.shields.io/pypi/pyversions/django-service-objects.svg\n[python-support-link]: https://pypi.org/project/django-service-objects/\n[django-version-image]: https://img.shields.io/pypi/djversions/django_service_objects.svg\n[django-link]: https://docs.djangoproject.com/en/3.0/releases/\n[license-image]: https://img.shields.io/pypi/l/django-service-objects.svg\n[license-link]: https://github.com/mixxorz/django-service-objects/blob/master/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixxorz%2Fdjango-service-objects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmixxorz%2Fdjango-service-objects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixxorz%2Fdjango-service-objects/lists"}