django-alt is an alternative approach to data validation and REST endpoint definition in Django and DRF.
Latest version is 0.74.
Requirements: this package depends on django and djangorestframework.
pip install django-alt
- No standardized way to separate domain and data logic.
- No standardized way to validate serialized data.
- Standard validation techniques do not offer any mechanisms for separation of concerns. (e.g. validating object creation vs. update).
- Cumbersome lifecycle hooks (e.g. code to execute upon object creation).
- Allow more declarative expressions while making it easy to spice them up.
This package aims to help solving these problems. It allows a notion of a
validator – an encapsulation of domain logic for a given model.
Validators allow you to:
- Handle before and after lifecycle events of model changes (creation, update, deletion).
- Write arbitrary methods to clean and validate individual fields that are automatically called when needed.
- Write arbitrary methods to validate interdependent fields.
This package also includes managers and endpoints – means to automate
validated model object management as REST resources (or not). A plentiful of
shorthand helpers make validating CRUD ops feel like a breeze. Validators also easily tie into existing infrastructure.
Be sure to also
checkout recipes.md
for quick–starting and more examples
or indepth.md
for a deeper dive.
class TodoEndpoint(Endpoint):
serializer = TodoSerializer
config = {
'get, patch, delete': {
'queryset': lambda todo, **url: todo.objects.get(id=url['pk'])
}
}class TodoValidator(Validator):
def clean(self, attrs):
attrs['slug'] = slugify(attrs['name'])
def clean_author(self, author):
return author.capitalize()
def field_author(self, author):
invalid_if(not author.is_active, 'author', 'Sorry, you cannot post')
def did_create(self, instance, validated_attrs):
inform_subscribers(instance)class TodoSerializer(ValidatedModelSerializer):
class Meta:
model = Todo
fields = '__all__'
validator_class = TodoValidatorclass TodoSpecialEndpoint(Endpoint):
serializer = TodoSerializer
config = {
'get': {
'queryset': lambda todo, **url: todo.objects.all(),
'filters': {
'hot': lambda: qs, hot: qs.filter(hot=hot),
'confirmed': lambda: qs, confirmed: qs.filter(confirmed=confirmed)
}
}
}
@classmethod
def can_get(cls):
pre_permission = lambda request, **url: not request.user.is_anonymous
post_permission = lambda request, queryset, attrs: not attrs.get('confirmed', False)
return (pre_permission, post_permission)urlpatterns = [url(r'^todos/$', TodoSpecialEndpoint.as_view())]This code would automatically create a behind-the-scenes view. This simple definition uses some powerful concepts:
/todos/would return all Todo objects serialized as JSON./todos/?hot=truewould return all Todo objects that have an attributehotthat is true./todos/?confirmed=truewould return all Todo objects that have an attributeconfirmedthat is true./todos/?confirmed=true&hot=trueyou can probably guess...
While on the 0.x track, this project is subject to rapid development and some changes might break reverse–compatibility. Any contribution or ideas are welcome!
To see the hot upcoming features, switch to the dev-1.0 branch.
Vilius Poška.
This project is freely licensed under the MIT license.