From 628e280102173f962a0db88726f8d29dbba9c262 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 11:00:06 +0800 Subject: [PATCH 1/7] Invalidate cache for equipments on transaction update --- equipment_tracker/transactions/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/equipment_tracker/transactions/models.py b/equipment_tracker/transactions/models.py index dd968de..65f735c 100644 --- a/equipment_tracker/transactions/models.py +++ b/equipment_tracker/transactions/models.py @@ -43,5 +43,7 @@ class Transaction(models.Model): return f"Transaction #{self.id} under {self.teacher} by {self.borrower}" def save(self, *args, **kwargs): + cache.delete('available_equipment_instances') + cache.delete('equipment_instances') cache.delete('non_finalized_transactions') return super().save(*args, **kwargs) From 10f3ece9b73e56b314fcceef4892d9ee70eaca15 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 11:02:16 +0800 Subject: [PATCH 2/7] Improve caching --- equipment_tracker/transactions/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/equipment_tracker/transactions/views.py b/equipment_tracker/transactions/views.py index 47514ed..50e5219 100644 --- a/equipment_tracker/transactions/views.py +++ b/equipment_tracker/transactions/views.py @@ -3,6 +3,7 @@ from accounts.permissions import IsTeacher, IsStudent from rest_framework import viewsets, generics from .serializers import TransactionSerializer from .models import Transaction +from django.core.cache import cache class TransactionViewSet(viewsets.ModelViewSet): From f418bc017dfa79e227101ea7a3a00101bdec134d Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 11:07:48 +0800 Subject: [PATCH 3/7] Improve caching --- equipment_tracker/schema.yml | 23 ++----------------- equipment_tracker/transactions/serializers.py | 4 ++++ 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/equipment_tracker/schema.yml b/equipment_tracker/schema.yml index 3dbb1ad..190c3e3 100644 --- a/equipment_tracker/schema.yml +++ b/equipment_tracker/schema.yml @@ -603,7 +603,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -631,7 +630,6 @@ paths: required: true security: - jwtAuth: [] - - {} responses: '201': content: @@ -652,7 +650,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -676,7 +673,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -709,7 +705,6 @@ paths: required: true security: - jwtAuth: [] - - {} responses: '200': content: @@ -741,7 +736,6 @@ paths: $ref: '#/components/schemas/PatchedEquipmentInstance' security: - jwtAuth: [] - - {} responses: '200': content: @@ -762,7 +756,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '204': description: No response body @@ -773,7 +766,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -790,7 +782,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -807,7 +798,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -824,7 +814,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -852,7 +841,6 @@ paths: required: true security: - jwtAuth: [] - - {} responses: '201': content: @@ -873,7 +861,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -897,7 +884,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -930,7 +916,6 @@ paths: required: true security: - jwtAuth: [] - - {} responses: '200': content: @@ -962,7 +947,6 @@ paths: $ref: '#/components/schemas/PatchedEquipment' security: - jwtAuth: [] - - {} responses: '200': content: @@ -983,7 +967,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '204': description: No response body @@ -994,7 +977,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -1011,7 +993,6 @@ paths: - api security: - jwtAuth: [] - - {} responses: '200': content: @@ -1296,7 +1277,7 @@ components: $ref: '#/components/schemas/StatusEnum' remarks: type: string - maxLength: 512 + nullable: true last_updated: type: string format: date-time @@ -1551,7 +1532,7 @@ components: $ref: '#/components/schemas/StatusEnum' remarks: type: string - maxLength: 512 + nullable: true last_updated: type: string format: date-time diff --git a/equipment_tracker/transactions/serializers.py b/equipment_tracker/transactions/serializers.py index eaad849..4eb567f 100644 --- a/equipment_tracker/transactions/serializers.py +++ b/equipment_tracker/transactions/serializers.py @@ -5,6 +5,7 @@ from .models import Transaction from breakages.models import BreakageReport from accounts.models import CustomUser from config.settings import DEBUG +from django.core.cache import cache class CustomUserSerializer(serializers.ModelSerializer): @@ -128,6 +129,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): return transaction def update(self, instance, validated_data): + cache.delete('non_finalized_transactions') user = self.context['request'].user # User Validation @@ -248,6 +250,8 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + cache.delete('available_equipment_instances') + cache.delete('equipment_instances') return super().update(instance, validated_data) # If the transaction changes from Returned: Pending Checking to With Breakages, we create a Breakage Report instance From c61f978c753712a50f1a2e1fd1da7973180ef817 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 11:11:13 +0800 Subject: [PATCH 4/7] Improve caching --- equipment_tracker/transactions/serializers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/equipment_tracker/transactions/serializers.py b/equipment_tracker/transactions/serializers.py index 4eb567f..7d6256f 100644 --- a/equipment_tracker/transactions/serializers.py +++ b/equipment_tracker/transactions/serializers.py @@ -191,6 +191,8 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + cache.delete('available_equipment_instances') + cache.delete('equipment_instances') return super().update(instance, validated_data) # For Approved transactions, @@ -208,6 +210,8 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + cache.delete('available_equipment_instances') + cache.delete('equipment_instances') return super().update(instance, validated_data) # If there are no issues and a transaction changes from Approved to Borrowed, label the selected equipment's statuses as Borrowed From 8e43e06ec21c652c90298f555681f0b8e39af283 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 11:54:38 +0800 Subject: [PATCH 5/7] Order by id available equipments --- equipment_tracker/equipments/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/equipment_tracker/equipments/views.py b/equipment_tracker/equipments/views.py index d1a03a7..e9f20d9 100644 --- a/equipment_tracker/equipments/views.py +++ b/equipment_tracker/equipments/views.py @@ -103,7 +103,8 @@ class AvailableEquipmentInstanceViewSet(generics.ListAPIView): # Get all equipment instances which are not associated with non-finalized transactions queryset = EquipmentInstance.objects.exclude( - id__in=non_finalized_equipments.values_list('id', flat=True) + id__in=non_finalized_equipments.values_list( + 'id', flat=True).order_by('id') ) cache.set(key, queryset, timeout=60*60*24) From e482979d20d4daa5b17d141fbd3540a1134a31fa Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 12:21:14 +0800 Subject: [PATCH 6/7] Improve query caching --- equipment_tracker/config/settings.py | 2 +- equipment_tracker/equipments/views.py | 4 ++-- equipment_tracker/schema.yml | 19 +++++++++++++++++++ equipment_tracker/transactions/serializers.py | 9 ++++++--- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/equipment_tracker/config/settings.py b/equipment_tracker/config/settings.py index c53cc0c..0e55c22 100644 --- a/equipment_tracker/config/settings.py +++ b/equipment_tracker/config/settings.py @@ -28,7 +28,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = str(os.getenv('SECRET_KEY')) # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = True ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '*'] CSRF_TRUSTED_ORIGINS = [ diff --git a/equipment_tracker/equipments/views.py b/equipment_tracker/equipments/views.py index e9f20d9..aaf559c 100644 --- a/equipment_tracker/equipments/views.py +++ b/equipment_tracker/equipments/views.py @@ -99,12 +99,12 @@ class AvailableEquipmentInstanceViewSet(generics.ListAPIView): # Get all equipment instances associated with non-finalized transactions non_finalized_equipments = EquipmentInstance.objects.filter( transaction__in=non_finalized_transactions - ).prefetch_related('equipment') + ).order_by('id').prefetch_related('equipment') # Get all equipment instances which are not associated with non-finalized transactions queryset = EquipmentInstance.objects.exclude( id__in=non_finalized_equipments.values_list( - 'id', flat=True).order_by('id') + 'id', flat=True) ) cache.set(key, queryset, timeout=60*60*24) diff --git a/equipment_tracker/schema.yml b/equipment_tracker/schema.yml index 190c3e3..96e99a3 100644 --- a/equipment_tracker/schema.yml +++ b/equipment_tracker/schema.yml @@ -603,6 +603,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -630,6 +631,7 @@ paths: required: true security: - jwtAuth: [] + - {} responses: '201': content: @@ -650,6 +652,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -673,6 +676,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -705,6 +709,7 @@ paths: required: true security: - jwtAuth: [] + - {} responses: '200': content: @@ -736,6 +741,7 @@ paths: $ref: '#/components/schemas/PatchedEquipmentInstance' security: - jwtAuth: [] + - {} responses: '200': content: @@ -756,6 +762,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '204': description: No response body @@ -766,6 +773,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -782,6 +790,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -798,6 +807,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -814,6 +824,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -841,6 +852,7 @@ paths: required: true security: - jwtAuth: [] + - {} responses: '201': content: @@ -861,6 +873,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -884,6 +897,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -916,6 +930,7 @@ paths: required: true security: - jwtAuth: [] + - {} responses: '200': content: @@ -947,6 +962,7 @@ paths: $ref: '#/components/schemas/PatchedEquipment' security: - jwtAuth: [] + - {} responses: '200': content: @@ -967,6 +983,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '204': description: No response body @@ -977,6 +994,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: @@ -993,6 +1011,7 @@ paths: - api security: - jwtAuth: [] + - {} responses: '200': content: diff --git a/equipment_tracker/transactions/serializers.py b/equipment_tracker/transactions/serializers.py index 7d6256f..ee57a97 100644 --- a/equipment_tracker/transactions/serializers.py +++ b/equipment_tracker/transactions/serializers.py @@ -191,9 +191,10 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + q = super().update(instance, validated_data) cache.delete('available_equipment_instances') cache.delete('equipment_instances') - return super().update(instance, validated_data) + return q # For Approved transactions, # If not changing to Borrowed or Cancelled, throw an error @@ -210,9 +211,10 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + q = super().update(instance, validated_data) cache.delete('available_equipment_instances') cache.delete('equipment_instances') - return super().update(instance, validated_data) + return q # If there are no issues and a transaction changes from Approved to Borrowed, label the selected equipment's statuses as Borrowed if instance.transaction_status == "Approved" and validated_data.get('transaction_status') == "Borrowed": @@ -254,9 +256,10 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer): # This updates the status field of all equipment instances in a single query EquipmentInstance.objects.filter( id__in=[equipment.id for equipment in equipments]).update(status='Available') + q = super().update(instance, validated_data) cache.delete('available_equipment_instances') cache.delete('equipment_instances') - return super().update(instance, validated_data) + return q # If the transaction changes from Returned: Pending Checking to With Breakages, we create a Breakage Report instance if instance.transaction_status == "Returned: Pending Checking" and validated_data.get('transaction_status') == "With Breakages: Pending Resolution": From d0fd42448cdcf090811a01b63c45bb987154a94c Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 7 Jan 2024 12:21:31 +0800 Subject: [PATCH 7/7] Turn off debug flag --- equipment_tracker/config/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/equipment_tracker/config/settings.py b/equipment_tracker/config/settings.py index 0e55c22..c53cc0c 100644 --- a/equipment_tracker/config/settings.py +++ b/equipment_tracker/config/settings.py @@ -28,7 +28,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = str(os.getenv('SECRET_KEY')) # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '*'] CSRF_TRUSTED_ORIGINS = [