Skip to content

Instantly share code, notes, and snippets.

@fdemmer
Last active July 23, 2016 10:58
Show Gist options
  • Save fdemmer/311f7cb1fad16845636f13c15eb73e68 to your computer and use it in GitHub Desktop.
Save fdemmer/311f7cb1fad16845636f13c15eb73e68 to your computer and use it in GitHub Desktop.
Using marshmallow to parse/validate query parameters with a mixin for Django views
# -*- coding: utf-8 -*-
from marshmallow import Schema, fields
from django.utils.functional import cached_property
class ParameterMixin(object):
"""
Mixin for a View-like class for URL parameter parsing and validation using
marshmallow (works well with Django views or DRF ViewSets).
Inside the class define a marshmallow `Schema` with the URL parameters as
fields called "Parameters", eg::
from marshmallow import schema, fields
class MyView(View):
class Parameters(schema.Schema):
activate = fields.Boolean(missing=False)
The name of the class can be customized using `self.parameter_schema_name`.
Overload `self.get_parameters()` to customize the parameters source.
Then use the `self.query` cached_property to access cleaned, validated
parameters::
self.query['activate']
Upon first access to `self.query` the parameters are validated.
If the parameter schema was initialized in strict mode (default), this
may raise a `ValidationError` exception!
With DRF it is recommended to overload `handle_error` in the schema
class to raise a DRF `APIException` for a proper error response::
from rest_framework import viewsets, exceptions
class MyViewSet(ParameterMixin, viewsets.ReadOnlyModelViewSet):
class Parameters(schema.Schema):
updated_after = fields.DateTime(missing=None)
def handle_error(self, error, data):
raise exceptions.ValidationError(error.messages)
To disable strict validation set `self.parameter_strict` to `False`.
"""
parameter_schema_name = 'Parameters'
parameter_strict = True
@cached_property
def parameter_schema(self):
return self.get_parameter_schema()
@property
def _list_type_parameters(self):
return [
k for k, v in self.parameter_schema.fields.items()
if isinstance(v, fields.List)
]
def get_parameter_schema(self, strict=None):
cls = getattr(self, self.parameter_schema_name, Schema)
strict = strict if strict is not None else self.parameter_strict
return cls(strict=strict)
def get_parameters(self):
querydict = self.request.GET
return {
k: v if k in self._list_type_parameters else v[0]
for k, v in querydict.iterlists()
}
@cached_property
def query(self):
schema = self.get_parameter_schema()
# raises validation error, when schema is using strict
return schema.load(self.get_parameters()).data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment