Offloaded study group radius calculation to backend and fixed study groups serializer

This commit is contained in:
Keannu Bernasol 2023-09-24 21:03:32 +08:00
parent 018475b92c
commit 50fdebf222
2 changed files with 39 additions and 18 deletions

View file

@ -14,6 +14,7 @@ class CustomUserKeyRelatedField(serializers.PrimaryKeyRelatedField):
class StudyGroupSerializer(serializers.ModelSerializer): class StudyGroupSerializer(serializers.ModelSerializer):
name = serializers.CharField()
users = CustomUserKeyRelatedField( users = CustomUserKeyRelatedField(
queryset=CustomUser.objects.all(), many=True) queryset=CustomUser.objects.all(), many=True)
subject = serializers.SlugRelatedField( subject = serializers.SlugRelatedField(
@ -21,6 +22,7 @@ class StudyGroupSerializer(serializers.ModelSerializer):
location = PointField() location = PointField()
landmark = serializers.SlugRelatedField( landmark = serializers.SlugRelatedField(
queryset=Landmark.objects.all(), many=False, slug_field='name', required=False, allow_null=True) queryset=Landmark.objects.all(), many=False, slug_field='name', required=False, allow_null=True)
radius = serializers.FloatField()
def create(self, validated_data): def create(self, validated_data):
user = self.context['request'].user user = self.context['request'].user
@ -40,7 +42,7 @@ class StudyGroupSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = StudyGroup model = StudyGroup
fields = '__all__' fields = '__all__'
read_only_fields = ['landmark'] read_only_fields = ['landmark', 'radius']
class StudyGroupMembershipSerializer(serializers.ModelSerializer): class StudyGroupMembershipSerializer(serializers.ModelSerializer):

View file

@ -4,11 +4,12 @@ from rest_framework.exceptions import PermissionDenied
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from .serializers import StudyGroupSerializer from .serializers import StudyGroupSerializer
from .models import StudyGroup from .models import StudyGroup
from subjects.models import Subject from subjects.models import Subject, SubjectInstance
from student_status.models import StudentStatus from student_status.models import StudentStatus
from rest_framework import generics, viewsets, exceptions from rest_framework import generics, viewsets, exceptions
from django.contrib.gis.geos import fromstr from django.contrib.gis.geos import fromstr
from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.db.models.functions import Distance
# Create your views here. # Create your views here.
@ -20,6 +21,11 @@ class StudyGroupListView(generics.ListAPIView):
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
if not user.is_student:
raise PermissionDenied(
"You must be a student to view study groups"
)
if not user.is_student: if not user.is_student:
raise PermissionDenied( raise PermissionDenied(
"You must be a student to view study groups" "You must be a student to view study groups"
@ -29,15 +35,14 @@ class StudyGroupListView(generics.ListAPIView):
user_course = user.course user_course = user.course
print(user_course) print(user_course)
# Get subject names related to the user's course # Get the subject name of the student's subjects from SubjectInstance
subject_names = Subject.objects.filter( user_subject_names = user.subjects.values_list('subject', flat=True)
course=user_course print('user subjects:', user_subject_names)
).values_list('subject', flat=True) # Get the corresponding Subject models
user_subjects = Subject.objects.filter(name__in=user_subject_names)
# Now fetch the StudyGroups with the matching Subject models
studygroups = StudyGroup.objects.filter(subject__in=user_subjects)
print(subject_names)
# Now fetch the StudyGroups with the matching subject names
studygroups = StudyGroup.objects.filter(subject_name__in=subject_names)
return studygroups return studygroups
@ -64,16 +69,30 @@ class StudyGroupListNearView(generics.ListAPIView):
user_course = user.course user_course = user.course
print(user_course) print(user_course)
# Get subject names related to the user's course # Get the subject name of the student's subjects from SubjectInstance
subject_names = Subject.objects.filter( user_subject_names = user.subjects.values_list('subject', flat=True)
course=user_course # Get the corresponding Subject models
).values_list('subject', flat=True) user_subjects = Subject.objects.filter(name__in=user_subject_names)
print(subject_names) # Now fetch the StudyGroups with the matching Subject models that are within 100m
studygroups = StudyGroup.objects.filter(subject__in=user_subjects).annotate(
distance=Distance('location', user_location)).filter(distance__lte=100)
for group in studygroups:
# Get all StudentStatus locations of the group
group_locations = group.users.values_list('location', flat=True)
# Convert string locations to GEOSGeometry objects
point_locations = [fromstr(loc, srid=4326)
for loc in group_locations]
# Calculate distances between every pair of locations
distances = [(loc1.distance(
loc2)*100000)for loc1 in point_locations for loc2 in point_locations]
# Get the maximum distance
group_radius = max(distances) if distances else 0
group_radius = max(group_radius, 15)
# Annotate the group with the radius
group.radius = group_radius
# Now fetch the StudyGroups with the matching subject names that are within 50m
studygroups = StudyGroup.objects.filter(subject_name__in=subject_names).annotate(
distance=Distance('location', user_location)).filter(distance__lte=50)
return studygroups return studygroups