jones-dev #19
@ -1,5 +1,7 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from rest_framework import serializers
|
||||
@ -7,8 +9,105 @@ from rest_framework import serializers
|
||||
from apps.home.models import Ticket, TicketPriority, TicketTag
|
||||
from apps.authentication.models import Department
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class DepartmentSerializer(serializers.ModelSerializer):
|
||||
|
||||
class DynamicModelSerializer(serializers.ModelSerializer):
|
||||
"""For use with GET requests, to specify which fields to include or exclude
|
||||
Mimics some graphql functionality.
|
||||
|
||||
Usage: Inherit your ModelSerializer with this class. Add "only_fields" or
|
||||
"exclude_fields" to the query parameters of your GET request.
|
||||
|
||||
This also works with nested foreign keys, for example:
|
||||
?only_fields=name,age&company__only_fields=id,name
|
||||
|
||||
Some more examples:
|
||||
|
||||
?only_fields=company,name&company__exclude_fields=name
|
||||
?exclude_fields=name&company__only_fields=id
|
||||
?company__exclude_fields=name
|
||||
|
||||
Note: the Foreign Key serializer must also inherit from this class
|
||||
"""
|
||||
|
||||
def only_keep_fields(self, fields_to_keep):
|
||||
fields_to_keep = set(fields_to_keep.split(","))
|
||||
all_fields = set(self.fields.keys())
|
||||
for field in all_fields - fields_to_keep:
|
||||
self.fields.pop(field, None)
|
||||
|
||||
def exclude_fields(self, fields_to_exclude):
|
||||
fields_to_exclude = fields_to_exclude.split(",")
|
||||
for field in fields_to_exclude:
|
||||
self.fields.pop(field, None)
|
||||
|
||||
def remove_unwanted_fields(self, dynamic_params):
|
||||
if fields_to_keep := dynamic_params.pop("only_fields", None):
|
||||
self.only_keep_fields(fields_to_keep)
|
||||
|
||||
if fields_to_exclude := dynamic_params.pop("exclude_fields", None):
|
||||
self.exclude_fields(fields_to_exclude)
|
||||
|
||||
def get_or_create_dynamic_params(self, child):
|
||||
if "dynamic_params" not in self.fields[child]._context:
|
||||
self.fields[child]._context.update({"dynamic_params": {}})
|
||||
return self.fields[child]._context["dynamic_params"]
|
||||
|
||||
@staticmethod
|
||||
def split_param(dynamic_param):
|
||||
crumbs = dynamic_param.split("__")
|
||||
return crumbs[0], "__".join(crumbs[1:]) if len(crumbs) > 1 else None
|
||||
|
||||
def set_dynamic_params_for_children(self, dynamic_params):
|
||||
for param, fields in dynamic_params.items():
|
||||
child, child_dynamic_param = self.split_param(param)
|
||||
if child in set(self.fields.keys()):
|
||||
dynamic_params = self.get_or_create_dynamic_params(child)
|
||||
dynamic_params.update({child_dynamic_param: fields})
|
||||
|
||||
@staticmethod
|
||||
def is_param_dynamic(p):
|
||||
return p.endswith("only_fields") or p.endswith("exclude_fields")
|
||||
|
||||
def get_dynamic_params_for_root(self, request):
|
||||
query_params = request.query_params.items()
|
||||
return {k: v for k, v in query_params if self.is_param_dynamic(k)}
|
||||
|
||||
def get_dynamic_params(self):
|
||||
"""
|
||||
When dynamic params get passed down in set_context_for_children
|
||||
If the child is a subclass of ListSerializer (has many=True)
|
||||
The context must be fetched from ListSerializer Class
|
||||
"""
|
||||
if isinstance(self.parent, serializers.ListSerializer):
|
||||
return self.parent._context.get("dynamic_params", {})
|
||||
return self._context.get("dynamic_params", {})
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
request = kwargs.get("context", {}).get("request")
|
||||
super().__init__(*args, **kwargs)
|
||||
is_root = bool(request)
|
||||
|
||||
if is_root:
|
||||
if request.method != "GET":
|
||||
return
|
||||
|
||||
dynamic_params = self.get_dynamic_params_for_root(request)
|
||||
self._context.update({"dynamic_params": dynamic_params})
|
||||
|
||||
def to_representation(self, *args, **kwargs):
|
||||
if dynamic_params := self.get_dynamic_params().copy():
|
||||
self.remove_unwanted_fields(dynamic_params)
|
||||
self.set_dynamic_params_for_children(dynamic_params)
|
||||
|
||||
return super().to_representation(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class DepartmentSerializer(DynamicModelSerializer):
|
||||
class Meta:
|
||||
model = Department
|
||||
fields = [
|
||||
@ -16,7 +115,7 @@ class DepartmentSerializer(serializers.ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class UserSerializer(DynamicModelSerializer):
|
||||
department = DepartmentSerializer()
|
||||
|
||||
class Meta:
|
||||
@ -27,7 +126,7 @@ class UserSerializer(serializers.ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class TicketPrioritySerializer(serializers.ModelSerializer):
|
||||
class TicketPrioritySerializer(DynamicModelSerializer):
|
||||
class Meta:
|
||||
model = TicketPriority
|
||||
fields = [
|
||||
@ -35,7 +134,7 @@ class TicketPrioritySerializer(serializers.ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class TicketTagSerializer(serializers.ModelSerializer):
|
||||
class TicketTagSerializer(DynamicModelSerializer):
|
||||
class Meta:
|
||||
model = TicketTag
|
||||
fields = [
|
||||
@ -43,15 +142,15 @@ class TicketTagSerializer(serializers.ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class TicketSerializer(serializers.ModelSerializer):
|
||||
class TicketSerializer(DynamicModelSerializer):
|
||||
author = UserSerializer()
|
||||
priority = TicketPrioritySerializer()
|
||||
tags = TicketTagSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = [
|
||||
fields = (
|
||||
"uuid", "title", "description", "author", "create_timestamp",
|
||||
"edit_timestamp", "is_edited", "was_yesterday", "is_older_than_day",
|
||||
"timestamp", "priority", "tags",
|
||||
]
|
||||
"timestamp", "priority", "tags", "short_description"
|
||||
)
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
from django_filters import rest_framework as rest_filters
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.utils.decorators import method_decorator
|
||||
|
Loading…
x
Reference in New Issue
Block a user