Please note that this is a squshed commit and the work of: Symbolist, macdiesel, nedbat, doctoryes, muzaffaryousaf and muhammad-ammar
74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
"""
|
|
API view to allow manipulation of configuration models.
|
|
"""
|
|
from rest_framework.generics import CreateAPIView, RetrieveAPIView
|
|
from rest_framework.permissions import DjangoModelPermissions
|
|
from rest_framework.authentication import SessionAuthentication
|
|
from rest_framework.serializers import ModelSerializer
|
|
from django.db import transaction
|
|
|
|
|
|
class ReadableOnlyByAuthors(DjangoModelPermissions):
|
|
"""Only allow access by users with `add` permissions on the model."""
|
|
perms_map = DjangoModelPermissions.perms_map.copy()
|
|
perms_map['GET'] = perms_map['OPTIONS'] = perms_map['HEAD'] = perms_map['POST']
|
|
|
|
|
|
class AtomicMixin(object):
|
|
"""Mixin to provide atomic transaction for as_view."""
|
|
@classmethod
|
|
def create_atomic_wrapper(cls, wrapped_func):
|
|
"""Returns a wrapped function."""
|
|
def _create_atomic_wrapper(*args, **kwargs):
|
|
"""Actual wrapper."""
|
|
# When a view call fails due to a permissions error, it raises an exception.
|
|
# An uncaught exception breaks the DB transaction for any following DB operations
|
|
# unless it's wrapped in a atomic() decorator or context manager.
|
|
with transaction.atomic():
|
|
return wrapped_func(*args, **kwargs)
|
|
|
|
return _create_atomic_wrapper
|
|
|
|
@classmethod
|
|
def as_view(cls, **initkwargs):
|
|
"""Overrides as_view to add atomic transaction."""
|
|
view = super(AtomicMixin, cls).as_view(**initkwargs)
|
|
return cls.create_atomic_wrapper(view)
|
|
|
|
|
|
class ConfigurationModelCurrentAPIView(AtomicMixin, CreateAPIView, RetrieveAPIView):
|
|
"""
|
|
This view allows an authenticated user with the appropriate model permissions
|
|
to read and write the current configuration for the specified `model`.
|
|
|
|
Like other APIViews, you can use this by using a url pattern similar to the following::
|
|
|
|
url(r'config/example_config$', ConfigurationModelCurrentAPIView.as_view(model=ExampleConfig))
|
|
"""
|
|
authentication_classes = (SessionAuthentication,)
|
|
permission_classes = (ReadableOnlyByAuthors,)
|
|
model = None
|
|
|
|
def get_queryset(self):
|
|
return self.model.objects.all()
|
|
|
|
def get_object(self):
|
|
# Return the currently active configuration
|
|
return self.model.current()
|
|
|
|
def get_serializer_class(self):
|
|
if self.serializer_class is None:
|
|
class AutoConfigModelSerializer(ModelSerializer):
|
|
"""Serializer class for configuration models."""
|
|
class Meta(object):
|
|
"""Meta information for AutoConfigModelSerializer."""
|
|
model = self.model
|
|
|
|
self.serializer_class = AutoConfigModelSerializer
|
|
|
|
return self.serializer_class
|
|
|
|
def perform_create(self, serializer):
|
|
# Set the requesting user as the one who is updating the configuration
|
|
serializer.save(changed_by=self.request.user)
|