text: from functools import wraps
  from rest_framework.request import Request
  from django.core.cache import cache
  from datetime import datetime, timedelta
  import time
  from drf_util.exceptions import ValidationException
  
  
  def serialize_decorator(serializer_method, preview_function=None, read_params=False, partial=False):
      def _new_decorator(view_func):
          def _decorator(*args, **kwargs):
              request = next(filter(lambda arg: isinstance(arg, Request), args))
  
              if request.method in ["POST", "PATCH", "PUT", "DELETE"]:
                  data = request.query_params if read_params else request.data
              else:
                  data = request.query_params
  
              # if need to change data before serialize
              if preview_function:
                  data = data.copy()
                  data = preview_function(data)
  
              # serialize data
              serializer = serializer_method(data=data, partial=partial, context={"request": request})
              if serializer.is_valid():
                  request.valid = serializer.validated_data
                  request.serializer = serializer
                  return view_func(*args, **kwargs)
  
              # if data not is valid
              raise ValidationException(serializer.errors)
  
          return wraps(view_func)(_decorator)
  
      return _new_decorator
  
  
  # ======================================================================================================================
  # Semaphore decorator
  # ======================================================================================================================
  def await_checker(key, step):
      """
          Function for checking time for starting function
          @param {string} key - cache key, usually it's function name
          @param {integer} step - seconds to next usage
          @return None
      """
      now_date = datetime.now()
      # getting next date to using this function
      next_use_date = cache.get(key, datetime.now())
      # define how much seconds need to wait
      seconds = (next_use_date - now_date).total_seconds()
      if seconds < 0:
          # sleep can't be negative second, set 0
          seconds = 0
      # override next date to using this function
      set_await(key, seconds + step)
      time.sleep(seconds)
  
  
  def set_await(key, seconds):
      """
          Function for define and override next date to using function
          @param {string} key
          @param {integer} seconds
          @return None
      """
      next_date = datetime.now() + timedelta(seconds=seconds)
      cache.set(key, next_date, seconds)
  
  
  def await_process_decorator(rate=20, period=60):
      """
      decorator for some function, checking and updating time to waiting for use this function
      @param {integer} rate : count of usage some function, by default it's 20 times
      @param {integer} period : period of usage some function,  by default it's 1 minute
      """
  
      def decorator(function):
          def wrapper(*args, **kwargs):
              # define step, by default it's 20 times in 1 minute
              step = period / rate
              # checking time
              await_checker(function.__name__, step)
              # running function, after waiting
              return function(*args, **kwargs)
  
          return wrapper
  
      return decorator
  