mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-10-05 01:15:23 +00:00
Merge pull request #18 from i701/chore/optimize-queries
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 3m56s
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 3m56s
fix(views): optimize database queries to solve N+1 problems 🔨🐛
This commit is contained in:
11
api/views.py
11
api/views.py
@@ -42,7 +42,6 @@ from .serializers import (
|
||||
AuthSerializer,
|
||||
CustomUserSerializer,
|
||||
CustomReadOnlyUserSerializer,
|
||||
CustomReadOnlyUserByIDCardSerializer,
|
||||
UserProfileUpdateSerializer,
|
||||
)
|
||||
|
||||
@@ -579,16 +578,6 @@ def filter_temporary_user(request):
|
||||
)
|
||||
|
||||
|
||||
class ListUserByIDCardView(generics.ListAPIView):
|
||||
# Create user API view
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = CustomReadOnlyUserByIDCardSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = "__all__"
|
||||
filterset_class = UserFilter
|
||||
queryset = User.objects.all()
|
||||
|
||||
|
||||
class UserDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = CustomReadOnlyUserSerializer
|
||||
|
@@ -235,8 +235,11 @@ REST_FRAMEWORK = {
|
||||
"login": "1000/min",
|
||||
},
|
||||
"EXCEPTION_HANDLER": "api.exceptions.custom_exception_handler",
|
||||
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
|
||||
# "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema"
|
||||
"DEFAULT_RENDERER_CLASSES": (
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
# "rest_framework.renderers.BrowsableAPIRenderer",
|
||||
),
|
||||
# "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
|
||||
|
@@ -13,6 +13,7 @@ from rest_framework.response import Response
|
||||
from api.mixins import StaffEditorPermissionMixin
|
||||
from api.tasks import add_new_devices_to_omada
|
||||
from apibase.env import BASE_DIR, env
|
||||
from django.db.models import Prefetch
|
||||
import logging
|
||||
|
||||
from .models import Device, Payment, Topup, WalletTransaction
|
||||
@@ -60,10 +61,18 @@ class ListCreatePaymentView(StaffEditorPermissionMixin, generics.ListCreateAPIVi
|
||||
filterset_class = PaymentFilter
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
if self.request.user.is_superuser:
|
||||
return queryset
|
||||
return queryset.filter(user=self.request.user)
|
||||
unpaid_qs = Payment.objects.filter(paid=False).order_by("-created_at")
|
||||
device_qs = Device.objects.prefetch_related(
|
||||
Prefetch("payments", queryset=unpaid_qs, to_attr="unpaid_payments")
|
||||
)
|
||||
queryset = Payment.objects.select_related("user").prefetch_related(
|
||||
Prefetch("devices", queryset=device_qs)
|
||||
)
|
||||
|
||||
if not self.request.user.is_superuser:
|
||||
queryset = queryset.filter(user=self.request.user)
|
||||
|
||||
return queryset
|
||||
|
||||
def create(self, request):
|
||||
data = request.data
|
||||
@@ -163,7 +172,7 @@ class UpdatePaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
|
||||
class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
serializer_class = PaymentSerializer
|
||||
queryset = Payment.objects.all()
|
||||
queryset = Payment.objects.select_related("user").all()
|
||||
lookup_field = "pk"
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
@@ -322,7 +331,7 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
|
||||
|
||||
class CancelPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
queryset = Payment.objects.all()
|
||||
queryset = Payment.objects.select_related("user").all()
|
||||
serializer_class = PaymentSerializer
|
||||
lookup_field = "pk"
|
||||
|
||||
@@ -352,7 +361,7 @@ class CancelPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
|
||||
|
||||
class ListCreateTopupView(StaffEditorPermissionMixin, generics.ListCreateAPIView):
|
||||
queryset = Topup.objects.all()
|
||||
queryset = Topup.objects.all().prefetch_related("user")
|
||||
serializer_class = TopupSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = "__all__"
|
||||
|
@@ -36,9 +36,9 @@ class DeviceSerializer(serializers.ModelSerializer):
|
||||
|
||||
def get_pending_payment_id(self, obj):
|
||||
unpaid_payment = (
|
||||
Payment.objects.filter(devices=obj, paid=False)
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
obj.unpaid_payments[0]
|
||||
if hasattr(obj, "unpaid_payments") and obj.unpaid_payments
|
||||
else None
|
||||
)
|
||||
return unpaid_payment.id if unpaid_payment else None
|
||||
|
||||
@@ -63,9 +63,9 @@ class AdminDeviceSerializer(serializers.ModelSerializer):
|
||||
|
||||
def get_pending_payment_id(self, obj):
|
||||
unpaid_payment = (
|
||||
Payment.objects.filter(devices=obj, paid=False)
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
obj.unpaid_payments[0]
|
||||
if hasattr(obj, "unpaid_payments") and obj.unpaid_payments
|
||||
else None
|
||||
)
|
||||
return unpaid_payment.id if unpaid_payment else None
|
||||
|
||||
|
@@ -3,7 +3,9 @@ from xmlrpc.client import Boolean
|
||||
from rest_framework import generics, status
|
||||
from rest_framework.response import Response
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from billing.models import Payment
|
||||
from .models import Device
|
||||
from django.db.models import Prefetch
|
||||
from .serializers import (
|
||||
CreateDeviceSerializer,
|
||||
DeviceSerializer,
|
||||
@@ -28,6 +30,13 @@ class DeviceListCreateAPIView(
|
||||
filterset_fields = "__all__"
|
||||
filterset_class = DeviceFilter
|
||||
|
||||
def get_queryset(self):
|
||||
unpaid_qs = Payment.objects.filter(paid=False).order_by("-created_at")
|
||||
base_qs = Device.objects.select_related("user").prefetch_related(
|
||||
Prefetch("payments", queryset=unpaid_qs, to_attr="unpaid_payments")
|
||||
)
|
||||
return base_qs.all()
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
all_devices = request.query_params.get("all_devices", "false").lower() in [
|
||||
@@ -90,7 +99,7 @@ class DeviceDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
||||
|
||||
|
||||
class DeviceUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
queryset = Device.objects.all()
|
||||
queryset = Device.objects.select_related("user").all()
|
||||
serializer_class = CreateDeviceSerializer
|
||||
lookup_field = "pk"
|
||||
|
||||
@@ -116,7 +125,7 @@ class DeviceUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
|
||||
|
||||
class DeviceBlockAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
queryset = Device.objects.all()
|
||||
queryset = Device.objects.select_related("user").all()
|
||||
serializer_class = BlockDeviceSerializer
|
||||
lookup_field = "pk"
|
||||
|
||||
@@ -154,7 +163,7 @@ class DeviceBlockAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
|
||||
|
||||
class DeviceDestroyAPIView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
||||
queryset = Device.objects.all()
|
||||
queryset = Device.objects.select_related("user").all()
|
||||
serializer_class = DeviceSerializer
|
||||
lookup_field = "pk"
|
||||
|
||||
|
Reference in New Issue
Block a user