Skip to content

Commit

Permalink
Merge pull request #75 from MEHRSHAD-MIRSHEKARY/feat/serializer-null-…
Browse files Browse the repository at this point in the history
…fields

Feat/serializer null fields
  • Loading branch information
ARYAN-NIKNEZHAD authored Sep 26, 2024
2 parents 86a1ddc + b886af0 commit 2529eb2
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 71 deletions.
28 changes: 14 additions & 14 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ repos:
files: ^(docs/(.*/)*.*\.rst)
additional_dependencies: [ Sphinx==6.2.1 ]

# - repo: local
# hooks:
- repo: local
hooks:
# - id: pytest
# name: Pytest
# entry: poetry run pytest -v
Expand All @@ -94,15 +94,15 @@ repos:
# pass_filenames: false
# always_run: true

# - id: pylint
# name: pylint
# entry: pylint
# language: system
# types: [ python ]
# require_serial: true
# args:
# - "-rn"
# - "-sn"
# - "--rcfile=pyproject.toml"
# files: ^django_notification/
# exclude: (migrations/|tests/|docs/).*
- id: pylint
name: pylint
entry: pylint
language: system
types: [ python ]
require_serial: true
args:
- "-rn"
- "-sn"
- "--rcfile=pyproject.toml"
files: ^django_notification/
exclude: (migrations/|tests/|docs/).*
9 changes: 7 additions & 2 deletions django_notification/api/serializers/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth.models import Group, Permission
from rest_framework import serializers

from django_notification.settings.conf import config
from django_notification.utils.serialization.field_filters import (
filter_non_empty_fields,
)
Expand Down Expand Up @@ -50,7 +51,7 @@ def get_permissions(self, obj: Group) -> List[Dict]:

def to_representation(self, instance: Group) -> Dict:
"""Customize the representation of the Group instance by filtering out
non-empty fields.
non-empty fields, if the exclude_serializer_null_fields flag is True.
Args:
instance (Group): The group instance being serialized.
Expand All @@ -60,4 +61,8 @@ def to_representation(self, instance: Group) -> Dict:
"""
data = super().to_representation(instance)
return filter_non_empty_fields(data)

if config.exclude_serializer_null_fields:
return filter_non_empty_fields(data)

return data
7 changes: 6 additions & 1 deletion django_notification/api/serializers/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
user_serializer_class,
)
from django_notification.models.notification import Notification
from django_notification.settings.conf import config
from django_notification.utils.serialization.field_filters import (
filter_non_empty_fields,
)
Expand Down Expand Up @@ -83,4 +84,8 @@ def to_representation(self, instance: Notification) -> Dict:
"""
data = super().to_representation(instance)
return filter_non_empty_fields(data)

if config.exclude_serializer_null_fields:
return filter_non_empty_fields(data)

return data
7 changes: 6 additions & 1 deletion django_notification/api/serializers/simple_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rest_framework.serializers import ModelSerializer, SerializerMethodField

from django_notification.models.notification import Notification
from django_notification.settings.conf import config
from django_notification.utils.serialization import (
filter_non_empty_fields,
generate_title,
Expand Down Expand Up @@ -69,4 +70,8 @@ def to_representation(self, instance: Dict[str, Any]) -> Dict[str, str]:
"""
data = super().to_representation(instance)
return filter_non_empty_fields(data)

if config.exclude_serializer_null_fields:
return filter_non_empty_fields(data)

return data
6 changes: 4 additions & 2 deletions django_notification/constants/default_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class DefaultSerializerSettings:


@dataclass(frozen=True)
class DefaultAdminPermSettings:
class DefaultAdminSettings:
admin_site_class: Optional[str] = None
admin_has_add_permission: bool = False
admin_has_change_permission: bool = False
admin_has_delete_permission: bool = False
Expand All @@ -30,7 +31,7 @@ class DefaultThrottleSettings:
@dataclass(frozen=True)
class DefaultPaginationAndFilteringSettings:
pagination_class: str = "django_notification.api.paginations.limit_offset_pagination.DefaultLimitOffSetPagination"
filterset_class: str = None
filterset_class: Optional[str] = None
ordering_fields: List[str] = field(
default_factory=lambda: ["id", "timestamp", "public"]
)
Expand All @@ -44,6 +45,7 @@ class DefaultAPISettings:
allow_list: bool = True
allow_retrieve: bool = True
include_serializer_full_details: bool = False
exclude_serializer_none_fields: bool = False
extra_permission_class: Optional[str] = None
parser_classes: List[str] = field(
default_factory=lambda: [
Expand Down
66 changes: 39 additions & 27 deletions django_notification/settings/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,119 +38,131 @@ def check_notification_settings(app_configs: Any, **kwargs: Any) -> List[Error]:
# Validate boolean settings
errors.extend(
validate_boolean_setting(
config.include_soft_delete, "DJANGO_NOTIFICATION_API_INCLUDE_SOFT_DELETE"
config.include_soft_delete, f"{config.prefix}API_INCLUDE_SOFT_DELETE"
)
)
errors.extend(
validate_boolean_setting(
config.include_hard_delete, "DJANGO_NOTIFICATION_API_INCLUDE_HARD_DELETE"
config.include_hard_delete, f"{config.prefix}API_INCLUDE_HARD_DELETE"
)
)
errors.extend(
validate_boolean_setting(
config.admin_has_add_permission,
"DJANGO_NOTIFICATION_ADMIN_HAS_ADD_PERMISSION",
f"{config.prefix}ADMIN_HAS_ADD_PERMISSION",
)
)
errors.extend(
validate_boolean_setting(
config.admin_has_change_permission,
"DJANGO_NOTIFICATION_ADMIN_HAS_CHANGE_PERMISSION",
f"{config.prefix}ADMIN_HAS_CHANGE_PERMISSION",
)
)
errors.extend(
validate_boolean_setting(
config.admin_has_delete_permission,
"DJANGO_NOTIFICATION_ADMIN_HAS_DELETE_PERMISSION",
f"{config.prefix}ADMIN_HAS_DELETE_PERMISSION",
)
)
errors.extend(
validate_boolean_setting(
config.include_serializer_full_details,
"DJANGO_NOTIFICATION_SERIALIZER_INCLUDE_FULL_DETAILS",
f"{config.prefix}SERIALIZER_INCLUDE_FULL_DETAILS",
)
)
errors.extend(
validate_boolean_setting(
config.api_allow_list, "DJANGO_NOTIFICATION_API_ALLOW_LIST"
config.exclude_serializer_null_fields,
f"{config.prefix}SERIALIZER_EXCLUDE_NULL_FIELDS",
)
)
errors.extend(
validate_boolean_setting(
config.api_allow_retrieve, "DJANGO_NOTIFICATION_API_ALLOW_RETRIEVE"
config.api_allow_list, f"{config.prefix}API_ALLOW_LIST"
)
)
errors.extend(
validate_boolean_setting(
config.api_allow_retrieve, f"{config.prefix}API_ALLOW_RETRIEVE"
)
)

errors.extend(
validate_list_fields(
config.user_serializer_fields, "DJANGO_NOTIFICATION_USER_SERIALIZER_FIELDS"
config.user_serializer_fields, f"{config.prefix}USER_SERIALIZER_FIELDS"
)
)

errors.extend(
validate_list_fields(
config.api_ordering_fields, "DJANGO_NOTIFICATION_API_ORDERING_FIELDS"
config.api_ordering_fields, f"{config.prefix}API_ORDERING_FIELDS"
)
)

errors.extend(
validate_list_fields(
config.api_search_fields, "DJANGO_NOTIFICATION_API_SEARCH_FIELDS"
config.api_search_fields, f"{config.prefix}API_SEARCH_FIELDS"
)
)

errors.extend(
validate_throttle_rate(
config.staff_user_throttle_rate,
"DJANGO_NOTIFICATION_STAFF_USER_THROTTLE_RATE",
f"{config.prefix}STAFF_USER_THROTTLE_RATE",
)
)
errors.extend(
validate_throttle_rate(
config.authenticated_user_throttle_rate,
"DJANGO_NOTIFICATION_AUTHENTICATED_USER_THROTTLE_RATE",
f"{config.prefix}AUTHENTICATED_USER_THROTTLE_RATE",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_USER_SERIALIZER_CLASS", None),
"DJANGO_NOTIFICATION_USER_SERIALIZER_CLASS",
config.get_setting(f"{config.prefix}USER_SERIALIZER_CLASS", None),
f"{config.prefix}USER_SERIALIZER_CLASS",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_GROUP_SERIALIZER_CLASS", None),
"DJANGO_NOTIFICATION_GROUP_SERIALIZER_CLASS",
config.get_setting(f"{config.prefix}GROUP_SERIALIZER_CLASS", None),
f"{config.prefix}GROUP_SERIALIZER_CLASS",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_API_THROTTLE_CLASS", None),
"DJANGO_NOTIFICATION_API_THROTTLE_CLASS",
config.get_setting(f"{config.prefix}API_THROTTLE_CLASS", None),
f"{config.prefix}API_THROTTLE_CLASS",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_API_PAGINATION_CLASS", None),
"DJANGO_NOTIFICATION_API_PAGINATION_CLASS",
config.get_setting(f"{config.prefix}API_PAGINATION_CLASS", None),
f"{config.prefix}API_PAGINATION_CLASS",
)
)
errors.extend(
validate_optional_classes_setting(
config.get_setting("DJANGO_NOTIFICATION_API_PARSER_CLASSES", []),
"DJANGO_NOTIFICATION_API_PARSER_CLASSES",
config.get_setting(f"{config.prefix}API_PARSER_CLASSES", []),
f"{config.prefix}API_PARSER_CLASSES",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting(f"{config.prefix}API_FILTERSET_CLASS", None),
f"{config.prefix}API_FILTERSET_CLASS",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_API_FILTERSET_CLASS", None),
"DJANGO_NOTIFICATION_API_FILTERSET_CLASS",
config.get_setting(f"{config.prefix}API_EXTRA_PERMISSION_CLASS", None),
f"{config.prefix}API_EXTRA_PERMISSION_CLASS",
)
)
errors.extend(
validate_optional_class_setting(
config.get_setting("DJANGO_NOTIFICATION_API_EXTRA_PERMISSION_CLASS", None),
"DJANGO_NOTIFICATION_API_EXTRA_PERMISSION_CLASS",
config.get_setting(f"{config.prefix}ADMIN_SITE_CLASS", None),
f"{config.prefix}ADMIN_SITE_CLASS",
)
)

Expand Down
4 changes: 4 additions & 0 deletions django_notification/settings/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ def __init__(self) -> None:
f"{self.prefix}SERIALIZER_INCLUDE_FULL_DETAILS",
self.default_api_settings.include_serializer_full_details,
)
self.exclude_serializer_null_fields: bool = self.get_setting(
f"{self.prefix}SERIALIZER_EXCLUDE_NULL_FIELDS",
self.default_api_settings.exclude_serializer_none_fields,
)

self.api_allow_list: bool = self.get_setting(
f"{self.prefix}API_ALLOW_LIST", self.default_api_settings.allow_list
Expand Down
3 changes: 3 additions & 0 deletions django_notification/tests/api/serializers/test_group.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import sys
from unittest.mock import patch

import pytest
from django.contrib.auth.models import Group
from rest_framework.exceptions import ValidationError
from django_notification.api.serializers.group import GroupSerializer
from django_notification.settings.conf import config
from django_notification.utils.serialization.field_filters import (
filter_non_empty_fields,
)
Expand All @@ -23,6 +25,7 @@ class TestGroupSerializer:
Test the GroupSerializer and PermissionSerializer functionality.
"""

@patch.object(config, "exclude_serializer_null_fields", False)
def test_group_serializer_with_valid_data(self, group_with_perm: Group) -> None:
"""
Test that the GroupSerializer correctly serializes a group with permissions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import sys
from typing import Dict, Any
from unittest.mock import patch

import pytest

from django_notification.api.serializers.simple_notification import (
SimpleNotificationSerializer,
)
from django_notification.settings.conf import config
from django_notification.utils.serialization.field_filters import (
filter_non_empty_fields,
)
Expand Down Expand Up @@ -52,6 +54,7 @@ def test_serializer_fields(self, notification_dict: Dict[str, Any]) -> None:
serializer = SimpleNotificationSerializer(notification_dict)
assert set(serializer.data.keys()) == set(expected_fields)

@patch.object(config, "exclude_serializer_null_fields", False)
@mark.django_db
def test_title_generation(self, notification_dict: Dict[str, Any]) -> None:
"""
Expand Down
1 change: 1 addition & 0 deletions django_notification/tests/api/views/test_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def setup_method(self) -> None:
"""
self.client = APIClient()

@patch.object(config, "exclude_serializer_null_fields", False)
def test_get_queryset_for_staff(
self, admin_user: Type[User], notification: Notification
) -> None:
Expand Down
4 changes: 2 additions & 2 deletions django_notification/tests/constants.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
PYTHON_VERSION = (3, 8)
PYTHON_VERSION_REASON = "Requires Python 3.8 or higher"
PYTHON_VERSION = (3, 9)
PYTHON_VERSION_REASON = "Requires Python 3.9 or higher"
Loading

0 comments on commit 2529eb2

Please sign in to comment.