Skip to content

Commit 68407e2

Browse files
committed
refactor(coupons): update views, fix cache issue
1 parent d38c41d commit 68407e2

File tree

7 files changed

+183
-63
lines changed

7 files changed

+183
-63
lines changed

apps/coupons/managers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
class FixedCouponManager(models.Manager):
77
"""Manager for FixedCoupon model."""
88

9-
def get_queryset(self):
10-
return super().get_queryset().filter(is_active=True, available=True)
9+
def get_all(self):
10+
"""Return default queryset."""
11+
return self.filter(available=True, is_active=True)
1112

1213

1314
class PercentageCouponManager(models.Manager):
1415
"""Manager for PercentageCoupon model."""
1516

16-
def get_queryset(self):
17-
return super().get_queryset().filter(is_active=True, available=True)
17+
def get_all(self):
18+
"""Return default queryset."""
19+
return self.filter(available=True, is_active=True)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.0.4 on 2024-04-22 16:34
2+
3+
import datetime
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('coupons', '0004_alter_fixedcoupon_discount_price_and_more'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='fixedcoupon',
16+
name='end_date',
17+
field=models.DateField(default=datetime.datetime(2024, 5, 22, 16, 34, 16, 788467, tzinfo=datetime.timezone.utc)),
18+
),
19+
migrations.AlterField(
20+
model_name='percentagecoupon',
21+
name='end_date',
22+
field=models.DateField(default=datetime.datetime(2024, 5, 22, 16, 34, 16, 789227, tzinfo=datetime.timezone.utc)),
23+
),
24+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.0.4 on 2024-04-22 17:54
2+
3+
import datetime
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('coupons', '0005_alter_fixedcoupon_end_date_and_more'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='fixedcoupon',
16+
name='end_date',
17+
field=models.DateField(default=datetime.datetime(2024, 5, 22, 17, 54, 21, 904424, tzinfo=datetime.timezone.utc)),
18+
),
19+
migrations.AlterField(
20+
model_name='percentagecoupon',
21+
name='end_date',
22+
field=models.DateField(default=datetime.datetime(2024, 5, 22, 17, 54, 21, 905234, tzinfo=datetime.timezone.utc)),
23+
),
24+
]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 5.0.4 on 2024-04-22 17:56
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('coupons', '0006_alter_fixedcoupon_end_date_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='fixedcoupon',
15+
options={'ordering': ['pk'], 'verbose_name': 'fixed coupon', 'verbose_name_plural': 'fixed coupons'},
16+
),
17+
migrations.AlterModelOptions(
18+
name='percentagecoupon',
19+
options={'ordering': ['pk'], 'verbose_name': 'percentage coupon', 'verbose_name_plural': 'percentage coupons'},
20+
),
21+
migrations.AlterField(
22+
model_name='fixedcoupon',
23+
name='end_date',
24+
field=models.DateField(),
25+
),
26+
migrations.AlterField(
27+
model_name='fixedcoupon',
28+
name='start_date',
29+
field=models.DateField(),
30+
),
31+
migrations.AlterField(
32+
model_name='percentagecoupon',
33+
name='end_date',
34+
field=models.DateField(),
35+
),
36+
migrations.AlterField(
37+
model_name='percentagecoupon',
38+
name='start_date',
39+
field=models.DateField(),
40+
),
41+
]

apps/coupons/models.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
"""Models for Coupons App."""
22

3-
from datetime import timedelta
43
from django.db import models
54
from django.core.validators import MinValueValidator, MaxValueValidator
6-
from django.utils import timezone
75

86
from apps.utilities.models import BaseModel
97
from .managers import FixedCouponManager, PercentageCouponManager
@@ -16,15 +14,16 @@ class FixedCoupon(BaseModel):
1614
code = models.CharField(max_length=36, unique=True, blank=True)
1715
discount_price = models.DecimalField(
1816
max_digits=7, decimal_places=2, validators=[validate_discount_price])
19-
start_date = models.DateField(default=timezone.now)
20-
end_date = models.DateField(default=timezone.now() + timedelta(days=30))
17+
start_date = models.DateField()
18+
end_date = models.DateField()
2119
quantity = models.PositiveIntegerField(default=50)
2220
is_active = models.BooleanField(default=True)
2321

2422
objects = FixedCouponManager()
2523

2624
class Meta:
2725
"""Meta definition for FixedCoupon."""
26+
ordering = ["pk"]
2827
verbose_name = "fixed coupon"
2928
verbose_name_plural = "fixed coupons"
3029

@@ -44,15 +43,16 @@ class PercentageCoupon(BaseModel):
4443
code = models.CharField(max_length=36, unique=True, blank=True)
4544
discount_percentage = models.IntegerField(
4645
validators=[MinValueValidator(5), MaxValueValidator(25)])
47-
start_date = models.DateField(default=timezone.now)
48-
end_date = models.DateField(default=timezone.now() + timedelta(days=30))
46+
start_date = models.DateField()
47+
end_date = models.DateField()
4948
quantity = models.PositiveIntegerField(default=50)
5049
is_active = models.BooleanField(default=True)
5150

5251
objects = PercentageCouponManager()
5352

5453
class Meta:
5554
"""Meta definition for PercentageCoupon."""
55+
ordering = ["pk"]
5656
verbose_name = "percentage coupon"
5757
verbose_name_plural = "percentage coupons"
5858

apps/coupons/views.py

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,47 @@ class FixedCouponListAPIView(APIView):
1919
"""APIView for listing and creating fixed coupons."""
2020
permission_classes = [IsAuthenticated]
2121
serializer_class = FixedCouponSerializer
22-
pagination_class = MediumSetPagination
23-
CACHE_TIMEOUT = 7200 # Cache for 2 hours
22+
cache_key = "fixed_coupon"
23+
cache_timeout = 7200
2424

2525
def get(self, request, format=None):
2626
# Get a list of available fixed coupons
27-
cache_key = f"fixed_coupon_{request.user.id}"
28-
cached_data = cache.get(cache_key)
27+
paginator = MediumSetPagination()
28+
cached_data = cache.get(self.cache_key)
2929

3030
if cached_data is None:
31-
coupons = FixedCoupon.objects.filter(available=True).order_by("id")
32-
if coupons.exists():
33-
serializer = self.serializer_class(coupons, many=True)
34-
# Set cache
35-
cache.set(cache_key, serializer.data, self.CACHE_TIMEOUT)
36-
return Response(serializer.data, status=status.HTTP_200_OK)
37-
return Response(
38-
{"detail": "No fixed coupons available."},
39-
status=status.HTTP_404_NOT_FOUND
40-
)
41-
return Response(cached_data, status=status.HTTP_200_OK)
31+
coupons = FixedCoupon.objects.get_all()
32+
if not coupons.exists():
33+
return Response(
34+
{"detail": "No fixed coupons available."},
35+
status=status.HTTP_404_NOT_FOUND
36+
)
37+
# Fetches the data from the database and serializes it
38+
paginated_data = paginator.paginate_queryset(coupons, request)
39+
serializer = self.serializer_class(paginated_data, many=True)
40+
# Set cache
41+
cache.set(self.cache_key, serializer.data, self.cache_timeout)
42+
else:
43+
# Retrieve the cached data and serialize it
44+
paginated_cached_data = paginator.paginate_queryset(
45+
cached_data, request)
46+
serializer = self.serializer_class(
47+
paginated_cached_data, many=True)
48+
49+
return paginator.get_paginated_response(serializer.data)
4250

4351
@transaction.atomic
4452
def post(self, request, format=None):
4553
# Create a new fixed coupon
4654
serializer = self.serializer_class(data=request.data)
55+
4756
if serializer.is_valid():
4857
serializer.save()
4958
# Invalidate cache
50-
cache_key = f"fixed_coupon_{request.user.id}"
51-
cache.delete(cache_key)
52-
return Response(
53-
serializer.data,
54-
status=status.HTTP_201_CREATED
55-
)
59+
cache.delete(self.cache_key)
60+
return Response(serializer.data, status=status.HTTP_201_CREATED)
5661
return Response(
57-
serializer.errors,
58-
status=status.HTTP_400_BAD_REQUEST
59-
)
62+
serializer.errors, status=status.HTTP_400_BAD_REQUEST)
6063

6164

6265
class FixedCouponDetailAPIView(APIView):
@@ -91,35 +94,43 @@ def put(self, request, fixed_coupon_id):
9194
def delete(self, request, fixed_coupon_id):
9295
# Delete a fixed coupon
9396
fixed_coupon = self.get_object(fixed_coupon_id)
94-
fixed_coupon.delete()
97+
fixed_coupon.available = False # Logical deletion
98+
fixed_coupon.save()
9599
return Response(status=status.HTTP_204_NO_CONTENT)
96100

97101

98102
class PercentageCouponListAPIView(APIView):
99103
"""APIView for listing and creating percentage coupons."""
100104
permission_classes = [IsAuthenticated]
101105
serializer_class = PercentageCouponSerializer
102-
pagination_class = MediumSetPagination
103-
CACHE_TIMEOUT = 7200 # Cache for 2 hours
106+
cache_key = "percentage_coupon"
107+
cache_timeout = 7200
104108

105109
def get(self, request, format=None):
106110
# Get a list of available percentage coupons
107-
cache_key = f"percentage_coupon_{request.user.id}"
108-
cached_data = cache.get(cache_key)
111+
paginator = MediumSetPagination()
112+
cached_data = cache.get(self.cache_key)
109113

110114
if cached_data is None:
111-
coupons = PercentageCoupon.objects.filter(
112-
available=True).order_by("id")
113-
if coupons.exists():
114-
serializer = self.serializer_class(coupons, many=True)
115-
# Set cache
116-
cache.set(cache_key, serializer.data, self.CACHE_TIMEOUT)
117-
return Response(serializer.data, status=status.HTTP_200_OK)
118-
return Response(
119-
{"detail": "No percentage coupons available."},
120-
status=status.HTTP_404_NOT_FOUND
121-
)
122-
return Response(cached_data, status=status.HTTP_200_OK)
115+
coupons = PercentageCoupon.objects.get_all()
116+
if not coupons.exists():
117+
return Response(
118+
{"detail": "No percentage coupons available."},
119+
status=status.HTTP_404_NOT_FOUND
120+
)
121+
122+
paginated_data = paginator.paginate_queryset(coupons, request)
123+
serializer = self.serializer_class(paginated_data, many=True)
124+
# Set cache
125+
cache.set(self.cache_key, serializer.data, self.cache_timeout)
126+
else:
127+
# Retrieve the cached data and serialize it
128+
paginated_cached_data = paginator.paginate_queryset(
129+
cached_data, request)
130+
serializer = self.serializer_class(
131+
paginated_cached_data, many=True)
132+
133+
return paginator.get_paginated_response(serializer.data)
123134

124135
@transaction.atomic
125136
def post(self, request, format=None):
@@ -128,16 +139,9 @@ def post(self, request, format=None):
128139
if serializer.is_valid():
129140
serializer.save()
130141
# Invalidate cache
131-
cache_key = f"percentage_coupon_{request.user.id}"
132-
cache.delete(cache_key)
133-
return Response(
134-
serializer.data,
135-
status=status.HTTP_201_CREATED
136-
)
137-
return Response(
138-
serializer.errors,
139-
status=status.HTTP_400_BAD_REQUEST
140-
)
142+
cache.delete(self.cache_key)
143+
return Response(serializer.data, status=status.HTTP_201_CREATED)
144+
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
141145

142146

143147
class PercentageCouponDetailAPIView(APIView):
@@ -174,7 +178,8 @@ def put(self, request, percentage_coupon_id):
174178
def delete(self, request, percentage_coupon_id):
175179
# Delete a percentage coupon
176180
percentage_coupon = self.get_object(percentage_coupon_id)
177-
percentage_coupon.delete()
181+
percentage_coupon.available = False # Logical deletion
182+
percentage_coupon.save()
178183
return Response(status=status.HTTP_204_NO_CONTENT)
179184

180185

apps/locations/serializers.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,21 @@ class Meta:
2121
]
2222

2323

24+
class RegionListSerializer(ModelSerializer):
25+
"""Serializer for Region model (List only)."""
26+
27+
class Meta:
28+
"""Meta definition for RegionListSerializer."""
29+
model = Region
30+
fields = [
31+
"id",
32+
"name",
33+
]
34+
35+
2436
class ComuneSerializer(ModelSerializer):
2537
"""Serializer for Comune model."""
26-
region = RegionSerializer(read_only=True)
38+
region = RegionSerializer()
2739

2840
class Meta:
2941
"""Meta definition for ComuneSerializer."""
@@ -35,3 +47,15 @@ class Meta:
3547
"created_at",
3648
"updated_at"
3749
]
50+
51+
52+
class ComuneListSerializer(ModelSerializer):
53+
"""Serializer for Comune model (List only)."""
54+
55+
class Meta:
56+
"""Meta definition for ComuneListSerializer."""
57+
model = Comune
58+
fields = [
59+
"id",
60+
"name"
61+
]

0 commit comments

Comments
 (0)