Skip to main content

Service objects for Django

Project description

django-service-objects Latest Version

Build Status Python Support PyPI - Django Version License

Service objects for Django

What?

This 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, 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 guide

Install from pypi:

pip install django-service-objects

Add service_objects to your INSTALLED_APPS:

# settings.py

INSTALLED_APPS = (
    ...
    'service_objects',
    ...
)

Example

Let's say you want to register new users. You could make a CreateUser service.

from django import forms

from service_objects.services import Service

class CreateUser(Service):
    email = forms.EmailField()
    password = forms.CharField(max_length=255)
    subscribe_to_newsletter = forms.BooleanField(required=False)

    def process(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_newsletter

        if self.subscribe_to_newsletter:
            newsletter = Newsletter.objects.get()
            newsletter.subscribers.add(self.user)
            newsletter.save()
            
        return self.user
    
    def post_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 a process method. This method gets called when you call execute() on the process. If your inputs are invalid, it raises InvalidInputsError.

The newly added post_process can 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 View
def create_user_view(request):
    form = NewUserForm()
    if request.method == 'POST':
        form = NewUserForm(request.POST)

        if form.is_valid():
            try:
                CreateUser.execute(request.POST)
                return redirect('/success/')
            except Exception:
                form.add_error(None, 'Something went wrong')

    return render(request, 'registration/new-user.html', {'form': form})


# Class Based View
class CreateUserView(ServiceView):
    form_class = NewUserForm
    service_class = CreateUser
    template_name = 'registration/new-user.html'
    success_url = '/success/'

A management command

# management/commands/create_user.py

class Command(BaseCommand):
    help = "Creates a new user"

    def add_arguments(self, parser):
        parser.add_argument('email')
        parser.add_argument('password')

    def handle(self, *args, **options):
        user = CreateUser.execute(options)
        self.stdout.write(f'New user created : {user.email}')

In your tests

class CreateUserTest(TestCase):

    def test_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!

Documentation

Docs can be found on readthedocs.

If you have any questions about service objects, you can tweet me @mixxorz.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-service-objects-0.7.0.tar.gz (10.8 kB view details)

Uploaded Source

File details

Details for the file django-service-objects-0.7.0.tar.gz.

File metadata

  • Download URL: django-service-objects-0.7.0.tar.gz
  • Upload date:
  • Size: 10.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.6.7

File hashes

Hashes for django-service-objects-0.7.0.tar.gz
Algorithm Hash digest
SHA256 42be7b09c5df229951d849c99cd7efc414e01caa15c3b652ba5e668a35f18888
MD5 f5cab5d6fa42911261a38b60b3e6bdf1
BLAKE2b-256 bc070bf4af701b0ae8cd9a8b66251e968ff8169cad2ff3adb54088da261d0707

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page