92 lines
2.9 KiB
Python
Executable File
92 lines
2.9 KiB
Python
Executable File
from deepmerge import Merger, STRATEGY_END
|
|
from django.db.models.signals import class_prepared
|
|
from django.utils.functional import curry
|
|
from django_fsm import (
|
|
FSMFieldMixin,
|
|
get_all_FIELD_transitions,
|
|
get_available_FIELD_transitions,
|
|
get_available_user_FIELD_transitions,
|
|
)
|
|
from rest_framework.request import _hasattr, is_form_media_type, Request
|
|
|
|
__all__ = ["patches"]
|
|
|
|
|
|
def merge_dicts(config, path, base, nxt):
|
|
if isinstance(base, list) and isinstance(nxt, list) and len(base) == len(nxt):
|
|
data = [{**a, **b} for a, b in zip(base, nxt)]
|
|
return data
|
|
return STRATEGY_END
|
|
|
|
|
|
merger = Merger(
|
|
[(list, merge_dicts), (list, "append"), (dict, "merge")], ["override"], ["override"]
|
|
)
|
|
|
|
|
|
def _patched_load_data_and_files(self):
|
|
"""
|
|
Parses the request content into `self.data`.
|
|
"""
|
|
if not _hasattr(self, "_data"):
|
|
self._data, self._files = self._parse()
|
|
if self._files:
|
|
self._full_data = merger.merge(self._data, self._files)
|
|
else:
|
|
self._full_data = self._data
|
|
|
|
# if a form media type, copy data & files refs to the underlying
|
|
# http request so that closable objects are handled appropriately.
|
|
if is_form_media_type(self.content_type):
|
|
self._request._post = self.POST
|
|
self._request._files = self.FILES
|
|
|
|
|
|
def _modified_contribute_to_class(self, cls, name, **kwargs):
|
|
self.base_cls = cls
|
|
|
|
super(FSMFieldMixin, self).contribute_to_class(cls, name, **kwargs)
|
|
setattr(cls, f"{self.name}_description", self.descriptor_class(self))
|
|
setattr(
|
|
cls,
|
|
"get_all_{0}_transitions".format(self.name),
|
|
curry(get_all_FIELD_transitions, field=self),
|
|
)
|
|
setattr(
|
|
cls,
|
|
"get_available_{0}_transitions".format(self.name),
|
|
curry(get_available_FIELD_transitions, field=self),
|
|
)
|
|
setattr(
|
|
cls,
|
|
"get_available_user_{0}_transitions".format(self.name),
|
|
curry(get_available_user_FIELD_transitions, field=self),
|
|
)
|
|
class_prepared.connect(self._collect_transitions)
|
|
|
|
|
|
# Do not obscure related model in FSMKeyField
|
|
# Pull request https://github.com/viewflow/django-fsm/pull/200/files#diff-7b4b9604f1842ff54833d14e644e9710
|
|
|
|
|
|
class Patches:
|
|
def __init__(self):
|
|
self._load_data_and_files = None
|
|
self._contribute_to_class = None
|
|
|
|
def on(self):
|
|
self._load_data_and_files = Request._load_data_and_files
|
|
self._contribute_to_class = FSMFieldMixin.contribute_to_class
|
|
|
|
Request._load_data_and_files = _patched_load_data_and_files
|
|
FSMFieldMixin.contribute_to_class = _modified_contribute_to_class
|
|
|
|
def off(self):
|
|
if self._load_data_and_files:
|
|
Request._load_data_and_files = self._load_data_and_files
|
|
if self._contribute_to_class:
|
|
FSMFieldMixin.contribute_to_class = self._contribute_to_class
|
|
|
|
|
|
patches = Patches()
|