Package: django-service-objects
django-service-objectsService objects for DjangoWhat?This is a small library providing aServicebase class to derive your service objects from. What are service objects? You can read more about the whys and hows inthis blog post, 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.Installation guideInstall from pypi:pip install django-service-objectsAddservice_objectsto yourINSTALLED_APPS:# settings.pyINSTALLED_APPS=(...'service_objects',...)ExampleLet's say you want to register new users. You could make aCreateUserservice.fromdjangoimportformsfromservice_objects.servicesimportServiceclassCreateUser(Service):email=forms.EmailField()password=forms.CharField(max_length=255)subscribe_to_newsletter=forms.BooleanField(required=False)defprocess(self):email=self.cleaned_data['email']password=self.cleaned_data['password']subscribe_to_newsletter=self.cleaned_data['subscribe_to_newsletter']self.user=User.objects.create_user(username=email,email=email,password=password)self.subscribe_to_newsletter=subscribe_to_newsletterifself.subscribe_to_newsletter:newsletter=Newsletter.objects.get()newsletter.subscribers.add(self.user)newsletter.save()returnself.userdefpost_process(self):WelcomeEmail.send(self.user,is_subscribed=self.subsribe_to_newsletter)# Calling a celery task after successfully creating the user.create_billing_account.delay(self.user.id)Notice that it's basically a Django form but with aprocessmethod. This method gets called when you callexecute()on the process. If your inputs are invalid, it raisesInvalidInputsError.The newly addedpost_processcan also be included for running extra tasks that need to be executed after the service completes.Here's how you use it:CreateUser.execute({'email':'kvothe@edemaruh.com','password':'doorsofstone','subscribe_to_newsletter':True,})Now you can use it anywhere.In your views# views.py# Function Based Viewdefcreate_user_view(request):form=NewUserForm()ifrequest.method=='POST':form=NewUserForm(request.POST)ifform.is_valid():try:CreateUser.execute(request.POST)returnredirect('/success/')exceptException:form.add_error(None,'Something went wrong')returnrender(request,'registration/new-user.html',{'form':form})# Class Based ViewclassCreateUserView(ServiceView):form_class=NewUserFormservice_class=CreateUsertemplate_name='registration/new-user.html'success_url='/success/'A management command# management/commands/create_user.pyclassCommand(BaseCommand):help="Creates a new user"defadd_arguments(self,parser):parser.add_argument('email')parser.add_argument('password')defhandle(self,*args,**options):user=CreateUser.execute(options)self.stdout.write(f'New user created :{user.email}')In your testsclassCreateUserTest(TestCase):deftest_create_user(self):inputs={'email':'kvothe@edemaruh.com','password':'do0r$0f$stone42','subscribe_to_newsletter':True,}CreateUser.execute(inputs)user=User.objects.get()self.assertEqual(user.email,inputs['email'])newsletter=Newsletter.objects.get()self.assertIn(user,newsletter.subscribers.all())And anywhere you want. You can even execute services inside other services. The possibilities are endless!DocumentationDocs can be found onreadthedocs.If you have any questions about service objects, you can tweet me@mixxorz.