Source code for fobi.contrib.apps.drf_integration.views

from django.contrib import messages
from django.http import HttpRequest
from django.utils.translation import gettext
from rest_framework import mixins, permissions
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from ....constants import (
    CALLBACK_BEFORE_FORM_VALIDATION,
    CALLBACK_FORM_INVALID,
    CALLBACK_FORM_VALID,
    CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS,
    CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
)
from ....models import FormEntry
from .base import (
    fire_form_callbacks,
    run_form_handlers,
    submit_plugin_form_data,
)
from .dynamic import get_declared_fields
from .metadata import FobiMetaData
from .serializers import FormEntrySerializer
from .utils import get_serializer_class

__title__ = "fobi.contrib.apps.drf_integration.views"
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2014-2019 Artur Barseghyan"
__license__ = "GPL 2.0/LGPL 2.1"
__all__ = ("FobiFormEntryViewSet",)


[docs]class FobiFormEntryViewSet( # mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, # mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet, ): """FormEntry view set.""" # By definition of this app we have only list, detail and update actions. # In update action we are going to handle form entry creation. # In case of self.action == 'update' or 'partial_update' we do need to # show dynamic serializer of the form fields (not of the model). # In all other cases, we need to show serializer of the model (which is # simply one field - model slug). queryset = FormEntry.objects.filter(is_public=True).select_related("user") permission_classes = [permissions.AllowAny] lookup_field = "slug" lookup_url_kwarg = "slug" metadata_class = FobiMetaData
[docs] def has_value(self): return None if self.action == "metadata" else True
[docs] def get_queryset(self): """Get queryset. We show all forms to authenticated users and show only public forms to non-authenticated users. """ user_is_authenticated = self.request.user.is_authenticated kwargs = {} if not user_is_authenticated: kwargs.update({"is_public": True}) return FormEntry.objects.select_related("user").filter(**kwargs)
[docs] def get_object(self): """Override get_object to get things done.""" obj = super(FobiFormEntryViewSet, self).get_object() # OK, calling this twice sucks, but fine for the time being. # In future we should try to get rid of additional queries # made double. declared_fields, declared_fields_metadata = get_declared_fields( obj, has_value=self.has_value() ) # Setting all the fields, one by one like they were attributes of # the object (while they are obviously NOT). It's all done just to # trick the rest_framework and make a profit of all the nice things # it provides with as little efforts as possible. However, we NEVER # save the object. for field_name, field_instance in declared_fields.items(): setattr(obj, field_name, field_instance.initial) # Return "patched" object. return obj
[docs] def get_serializer(self, *args, **kwargs): """Get the serializer.""" if self.action in ("update", "partial_update", "metadata"): serializer_class = self.get_serializer_class() # kwargs['context'] = {'request': self.request} kwargs["context"] = self.get_serializer_context() else: serializer_class = FormEntrySerializer # kwargs['context'] = {'request': self.request} kwargs["context"] = self.get_serializer_context() serializer = serializer_class(*args, **kwargs) # if 'data' in kwargs: # serializer.is_valid() return serializer
[docs] def get_serializer_class(self): """Get serializer class.""" form_entry = self.get_object() serializer_class = get_serializer_class( form_entry=form_entry, request=self.request, has_value=self.has_value(), ) return serializer_class
[docs] def update(self, request, *args, **kwargs): partial = kwargs.pop("partial", False) instance = self.get_object() serializer = self.get_serializer( instance, data=request.data, partial=partial ) serializer.is_valid(raise_exception=True) self.perform_update(serializer) # Handle submitted form data by firing form handler plugins. self._handle_form_entry_data_submission( form_entry=instance, request=request, serializer=serializer ) if getattr(instance, "_prefetched_objects_cache", None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return Response(serializer.data)
def _handle_form_entry_data_submission( self, form_entry, request, serializer ): """Handle form entry data submission.""" # Try to fetch only once. form_element_entries = form_entry.formelemententry_set.all() # Fire form valid before submit plugin data serializer = fire_form_callbacks( form_entry=form_entry, request=request, serializer=serializer, stage=CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA, ) # Fire plugin processors serializer = submit_plugin_form_data( form_entry=form_entry, request=request, serializer=serializer ) # Fire form valid callbacks serializer = fire_form_callbacks( form_entry=form_entry, request=request, serializer=serializer, stage=CALLBACK_FORM_VALID, ) # Run all handlers handler_responses, handler_errors = run_form_handlers( form_entry=form_entry, request=request, serializer=serializer, form_element_entries=form_element_entries, ) # Warning that not everything went ok. if handler_errors: _request = ( request if isinstance(request, HttpRequest) else request._request ) for handler_error in handler_errors: messages.warning( _request, gettext("Error occurred: {0}.").format(handler_error), ) # Fire post handler callbacks fire_form_callbacks( form_entry=form_entry, request=request, serializer=serializer, stage=CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS, )