162 lines
5.6 KiB
Python
162 lines
5.6 KiB
Python
"""Defines serializers used by the Team API."""
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.db.models import Count
|
|
|
|
from rest_framework import serializers
|
|
|
|
from openedx.core.lib.api.serializers import CollapsedReferenceSerializer, PaginationSerializer
|
|
from openedx.core.lib.api.fields import ExpandableField
|
|
from openedx.core.djangoapps.user_api.serializers import UserSerializer
|
|
|
|
from .models import CourseTeam, CourseTeamMembership
|
|
|
|
|
|
class UserMembershipSerializer(serializers.ModelSerializer):
|
|
"""Serializes CourseTeamMemberships with only user and date_joined
|
|
|
|
Used for listing team members.
|
|
"""
|
|
user = ExpandableField(
|
|
collapsed_serializer=CollapsedReferenceSerializer(
|
|
model_class=User,
|
|
id_source='username',
|
|
view_name='accounts_api',
|
|
read_only=True,
|
|
),
|
|
expanded_serializer=UserSerializer(),
|
|
)
|
|
|
|
class Meta(object):
|
|
"""Defines meta information for the ModelSerializer."""
|
|
model = CourseTeamMembership
|
|
fields = ("user", "date_joined")
|
|
read_only_fields = ("date_joined",)
|
|
|
|
|
|
class CourseTeamSerializer(serializers.ModelSerializer):
|
|
"""Serializes a CourseTeam with membership information."""
|
|
id = serializers.CharField(source='team_id', read_only=True) # pylint: disable=invalid-name
|
|
membership = UserMembershipSerializer(many=True, read_only=True)
|
|
|
|
class Meta(object):
|
|
"""Defines meta information for the ModelSerializer."""
|
|
model = CourseTeam
|
|
fields = (
|
|
"id",
|
|
"name",
|
|
"is_active",
|
|
"course_id",
|
|
"topic_id",
|
|
"date_created",
|
|
"description",
|
|
"country",
|
|
"language",
|
|
"membership",
|
|
)
|
|
read_only_fields = ("course_id", "date_created")
|
|
|
|
|
|
class CourseTeamCreationSerializer(serializers.ModelSerializer):
|
|
"""Deserializes a CourseTeam for creation."""
|
|
|
|
class Meta(object):
|
|
"""Defines meta information for the ModelSerializer."""
|
|
model = CourseTeam
|
|
fields = (
|
|
"name",
|
|
"course_id",
|
|
"description",
|
|
"topic_id",
|
|
"country",
|
|
"language",
|
|
)
|
|
|
|
def restore_object(self, attrs, instance=None):
|
|
"""Restores a CourseTeam instance from the given attrs."""
|
|
return CourseTeam.create(
|
|
name=attrs.get("name", ''),
|
|
course_id=attrs.get("course_id"),
|
|
description=attrs.get("description", ''),
|
|
topic_id=attrs.get("topic_id", ''),
|
|
country=attrs.get("country", ''),
|
|
language=attrs.get("language", ''),
|
|
)
|
|
|
|
|
|
class MembershipSerializer(serializers.ModelSerializer):
|
|
"""Serializes CourseTeamMemberships with information about both teams and users."""
|
|
user = ExpandableField(
|
|
collapsed_serializer=CollapsedReferenceSerializer(
|
|
model_class=User,
|
|
id_source='username',
|
|
view_name='accounts_api',
|
|
read_only=True,
|
|
),
|
|
expanded_serializer=UserSerializer(read_only=True)
|
|
)
|
|
team = ExpandableField(
|
|
collapsed_serializer=CollapsedReferenceSerializer(
|
|
model_class=CourseTeam,
|
|
id_source='team_id',
|
|
view_name='teams_detail',
|
|
read_only=True,
|
|
),
|
|
expanded_serializer=CourseTeamSerializer(read_only=True)
|
|
)
|
|
|
|
class Meta(object):
|
|
"""Defines meta information for the ModelSerializer."""
|
|
model = CourseTeamMembership
|
|
fields = ("user", "team", "date_joined")
|
|
read_only_fields = ("date_joined",)
|
|
|
|
|
|
class BaseTopicSerializer(serializers.Serializer):
|
|
"""Serializes a topic without team_count."""
|
|
description = serializers.CharField()
|
|
name = serializers.CharField()
|
|
id = serializers.CharField() # pylint: disable=invalid-name
|
|
|
|
|
|
class TopicSerializer(BaseTopicSerializer):
|
|
"""
|
|
Adds team_count to the basic topic serializer. Use only when
|
|
serializing a single topic. When serializing many topics, use
|
|
`PaginatedTopicSerializer` to avoid O(N) SQL queries. Requires
|
|
that `context` is provided with a valid course_id in order to
|
|
filter teams within the course.
|
|
"""
|
|
team_count = serializers.SerializerMethodField('get_team_count')
|
|
|
|
def get_team_count(self, topic):
|
|
"""Get the number of teams associated with this topic"""
|
|
return CourseTeam.objects.filter(course_id=self.context['course_id'], topic_id=topic['id']).count()
|
|
|
|
|
|
class PaginatedTopicSerializer(PaginationSerializer):
|
|
"""
|
|
Serializes a set of topics, adding team_count field to each topic.
|
|
Requires that `context` is provided with a valid course_id in
|
|
order to filter teams within the course.
|
|
"""
|
|
class Meta(object):
|
|
"""Defines meta information for the PaginatedTopicSerializer."""
|
|
object_serializer_class = BaseTopicSerializer
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Adds team_count to each topic."""
|
|
super(PaginatedTopicSerializer, self).__init__(*args, **kwargs)
|
|
|
|
# The following query gets all the team_counts for each topic
|
|
# and outputs the result as a list of dicts (one per topic).
|
|
topic_ids = [topic['id'] for topic in self.data['results']]
|
|
teams_per_topic = CourseTeam.objects.filter(
|
|
course_id=self.context['course_id'],
|
|
topic_id__in=topic_ids
|
|
).values('topic_id').annotate(team_count=Count('topic_id'))
|
|
|
|
topics_to_team_count = {d['topic_id']: d['team_count'] for d in teams_per_topic}
|
|
for topic in self.data['results']:
|
|
topic['team_count'] = topics_to_team_count.get(topic['id'], 0)
|