def parse_vote_value(self, obj, key): """ Raises a ValidationError on incorrect values, including None """ if key not in obj: raise ValidationError({"detail": f"The field {key} is required"}) field = DecimalField(min_value=-2, max_digits=15, decimal_places=6) value = field.to_internal_value(obj[key]) if value < 0 and value != -1 and value != -2: raise ValidationError({ "detail": "No fractional negative values allowed, only the special values -1 and -2" }) return value
class AssignmentAllPollSerializer(ModelSerializer): """ Serializer for assignment.models.AssignmentPoll objects. Serializes all polls. """ options = AssignmentOptionSerializer(many=True, read_only=True) votes = ListField(child=DictField( child=DecimalField(max_digits=15, decimal_places=6, min_value=-2)), write_only=True, required=False) has_votes = SerializerMethodField() class Meta: model = AssignmentPoll fields = ( 'id', 'pollmethod', 'description', 'published', 'options', 'votesabstain', 'votesno', 'votesvalid', 'votesinvalid', 'votescast', 'votes', 'has_votes', 'assignment' ) # js-data needs the assignment-id in the nested object to define relations. read_only_fields = ('pollmethod', ) validators = (default_votes_validator, ) def get_has_votes(self, obj): """ Returns True if this poll has some votes. """ return obj.has_votes() @transaction.atomic def update(self, instance, validated_data): """ Customized update method for polls. To update votes use the write only field 'votes'. Example data for a 'pollmethod'='yna' poll with two candidates: "votes": [{"Yes": 10, "No": 4, "Abstain": -2}, {"Yes": -1, "No": 0, "Abstain": -2}] Example data for a 'pollmethod' ='yn' poll with two candidates: "votes": [{"Votes": 10}, {"Votes": 0}] """ # Update votes. votes = validated_data.get('votes') if votes: options = list(instance.get_options()) if len(votes) != len(options): raise ValidationError({ 'detail': _('You have to submit data for %d candidates.') % len(options) }) for index, option in enumerate(options): if len(votes[index]) != len(instance.get_vote_values()): raise ValidationError({ 'detail': _('You have to submit data for %d vote values.') % len(instance.get_vote_values()) }) for vote_value, vote_weight in votes[index].items(): if vote_value not in instance.get_vote_values(): raise ValidationError({ 'detail': _('Vote value %s is invalid.') % vote_value }) instance.set_vote_objects_with_values(option, votes[index], skip_autoupdate=True) # Update remaining writeable fields. instance.description = validated_data.get('description', instance.description) instance.published = validated_data.get('published', instance.published) instance.votesabstain = validated_data.get('votesabstain', instance.votesabstain) instance.votesno = validated_data.get('votesno', instance.votesno) instance.votesvalid = validated_data.get('votesvalid', instance.votesvalid) instance.votesinvalid = validated_data.get('votesinvalid', instance.votesinvalid) instance.votescast = validated_data.get('votescast', instance.votescast) instance.save() return instance
class AssignmentPollSerializer(BasePollSerializer): """ Serializer for assignment.models.AssignmentPoll objects. Serializes all polls. """ amount_global_no = DecimalField(max_digits=15, decimal_places=6, min_value=-2, read_only=True) amount_global_abstain = DecimalField(max_digits=15, decimal_places=6, min_value=-2, read_only=True) class Meta: model = AssignmentPoll fields = ( "assignment", "description", "pollmethod", "votes_amount", "allow_multiple_votes_per_candidate", "global_no", "amount_global_no", "global_abstain", "amount_global_abstain", ) + BASE_POLL_FIELDS read_only_fields = ("state", ) def update(self, instance, validated_data): """ Prevent updating the assignment """ validated_data.pop("assignment", None) return super().update(instance, validated_data) def norm_100_percent_base_to_pollmethod(self, onehundred_percent_base, pollmethod, old_100_percent_base=None): """ Returns None, if the 100-%-base must not be changed, otherwise the correct 100-%-base. """ if pollmethod == AssignmentPoll.POLLMETHOD_YN and onehundred_percent_base in ( AssignmentPoll.PERCENT_BASE_VOTES, AssignmentPoll.PERCENT_BASE_YNA, ): return AssignmentPoll.PERCENT_BASE_YN if (pollmethod == AssignmentPoll.POLLMETHOD_YNA and onehundred_percent_base == AssignmentPoll.PERCENT_BASE_VOTES): if old_100_percent_base is None: return AssignmentPoll.PERCENT_BASE_YNA else: if old_100_percent_base in ( AssignmentPoll.PERCENT_BASE_YN, AssignmentPoll.PERCENT_BASE_YNA, ): return old_100_percent_base else: return pollmethod if (pollmethod == AssignmentPoll.POLLMETHOD_VOTES and onehundred_percent_base in (AssignmentPoll.PERCENT_BASE_YN, AssignmentPoll.PERCENT_BASE_YNA)): return AssignmentPoll.PERCENT_BASE_VOTES return None