Skip to content

Commit

Permalink
[WIP] feat(mixin, middleware): add a set of view mixin and session mi…
Browse files Browse the repository at this point in the history
…ddleware (#1)

* feat(mixin, middleware): add a set of view mixin and session middleware

* docs(readme): add readme

* feat(setup): add setup
  • Loading branch information
legshort authored May 1, 2019
1 parent ba24560 commit 379b0d6
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ venv.bak/

# mypy
.mypy_cache/


#ide
.idea
174 changes: 174 additions & 0 deletions READEME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#Django Rest Framework Mango

A set of viewset mixin for the [Django REST Framework.](https://www.django-rest-framework.org/)

##Installation
`pip install djangorestframework-mango`

##Usage

###ActionMixin
It has six action methods that can be use instead of compare action with str
- `is_create_action()`
- `is_retrieve_action()`
- `is_list_action()`
- `is_update_action()`
- `is_partial_update_action()`
- `is_destroy_action()`


```python
class ViewSet(ActionMixin, viewsets.GenericViewSet):
queryset = Model.objects.all()
serializer_class = ModelSerializer


def get_queryset(self):
queryset = super().get_queryset()

if self.is_create_action:
# change queryset for create
queryset = queryset.change_for_create()
elif self.is_retrieve_action():
# change queryset for retrieve
queryset = queryset.change_for_retrieve()
elif self.is_list_action():
# change queryset for list
queryset = queryset.change_for_list()
elif self.is_update_action():
# change queryset for update
queryset = queryset.change_for_update()
elif self.is_partial_update_action():
# change queryset for partial update
queryset = queryset.change_for_partial_update()
elif self.is_destroy_action():
# change queryset for destroy
queryset = queryset.change_for_destroy()

return queryset
```

###QuerysetMixin
It find action base queryset method and run it

```python
class ViewSet(QuerysetMixin, viewsets.GenericViewSet):
queryset = Model.objects.all()
serializer_class = ModelSerializer

# this method run automatically when this viewset gets create action
def create_queryset(self, queryset):
queryset = queryset.change_for_create()
return queryset

# this method run automatically when this viewset gets list action
def list_queryset(self, queryset):
queryset = queryset.change_for_list()
return queryset

# this method run automatically when this viewset gets retrieve action
def retrieve_queryset(self, queryset):
queryset = queryset.change_for_retrieve()
return queryset
# this method run automatically when this viewset gets update action
def update_queryset(self, queryset):
queryset = queryset.change_for_update()
return queryset
# this method run automatically when this viewset gets partial update action
def partil_update_queryset(self, queryset):
queryset = queryset.change_for_partial_update()
return queryset
# this method run automatically when this viewset gets destroy action
def destroy_queryset(self, queryset):
queryset = queryset.change_for_delete()
return queryset

# this method run automatically when this viewset gets update_extra_profile action
def update_extra_profile_queryset(self, queryset):
queryset = queryset.change_for_update_extra_profile()
return queryset

@action(methods['POST'], detail=True)
def update_extra_profile(self, request, pk=None):
# this method calls update_extra_profile_queryset() internally
queryset = self.get_queryset()

return Response(serializer.data)
```

###SerializerMixin
You can define multi serializers by action

```python
class ViewSet(QuerysetMixin, viewsets.GenericViewSet):
queryset = Model.objects.all()
serializer_class = ModelSerializer
serializer_class_by_actions = {
'create': ModelCreateSerializer,
'list': ModelListSerializer,
'retrieve': ModelRetrieveSerializer,
'update': ModelUpdateSerializer,
'partial_update': ModelParitlaUpdateSerializer,
'destory': ModelDestorySerializer,
'update_extra_profile': ModelUpdateExtraProfileSerializer,
}

@action(methods['POST'], detail=True)
def update_extra_profile(self, request, pk=None):
# self.get_serializer returns ModelUpdateExtraProfileSerializer
serializer = self.get_serializer()

return Response(serializer.data)
```

###PermissionMixin
You can define multi permissions by action

```python
class ViewSet(QuerysetMixin, viewsets.GenericViewSet):
queryset = Model.objects.all()
serializer_class = ModelSerializer
permission_by_actions = {
'create': [Authenticated],
'list': [ReadOnly],
'retrieve': [AllowAny],
'update': [Owner],
'partial_update': [Owner],
'destory': [Owner],
'update_extra_profile': [Owner],
}

@action(methods['POST'], detail=True)
def update_extra_profile(self, request, pk=None):
# this method requires Owner permission
serializer = self.get_serializer()

return Response(serializer.data)
```

###SessionMiddleware
You can use session data within request life cycle.
- add SessionMiddleware
- use session from view, serializer and model

```python
class ViewSet(viewsets.GenericViewSet):
queryset = Model.objects.all()
serializer_class = ModelSerializer

def list_queryset(self, queryset):
session = SessionMiddleware.get_session()
session['current_user'] = self.request.user

return queryset

class Model(DjangoModel):

@property
def current_user(self):
session = SessionMiddleware.get_session()
session['current_user'] = self.request.user

return session['current_user']

```
Empty file.
27 changes: 27 additions & 0 deletions django-rest-framework-mango/middlewares.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import threading


class SessionMiddleware:
_sessions = {}

def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
self._init_session(request)

response = self.get_response(request)

self._remove_session()

return response

def _init_session(self, request):
self._sessions[threading.current_thread()] = request

def _remove_session(self):
self._sessions.pop(threading.current_thread(), None)

@classmethod
def get_session(cls):
return cls._sessions.get(threading.current_thread())
63 changes: 63 additions & 0 deletions django-rest-framework-mango/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
class ActionMixin:
def is_create_action(self):
return 'create' == self.action

def is_retrieve_action(self):
return 'retrieve' == self.action

def is_list_action(self):
return 'list' == self.action

def is_update_action(self):
return 'update' == self.action

def is_partial_update_action(self):
return 'partial_update' == self.action

def is_destroy_action(self):
return 'destroy' == self.action


class QuerysetMixin(ActionMixin):
def get_queryset(self):
queryset = super().get_queryset()

if self.is_create_action and hasattr(self, 'create_queryset'):
queryset = self.create_queryset(queryset)
elif self.is_retrieve_action() and hasattr(self, 'retrieve_queryset'):
queryset = self.retrieve_queryset(queryset)
elif self.is_list_action() and hasattr(self, 'list_queryset'):
queryset = self.list_queryset(queryset)
elif self.is_update_action() and hasattr(self, 'update_queryset'):
queryset = self.update_queryset(queryset)
elif self.is_partial_update_action() and hasattr(self, 'partial_update_queryset'):
queryset = self.partial_update_queryset(queryset)
elif self.is_destroy_action() and hasattr(self, 'destroy_queryset'):
queryset = self.destroy_queryset(queryset)
elif hasattr(self, f'{self.action}_queryset'):
queryset_method = getattr(self, f'{self.action}_queryset')
queryset = queryset_method(queryset)

return queryset


class SerializerMixin:
def get_serializer_class(self):
if hasattr(self, 'serializer_class_by_actions'):
return self.serializer_class_by_actions.get(self.action, self.serializer_class)

return self.serializer_class


class PermissionMixin:
def get_permissions(self):
permission_classes = self.permission_classes

if hasattr(self, 'permission_by_actions'):
permission_classes = self.permission_by_actions.get(self.action, self.permission_classes)

return [permission() for permission in permission_classes]


class MangoMixin(QuerysetMixin, SerializerMixin, PermissionMixin):
pass
20 changes: 20 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from setuptools import setup

setup(name='django-rest-framework-mango',
version='0.1',
url='https://github.com/legshort/django-rest-framework-mango/',
license='MIT',
author='Jun Young Lee',
author_email='[email protected]',
description='A set of viewset mixin for the Django REST Framework.',
classifiers=[
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
],
keywords=['djangorestframework', 'drf', 'util', 'viewset'],
packages=['django-rest-framework-mango'],
long_description=open('README.md').read(),
install_requires=[
'django',
'djangorestframework', ]
)

0 comments on commit 379b0d6

Please sign in to comment.