Skip to content

Instantly share code, notes, and snippets.

@silviud
Forked from mixxorz/services.py
Created September 25, 2017 08:52
Show Gist options
  • Save silviud/5ca3936fedd587d4ffaeb82ecd0fc6ad to your computer and use it in GitHub Desktop.
Save silviud/5ca3936fedd587d4ffaeb82ecd0fc6ad to your computer and use it in GitHub Desktop.
Django Service Objects
from django import forms
from django.core.exceptions import ValidationError
from django.db import transaction
class InvalidInputsError(Exception):
def __init__(self, errors, non_field_errors):
self.errors = errors
self.non_field_errors = non_field_errors
def __str__(self):
return f'{repr(self.errors)} {repr(self.non_field_errors)}'
class Service(forms.Form):
def service_clean(self):
if not self.is_valid():
raise InvalidInputsError(self.errors, self.non_field_errors())
@classmethod
def execute(cls, inputs, files=None, **kwargs):
instance = cls(inputs, files, **kwargs)
instance.service_clean()
with transaction.atomic():
return instance.process()
def process(self):
raise NotImplementedError()
class MultipleFormField(forms.Field):
"""
A field that contains many forms, similar to a FormSet but easier to clean
"""
def __init__(self, form_class, min_count=1, max_count=None, *args,
**kwargs):
super().__init__(*args, **kwargs)
self.form_class = form_class
self.min_count = min_count
self.max_count = max_count
def clean(self, values):
if len(values) < self.min_count:
raise ValidationError(
f'There needs to be at least {self.min_count} item/s.')
if self.max_count and len(values) > self.max_count:
raise ValidationError(
f'There needs to be at most {self.max_count} item/s.')
item_forms = []
for index, item in enumerate(values):
item_form = self.form_class(item)
if not item_form.is_valid():
raise ValidationError(f'[{index}]: {repr(item_form.errors)}')
item_forms.append(item_form)
return item_forms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment