class AnswerSerializer(serializers.ModelSerializer): created = DateTimeUTCField(read_only=True) creator = ProfileFKSerializer(read_only=True, source='creator.get_profile') updated = DateTimeUTCField(read_only=True) updated_by = ProfileFKSerializer(read_only=True, source='updated_by.get_profile') num_helpful_votes = serializers.Field(source='num_helpful_votes') num_unhelpful_votes = serializers.Field(source='num_unhelpful_votes') class Meta: model = Answer fields = ( 'id', 'question', 'content', 'created', 'creator', 'updated', 'updated_by', 'is_spam', 'num_helpful_votes', 'num_unhelpful_votes', ) def validate_creator(self, attrs, source): user = getattr(self.context.get('request'), 'user') if user and not user.is_anonymous() and attrs.get('creator') is None: attrs['creator'] = user return attrs
class QuestionSerializer(serializers.ModelSerializer): # Use slugs for product and topic instead of ids. product = serializers.SlugRelatedField(required=True, slug_field='slug') topic = TopicField(required=True) # Use usernames for creator and updated_by instead of ids. created = DateTimeUTCField(read_only=True) creator = ProfileFKSerializer(source='creator.get_profile', read_only=True) involved = serializers.SerializerMethodField('get_involved_users') is_solved = serializers.Field(source='is_solved') is_taken = serializers.Field(source='is_taken') metadata = QuestionMetaDataSerializer(source='metadata_set', required=False) num_votes = serializers.Field(source='num_votes') solution = serializers.PrimaryKeyRelatedField(read_only=True) taken_by = ProfileFKSerializer(source='taken_by.get_profile', read_only=True) updated = DateTimeUTCField(read_only=True) updated_by = ProfileFKSerializer(source='updated_by.get_profile', read_only=True) class Meta: model = Question fields = ( 'answers', 'content', 'created', 'creator', 'id', 'involved', 'is_archived', 'is_locked', 'is_solved', 'is_spam', 'is_taken', 'last_answer', 'locale', 'metadata', 'num_answers', 'num_votes_past_week', 'num_votes', 'product', 'solution', 'taken_until', 'taken_by', 'title', 'topic', 'updated_by', 'updated', ) def get_involved_users(self, obj): involved = set([obj.creator.get_profile()]) involved.update(a.creator.get_profile() for a in obj.answers.all()) return ProfileFKSerializer(involved, many=True).data def validate_creator(self, attrs, source): user = getattr(self.context.get('request'), 'user') if user and not user.is_anonymous() and attrs.get(source) is None: attrs['creator'] = user return attrs
class ImageDetailSerializer(ImageShortSerializer): created = DateTimeUTCField(read_only=True) updated = DateTimeUTCField(read_only=True) updated_by = serializers.SlugRelatedField(slug_field='username') class Meta(ImageShortSerializer.Meta): fields = ImageShortSerializer.Meta.fields + ( 'created', 'updated', 'updated_by', 'description', 'is_draft', 'creator')
class AnswerSerializer(serializers.ModelSerializer): content = SplitSourceField(read_source='content_parsed', write_source='content') created = DateTimeUTCField(read_only=True) creator = serializers.SerializerMethodField('get_creator') num_helpful_votes = serializers.Field(source='num_helpful_votes') num_unhelpful_votes = serializers.Field(source='num_unhelpful_votes') updated = DateTimeUTCField(read_only=True) updated_by = serializers.SerializerMethodField('get_updated_by') class Meta: model = Answer fields = ( 'id', 'question', 'content', 'created', 'creator', 'updated', 'updated_by', 'is_spam', 'num_helpful_votes', 'num_unhelpful_votes', ) def get_creator(self, obj): return ProfileFKSerializer(Profile.objects.get(user=obj.creator)).data def get_updated_by(self, obj): updated_by = Profile.objects.get( user=obj.updated_by) if obj.updated_by else None return ProfileFKSerializer(updated_by).data if updated_by else None def validate_creator(self, attrs, source): user = getattr(self.context.get('request'), 'user') if user and not user.is_anonymous() and attrs.get('creator') is None: attrs['creator'] = user return attrs
class RealtimeActionSerializer(serializers.ModelSerializer): action_object = GenericRelatedField(serializer_type='full') actor = GenericRelatedField(serializer_type='full') target = GenericRelatedField(serializer_type='full') verb = serializers.CharField() timestamp = DateTimeUTCField() class Meta: model = PushNotificationRegistration fields = ( 'action_object', 'actor', 'id', 'target', 'timestamp', 'verb', )
class NotificationSerializer(serializers.ModelSerializer): is_read = serializers.Field(source='is_read') timestamp = DateTimeUTCField(source='action.timestamp') actor = GenericRelatedField(source='action.actor') verb = serializers.CharField(source='action.verb') action_object = GenericRelatedField(source='action.action_object') target = GenericRelatedField(source='action.target') class Meta: model = PushNotificationRegistration fields = ( 'is_read', # 'read_at', 'timestamp', 'actor', 'verb', 'action_object', 'target' )
class ProfileSerializer(serializers.ModelSerializer): username = serializers.WritableField(source='user.username') display_name = serializers.WritableField(source='name', required=False) date_joined = DateTimeUTCField(source='user.date_joined', read_only=True) avatar = serializers.SerializerMethodField('get_avatar_url') email = (PermissionMod(serializers.WritableField, permissions=[OnlySelf])(source='user.email', required=False)) settings = (PermissionMod(UserSettingSerializer, permissions=[OnlySelf])(many=True, read_only=True)) helpfulness = serializers.Field(source='answer_helpfulness') answer_count = serializers.SerializerMethodField('get_answer_count') question_count = serializers.SerializerMethodField('get_question_count') solution_count = serializers.SerializerMethodField('get_solution_count') # These are write only fields. It is very important they stays that way! password = serializers.WritableField(source='user.password', write_only=True) is_active = (PermissionMod(serializers.BooleanField, permissions=[OnlySelf])(source='user.is_active', read_only=True)) class Meta: model = Profile fields = [ 'username', 'display_name', 'date_joined', 'avatar', 'bio', 'website', 'twitter', 'facebook', 'mozillians', 'irc_handle', 'timezone', 'country', 'city', 'locale', 'email', 'settings', 'helpfulness', 'question_count', 'answer_count', 'solution_count', # Password and email are here so they can be involved in write # operations. They is marked as write-only above, so will not be # visible. 'password', 'is_active', ] def get_avatar_url(self, profile): return profile_avatar(profile.user) def get_question_count(self, profile): return num_questions(profile.user) def get_answer_count(self, profile): return num_answers(profile.user) def get_solution_count(self, profile): return num_solutions(profile.user) def restore_object(self, attrs, instance=None): """ Override the default behavior to make a user if one doesn't exist. This user may not be saved here, but will be saved if/when the .save() method of the serializer is called. """ instance = (super(ProfileSerializer, self).restore_object(attrs, instance)) if instance.user_id is None: # The Profile doesn't have a user, so create one. If an email is # specified, the user will be inactive until the email is # confirmed. Otherwise the user can be created immediately. if 'user.email' in attrs: u = RegistrationProfile.objects.create_inactive_user( attrs['user.username'], attrs['user.password'], attrs['user.email']) else: u = User(username=attrs['user.username']) u.set_password(attrs['user.password']) instance._nested_forward_relations['user'] = u return instance def validate_username(self, attrs, source): obj = self.object if obj is None: # This is a create if User.objects.filter(username=attrs['user.username']).exists(): raise ValidationError('A user with that username exists') else: # This is an update new_username = attrs.get('user.username', obj.user.username) if new_username != obj.user.username: raise ValidationError("Can't change this field.") if re.match(r'^[\w.-]{4,30}$', attrs['user.username']) is None: raise ValidationError( 'Usernames may only be letters, numbers, "." and "-".') return attrs def validate_display_name(self, attrs, source): if attrs.get('name') is None: attrs['name'] = attrs.get('user.username') return attrs def validate_email(self, attrs, source): email = attrs.get('user.email') if email and User.objects.filter(email=email).exists(): raise ValidationError('A user with that email address ' 'already exists.') return attrs
class QuestionSerializer(serializers.ModelSerializer): content = SplitSourceField(read_source='content_parsed', write_source='content') created = DateTimeUTCField(read_only=True) creator = serializers.SerializerMethodField('get_creator') involved = serializers.SerializerMethodField('get_involved_users') is_solved = serializers.Field(source='is_solved') is_taken = serializers.Field(source='is_taken') metadata = QuestionMetaDataSerializer(source='metadata_set', required=False) num_votes = serializers.Field(source='num_votes') product = serializers.SlugRelatedField(required=True, slug_field='slug') tags = QuestionTagSerializer(source='tags', read_only=True) solution = serializers.PrimaryKeyRelatedField(read_only=True) solved_by = serializers.SerializerMethodField('get_solved_by') taken_by = serializers.SerializerMethodField('get_taken_by') topic = TopicField(required=True) updated = DateTimeUTCField(read_only=True) updated_by = serializers.SerializerMethodField('get_updated_by') class Meta: model = Question fields = ( 'answers', 'content', 'created', 'creator', 'id', 'involved', 'is_archived', 'is_locked', 'is_solved', 'is_spam', 'is_taken', 'last_answer', 'locale', 'metadata', 'tags', 'num_answers', 'num_votes_past_week', 'num_votes', 'product', 'solution', 'taken_until', 'taken_by', 'title', 'topic', 'updated_by', 'updated', ) def get_involved_users(self, obj): involved = set([Profile.objects.get(user=obj.creator)]) involved.update( Profile.objects.get(user=a.creator) for a in obj.answers.all()) return ProfileFKSerializer(involved, many=True).data def get_solved_by(self, obj): return ProfileFKSerializer( obj.solution.creator).data if obj.solution else None def get_creator(self, obj): return ProfileFKSerializer(Profile.objects.get(user=obj.creator)).data def get_taken_by(self, obj): taken_by = Profile.objects.get( user=obj.taken_by) if obj.taken_by else None return ProfileFKSerializer(taken_by).data if taken_by else None def get_updated_by(self, obj): updated_by = Profile.objects.get( user=obj.updated_by) if obj.updated_by else None return ProfileFKSerializer(updated_by).data if updated_by else None def validate_creator(self, attrs, source): user = getattr(self.context.get('request'), 'user') if user and not user.is_anonymous() and attrs.get(source) is None: attrs['creator'] = user return attrs
class ProfileSerializer(serializers.ModelSerializer): username = serializers.WritableField(source='user.username') display_name = serializers.WritableField(source='name', required=False) date_joined = DateTimeUTCField(source='user.date_joined', read_only=True) avatar = serializers.SerializerMethodField('get_avatar_url') email = (PermissionMod(serializers.EmailField, permissions=[OnlySelf])(source='user.email', required=True)) settings = (PermissionMod(UserSettingSerializer, permissions=[OnlySelf])(many=True, read_only=True)) helpfulness = serializers.Field(source='answer_helpfulness') answer_count = serializers.SerializerMethodField('get_answer_count') question_count = serializers.SerializerMethodField('get_question_count') solution_count = serializers.SerializerMethodField('get_solution_count') last_answer_date = serializers.SerializerMethodField( 'get_last_answer_date') is_active = serializers.BooleanField(source='user.is_active', read_only=True) # These are write only fields. It is very important they stays that way! password = serializers.WritableField(source='user.password', write_only=True) class Meta: model = Profile fields = [ 'username', 'display_name', 'date_joined', 'avatar', 'bio', 'website', 'twitter', 'facebook', 'mozillians', 'irc_handle', 'timezone', 'country', 'city', 'locale', 'email', 'settings', 'helpfulness', 'question_count', 'answer_count', 'solution_count', 'last_answer_date', # Password and email are here so they can be involved in write # operations. They is marked as write-only above, so will not be # visible. 'password', 'is_active', ] def get_avatar_url(self, profile): request = self.context.get('request') size = request.REQUEST.get('avatar_size', 48) if request else 48 return profile_avatar(profile.user, size=size) def get_question_count(self, profile): return num_questions(profile.user) def get_answer_count(self, profile): return num_answers(profile.user) def get_solution_count(self, profile): return num_solutions(profile.user) def get_last_answer_date(self, profile): last_answer = profile.user.answers.order_by('-created').first() return last_answer.created if last_answer else None def save_object(self, obj, **kwargs): """It is universally a bad idea to force_insert=True on this object. So don't.""" kwargs.pop('force_insert', None) return super(ProfileSerializer, self).save_object(obj, **kwargs) def restore_object(self, attrs, instance=None): """ Override the default behavior to make a user if one doesn't exist. This user may not be saved here, but will be saved if/when the .save() method of the serializer is called. """ instance = (super(ProfileSerializer, self).restore_object(attrs, instance)) if instance.user_id is None: # This is a bit of cheat. The user shouldn't be saved yet, but # ``create_inactive_user`` saves it, so their isn't much of a choice. u = RegistrationProfile.objects.create_inactive_user( attrs['user.username'], attrs['user.password'], attrs['user.email']) instance.user_id = u.id instance.save() return instance def validate_username(self, attrs, source): obj = self.object if obj is None: # This is a create if User.objects.filter(username=attrs['user.username']).exists(): raise ValidationError('A user with that username exists') else: # This is an update new_username = attrs.get('user.username', obj.user.username) if new_username != obj.user.username: raise ValidationError("Can't change this field.") if re.match(r'^[\w.-]{4,30}$', attrs['user.username']) is None: raise ValidationError( 'Usernames may only be letters, numbers, "." and "-".') return attrs def validate_display_name(self, attrs, source): if attrs.get('name') is None: attrs['name'] = attrs.get('user.username') return attrs def validate_email(self, attrs, source): email = attrs.get('user.email') if email and User.objects.filter(email=email).exists(): raise ValidationError('A user with that email address ' 'already exists.') return attrs