Skip to content

Commit

Permalink
Merge pull request #229 from antaliadom-team/feature/db_optimization
Browse files Browse the repository at this point in the history
optimize db request in the /api/objects endpoint
  • Loading branch information
spaut33 committed May 19, 2023
2 parents 39b4f21 + 856ddb7 commit 23e090e
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 2 deletions.
4 changes: 4 additions & 0 deletions antalia_project/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@

# Список размеров в пикселях создаваемых превью для фотографий объекта [(hor, vert), ...]
PREVIEW_SIZES = ((738, 632), (328, 261))

# Caching
CACHE_TIMEOUT = 3600
CACHE_TIMEOUT_REAL_ESTATE = 60
10 changes: 9 additions & 1 deletion antalia_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
os.environ.get('SESSION_COOKIE_SECURE', default=False) == 'True'
)
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] = [ # noqa: F405
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.JSONRenderer'
]

X_FRAME_OPTIONS = 'DENY'
Expand Down Expand Up @@ -165,3 +165,11 @@
CELERY_RESULT_BACKEND = os.getenv(
'CELERY_RESULT_BACKEND', default='redis://localhost:6379/0'
)

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': CELERY_BROKER_URL, # Redis server location
'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient'},
}
}
7 changes: 7 additions & 0 deletions api/views/about_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from django.conf import settings
from django.core.exceptions import ValidationError
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from rest_framework import status, viewsets
from rest_framework.response import Response

Expand All @@ -19,12 +22,14 @@ class StaticPageViewSet(viewsets.ReadOnlyModelViewSet):
list_serializer_class = StaticPageListSerializer
authentication_classes = []

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
"""Список статических страниц."""
queryset = self.filter_queryset(self.get_queryset())
serializer = self.list_serializer_class(queryset, many=True)
return Response(serializer.data)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
"""Получение статической страницы."""
try:
Expand All @@ -44,12 +49,14 @@ class TeamViewSet(viewsets.ReadOnlyModelViewSet):
authentication_classes = []
queryset = Team.objects.filter(is_active=True)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
"""Список команды."""
queryset = self.filter_queryset(self.get_queryset())
serializer = TeamSerializer(queryset, many=True)
return Response(serializer.data)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
"""Получение члена команды."""
try:
Expand Down
43 changes: 43 additions & 0 deletions api/views/catalog_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from urllib.parse import urlparse

from django.conf import settings
from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import permissions, status, viewsets
from rest_framework.decorators import action, api_view, permission_classes
Expand Down Expand Up @@ -98,6 +101,14 @@ class LocationViewSet(viewsets.ModelViewSet):
search_fields = ('name', 'slug')
ordering = ('name',)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)


class CategoryViewSet(viewsets.ModelViewSet):
"""Категория"""
Expand All @@ -108,6 +119,14 @@ class CategoryViewSet(viewsets.ModelViewSet):
authentication_classes = []
lookup_field = 'id'

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)


class PropertyTypeViewSet(viewsets.ModelViewSet):
"""Тип недвижимости"""
Expand All @@ -118,6 +137,14 @@ class PropertyTypeViewSet(viewsets.ModelViewSet):
authentication_classes = []
lookup_field = 'id'

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)


class FacilityViewSet(viewsets.ModelViewSet):
"""Удобства"""
Expand All @@ -128,6 +155,14 @@ class FacilityViewSet(viewsets.ModelViewSet):
authentication_classes = []
lookup_field = 'id'

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

@method_decorator(cache_page(settings.CACHE_TIMEOUT))
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)


class RealEstateViewSet(viewsets.ModelViewSet, FavoriteMixin):
"""Каталог недвижимости"""
Expand All @@ -145,6 +180,14 @@ class RealEstateViewSet(viewsets.ModelViewSet, FavoriteMixin):
filter_backends = (DjangoFilterBackend,)
filterset_class = RealEstateFilter

@method_decorator(cache_page(settings.CACHE_TIMEOUT_REAL_ESTATE))
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

@method_decorator(cache_page(settings.CACHE_TIMEOUT_REAL_ESTATE))
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)

@action(
methods=('post', 'delete'),
detail=True,
Expand Down
14 changes: 14 additions & 0 deletions tests/fixtures/fixture_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,17 @@
@pytest.fixture(autouse=True)
def email_backend_setup(settings):
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'


@pytest.fixture(autouse=True)
def no_cache_setup(settings):
settings.CACHES = {
'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}
}


@pytest.fixture
def locmem_cache(settings):
settings.CACHES = {
'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}
}
21 changes: 20 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from django.conf import settings
from django.core import mail

import pytest

class TestTasksUtils:
from tests.common import APITestBase


class TestTasksUtils(APITestBase):
"""Тесты для celery tasks and core.utils"""

def test_send_common_order_emails_anon(self, admin, object1):
Expand Down Expand Up @@ -69,3 +74,17 @@ def test_send_reale_state_order_emails_user_anon(self, admin, object1):
assert len(mail.outbox) == 2
assert mail.outbox[0].subject == 'Подтверждение заявки.'
assert mail.outbox[1].subject == 'Поступила новая заявка.'

@pytest.mark.django_db
def test_cached_data(self, client, locmem_cache):
response1 = client.get(self.urls['location_list'])
assert response1.status_code == 200
# Make the second request to the same endpoint
response2 = client.get(self.urls['location_list'])
assert response2.status_code == 200
# Assert that the second response was served from the cache
assert (
response2.headers['cache-control']
== f'max-age={settings.CACHE_TIMEOUT}'
)
assert response1.content == response2.content

0 comments on commit 23e090e

Please sign in to comment.