def one_member(self): return @property def many_members(self): return @pytest.mark.parametrize( 'serializer_field,expect_array', ( (relations.SerializerMethodResourceRelatedField(model=MemberWithCustomID, source='get_member', read_only=True), False), (relations.SerializerMethodResourceRelatedField(model=MemberWithCustomID, source='get_members', read_only=True, many=True), True), (relations.ResourceRelatedField(model=MemberWithCustomID, source='one_member', read_only=True), False), (relations.ResourceRelatedField(model=MemberWithCustomID, source='many_members', read_only=True, many=True), True), (relations.ResourceRelatedField(queryset=MemberWithCustomID.objects.all(), source='one_member'), False), (relations.ResourceRelatedField(queryset=MemberWithCustomID.objects.all(), source='many_members', many=True), True), ) ) def test_get__manual_related_resource(serializer_field, expect_array): """ Support off combinations of related resources fields – they do supply models or don't. """ class ProjectSerializer(serializers.ModelSerializer): member_relation = serializer_field
class AbsenceBalanceSerializer(Serializer): credit = SerializerMethodField() used_days = SerializerMethodField() used_duration = SerializerMethodField() balance = SerializerMethodField() user = relations.ResourceRelatedField(model=get_user_model(), read_only=True) absence_type = relations.ResourceRelatedField(model=models.AbsenceType, read_only=True, source="id") absence_credits = relations.SerializerMethodResourceRelatedField( source="get_absence_credits", model=models.AbsenceCredit, many=True, read_only=True, ) def _get_start(self, instance): return date(instance.date.year, 1, 1) def get_credit(self, instance): """ Calculate how many days are approved for given absence type. For absence types which fill worktime this will be None. """ if "credit" in instance: return instance["credit"] # id is mapped to absence type absence_type = instance.id start = self._get_start(instance) # avoid multiple calculations as get_balance needs it as well instance["credit"] = absence_type.calculate_credit( instance.user, start, instance.date) return instance["credit"] def get_used_days(self, instance): """ Calculate how many days are used of given absence type. For absence types which fill worktime this will be None. """ if "used_days" in instance: return instance["used_days"] # id is mapped to absence type absence_type = instance.id start = self._get_start(instance) # avoid multiple calculations as get_balance needs it as well instance["used_days"] = absence_type.calculate_used_days( instance.user, start, instance.date) return instance["used_days"] def get_used_duration(self, instance): """ Calculate duration of absence type. For absence types which fill worktime this will be None. """ # id is mapped to absence type absence_type = instance.id if not absence_type.fill_worktime: return None start = self._get_start(instance) absences = sum( [ absence.calculate_duration( models.Employment.objects.get_at(instance.user, absence.date)) for absence in Absence.objects.filter( user=instance.user, date__range=[start, instance.date], type_id=instance.id, ).select_related("type") ], timedelta(), ) return duration_string(absences) def get_absence_credits(self, instance): """Get the absence credits for the user and type.""" if "absence_credits" in instance: return instance["absence_credits"] # id is mapped to absence type absence_type = instance.id start = self._get_start(instance) absence_credits = models.AbsenceCredit.objects.filter( absence_type=absence_type, user=instance.user, date__range=[start, instance.date], ).select_related("user") # avoid multiple calculations when absence credits need to be included instance["absence_credits"] = absence_credits return absence_credits def get_balance(self, instance): # id is mapped to absence type absence_type = instance.id if absence_type.fill_worktime: return None return self.get_credit(instance) - self.get_used_days(instance) included_serializers = { "absence_type": "timed.employment.serializers.AbsenceTypeSerializer", "absence_credits": "timed.employment.serializers.AbsenceCreditSerializer", } class Meta: resource_name = "absence-balances"
class EntrySerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): super(EntrySerializer, self).__init__(*args, **kwargs) # to make testing more concise we'll only output the # `featured` field when it's requested via `include` request = kwargs.get("context", {}).get("request") if request and "featured" not in request.query_params.get( "include", []): self.fields.pop("featured", None) included_serializers = { "authors": "example.serializers.AuthorSerializer", "comments": "example.serializers.CommentSerializer", "featured": "example.serializers.EntrySerializer", "suggested": "example.serializers.EntrySerializer", "tags": "example.serializers.TaggedItemSerializer", } body_format = serializers.SerializerMethodField() # single related from model blog_hyperlinked = relations.HyperlinkedRelatedField( related_link_view_name="entry-blog", related_link_url_kwarg="entry_pk", self_link_view_name="entry-relationships", read_only=True, source="blog", ) # many related from model comments = relations.ResourceRelatedField(many=True, read_only=True) # many related hyperlinked from model comments_hyperlinked = relations.HyperlinkedRelatedField( related_link_view_name="entry-comments", related_link_url_kwarg="entry_pk", self_link_view_name="entry-relationships", many=True, read_only=True, source="comments", ) # many related from serializer suggested = relations.SerializerMethodResourceRelatedField( related_link_view_name="entry-suggested", related_link_url_kwarg="entry_pk", self_link_view_name="entry-relationships", model=Entry, many=True, ) # many related hyperlinked from serializer suggested_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField( related_link_view_name="entry-suggested", related_link_url_kwarg="entry_pk", self_link_view_name="entry-relationships", model=Entry, many=True, ) # single related from serializer featured = relations.SerializerMethodResourceRelatedField(model=Entry) # single related hyperlinked from serializer featured_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField( related_link_view_name="entry-featured", related_link_url_kwarg="entry_pk", self_link_view_name="entry-relationships", model=Entry, read_only=True, ) tags = relations.ResourceRelatedField(many=True, read_only=True) def get_suggested(self, obj): return Entry.objects.exclude(pk=obj.pk) def get_featured(self, obj): return Entry.objects.exclude(pk=obj.pk).first() def get_body_format(self, obj): return "text" class Meta: model = Entry fields = ( "blog", "blog_hyperlinked", "headline", "body_text", "pub_date", "mod_date", "authors", "comments", "comments_hyperlinked", "featured", "suggested", "suggested_hyperlinked", "tags", "featured_hyperlinked", ) read_only_fields = ("tags", ) meta_fields = ("body_format", ) class JSONAPIMeta: included_resources = ["comments"]
class EntrySerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): super(EntrySerializer, self).__init__(*args, **kwargs) # to make testing more concise we'll only output the # `featured` field when it's requested via `include` request = kwargs.get('context', {}).get('request') if request and 'featured' not in request.query_params.get( 'include', []): self.fields.pop('featured', None) included_serializers = { 'authors': 'example.serializers.AuthorSerializer', 'comments': 'example.serializers.CommentSerializer', 'featured': 'example.serializers.EntrySerializer', 'suggested': 'example.serializers.EntrySerializer', 'tags': 'example.serializers.TaggedItemSerializer', } body_format = serializers.SerializerMethodField() # single related from model blog_hyperlinked = relations.HyperlinkedRelatedField( related_link_view_name='entry-blog', related_link_url_kwarg='entry_pk', self_link_view_name='entry-relationships', read_only=True, source='blog') # many related from model comments = relations.ResourceRelatedField(many=True, read_only=True) # many related hyperlinked from model comments_hyperlinked = relations.HyperlinkedRelatedField( related_link_view_name='entry-comments', related_link_url_kwarg='entry_pk', self_link_view_name='entry-relationships', many=True, read_only=True, source='comments') # many related from serializer suggested = relations.SerializerMethodResourceRelatedField( related_link_view_name='entry-suggested', related_link_url_kwarg='entry_pk', self_link_view_name='entry-relationships', source='get_suggested', model=Entry, many=True, read_only=True) # many related hyperlinked from serializer suggested_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField( related_link_view_name='entry-suggested', related_link_url_kwarg='entry_pk', self_link_view_name='entry-relationships', source='get_suggested', model=Entry, many=True, read_only=True) # single related from serializer featured = relations.SerializerMethodResourceRelatedField( source='get_featured', model=Entry, read_only=True) # single related hyperlinked from serializer featured_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField( related_link_view_name='entry-featured', related_link_url_kwarg='entry_pk', self_link_view_name='entry-relationships', source='get_featured', model=Entry, read_only=True) tags = TaggedItemSerializer(many=True, read_only=True) def get_suggested(self, obj): return Entry.objects.exclude(pk=obj.pk) def get_featured(self, obj): return Entry.objects.exclude(pk=obj.pk).first() def get_body_format(self, obj): return 'text' class Meta: model = Entry fields = ('blog', 'blog_hyperlinked', 'headline', 'body_text', 'pub_date', 'mod_date', 'authors', 'comments', 'comments_hyperlinked', 'featured', 'suggested', 'suggested_hyperlinked', 'tags', 'featured_hyperlinked') read_only_fields = ('tags', ) meta_fields = ('body_format', ) class JSONAPIMeta: included_resources = ['comments']
class UserSerializer(ModelSerializer): """User serializer.""" employments = relations.ResourceRelatedField(many=True, read_only=True) worktime_balance = SerializerMethodField() user_absence_types = relations.SerializerMethodResourceRelatedField( source='get_user_absence_types', model=models.UserAbsenceType, many=True, read_only=True) def get_user_absence_types(self, instance): """Get the user absence types for this user. :returns: All absence types for this user """ request = self.context.get('request') end = datetime.strptime( request.query_params.get('until', date.today().strftime('%Y-%m-%d')), '%Y-%m-%d').date() try: employment = models.Employment.objects.for_user(instance, end) except models.Employment.DoesNotExist: return models.UserAbsenceType.objects.none() start = max(employment.start_date, date(date.today().year, 1, 1)) return models.UserAbsenceType.objects.with_user(instance, start, end) def get_worktime(self, user, start=None, end=None): """Calculate the reported, expected and balance for user. 1. Determine the current employment of the user 2. Take the latest of those two as start date: * The start of the year * The start of the current employment 3. Take the delivered date if given or the current date as end date 4. Determine the count of workdays within start and end date 5. Determine the count of public holidays within start and end date 6. The expected worktime consists of following elements: * Workdays * Subtracted by holidays * Multiplicated with the worktime per day of the employment 7. Determine the overtime credit duration within start and end date 8. The reported worktime is the sum of the durations of all reports for this user within start and end date 9. The absences are all absences for this user between the start and end time 10. The balance is the reported time plus the absences plus the overtime credit minus the expected worktime :param user: user to get worktime from :param start_date: worktime starting on given day; if not set when employment started resp. begining of the year :param end_date: worktime till day or if not set today :returns: tuple of 3 values reported, expected and balance in given time frame """ end = end or date.today() try: employment = models.Employment.objects.for_user(user, end) except models.Employment.DoesNotExist: # If there is no active employment, set the balance to 0 return timedelta(), timedelta(), timedelta() location = employment.location if start is None: start = max(employment.start_date, date(date.today().year, 1, 1)) # workdays is in isoweekday, byweekday expects Monday to be zero week_workdays = [int(day) - 1 for day in employment.location.workdays] workdays = rrule.rrule(rrule.DAILY, dtstart=start, until=end, byweekday=week_workdays).count() # converting workdays as db expects 1 (Sunday) to 7 (Saturday) workdays_db = [ # special case for Sunday int(day) == 7 and 1 or int(day) + 1 for day in location.workdays ] holidays = models.PublicHoliday.objects.filter( location=location, date__gte=start, date__lte=end, date__week_day__in=workdays_db).count() expected_worktime = employment.worktime_per_day * (workdays - holidays) overtime_credit = sum( models.OvertimeCredit.objects.filter(user=user, date__gte=start, date__lte=end).values_list( 'duration', flat=True), timedelta()) reported_worktime = sum( Report.objects.filter(user=user, date__gte=start, date__lte=end).values_list('duration', flat=True), timedelta()) absences = sum( Absence.objects.filter(user=user, date__gte=start, date__lte=end).values_list('duration', flat=True), timedelta()) reported = reported_worktime + absences + overtime_credit return (reported, expected_worktime, reported - expected_worktime) def get_worktime_balance(self, instance): """Format the worktime balance. :return: The formatted worktime balance. :rtype: str """ request = self.context.get('request') until = request.query_params.get('until') end_date = until and datetime.strptime(until, '%Y-%m-%d').date() _, _, balance = self.get_worktime(instance, None, end_date) return duration_string(balance) included_serializers = { 'employments': 'timed.employment.serializers.EmploymentSerializer', 'user_absence_types': 'timed.employment.serializers.UserAbsenceTypeSerializer' } class Meta: """Meta information for the user serializer.""" model = get_user_model() fields = [ 'username', 'first_name', 'last_name', 'email', 'employments', 'worktime_balance', 'is_staff', 'is_active', 'user_absence_types', ]
class AuthorSerializer(serializers.ModelSerializer): bio = relations.ResourceRelatedField( related_link_view_name="author-related", self_link_view_name="author-relationships", queryset=AuthorBio.objects, ) entries = relations.ResourceRelatedField( related_link_view_name="author-related", self_link_view_name="author-relationships", queryset=Entry.objects, many=True, ) first_entry = relations.SerializerMethodResourceRelatedField( related_link_view_name="author-related", self_link_view_name="author-relationships", model=Entry, ) comments = relations.HyperlinkedRelatedField( related_link_view_name="author-related", self_link_view_name="author-relationships", queryset=Comment.objects, many=True, ) secrets = serializers.HiddenField(default="Shhhh!") defaults = serializers.CharField( default="default", max_length=20, min_length=3, write_only=True, help_text="help for defaults", ) initials = serializers.SerializerMethodField() included_serializers = { "bio": AuthorBioSerializer, "type": AuthorTypeSerializer } related_serializers = { "bio": "example.serializers.AuthorBioSerializer", "type": "example.serializers.AuthorTypeSerializer", "comments": "example.serializers.CommentSerializer", "entries": "example.serializers.EntrySerializer", "first_entry": "example.serializers.EntrySerializer", } class Meta: model = Author fields = ( "name", "email", "bio", "entries", "comments", "first_entry", "type", "secrets", "defaults", "initials", ) meta_fields = ("initials", ) def get_first_entry(self, obj): return obj.entries.first() def get_initials(self, obj): return "".join([word[0] for word in obj.name.split(" ")])
class AnnotationSerializer(serializers.ModelSerializer): file = relations.ResourceRelatedField(read_only=True) author = relations.ResourceRelatedField(read_only=True) selectors = serializers.JSONField() favorited = serializers.SerializerMethodField() favoritesCount = serializers.SerializerMethodField( method_name='get_favorites_count') # tagList = relations.ResourceRelatedField(many=True, read_only=True) # tags = relations.ResourceRelatedField(many=True, queryset=Tag.objects.all(), allow_null=True) # 自定义方法来处理关系 tags = TagRelatedField(many=True, required=False) comments = relations.ResourceRelatedField( many=True, read_only=True, related_link_view_name='annotation-comments', related_link_url_kwarg='annotation_pk', # TODO 暂时未发现实用性 # self_link_view_name='annotation-relationships' ) createdAt = serializers.SerializerMethodField(method_name='get_created_at') updatedAt = serializers.SerializerMethodField(method_name='get_updated_at') included_serializers = { 'file': 'scholar.apps.papers.serializers.FileSerializer', 'author': 'scholar.apps.profiles.serializers.ProfileSerializer', 'tags': 'scholar.apps.posts.serializers.TagSerializer', 'comments': 'scholar.apps.posts.serializers.CommentSerializer', } @staticmethod def setup_eager_loading(queryset): queryset = queryset.select_related('author') return queryset def get_created_at(self, instance): return instance.created_at.isoformat() def get_updated_at(self, instance): return instance.updated_at.isoformat() def get_favorited(self, instance): request = self.context.get('request', None) if request is None: return False if not request.user.is_authenticated(): return None return request.user.profile.is_favoriting(instance) def get_favorites_count(self, instance): return instance.favorited_by.count() def create(self, validated_data): profile = self.context['request'].user.profile file_pk = self.context['file_pk'] if file_pk: try: file = File.objects.get(pk=file_pk) except File.DoesNotExist: raise NotFound('File Not Found') tags = validated_data.pop('tags', []) annotation = Annotation.objects.create( **validated_data, author=profile, file=file, ) for tag in tags: annotation.tags.add(tag) return annotation class JSONAPIMeta: included_resources = ['author'] class Meta: model = Annotation fields = ( 'id', 'public', 'file', 'selectors', 'comment', 'color', 'author', 'tags', 'favorited', 'favoritesCount', 'comments', 'createdAt', 'updatedAt', )
class ProfileSerializer(serializers.ModelSerializer): username = serializers.CharField(source='user.username') bio = serializers.CharField(allow_blank=True, required=False) image = serializers.SerializerMethodField() following = serializers.SerializerMethodField() # followings = relations.ResourceRelatedField(many=True, read_only=True) # followers = relations.ResourceRelatedField(many=True, read_only=True) collects = relations.ResourceRelatedField(many=True, read_only=True) favorites = relations.ResourceRelatedField(many=True, read_only=True) owns = relations.ResourceRelatedField(many=True, read_only=True) followings = relations.SerializerMethodResourceRelatedField( source='get_followings', read_only=True, model=Profile, ) followers = relations.SerializerMethodResourceRelatedField( source='get_followers', read_only=True, model=Profile, ) related_serializers = { 'followings': 'scholar.apps.profiles.serializers.ProfileSerializer', 'followers': 'scholar.apps.profiles.serializers.ProfileSerializer', 'collects': 'scholar.apps.posts.serializers.PostSerializer', 'favorites': 'scholar.apps.annotations.serializers.annotationSerializer', 'owns': 'scholar.apps.papers.serializers.FileSerializer', } class Meta: model = Profile fields = ( 'user', 'username', 'bio', 'image', 'following', 'followers', 'followings', 'collects', 'favorites', 'owns', ) read_only_fields = ( 'user', 'username', 'collects', 'favorites', 'owns', 'followers', 'followings', ) def get_image(self, obj): if obj.image: return obj.image return 'https://static.productionready.io/images/smiley-cyrus.jpg' def get_following(self, instance): request = self.context.get('request', None) if request is None: return False if not request.user.is_authenticated(): return False follower = request.user.profile followee = instance return follower.is_following(followee) def get_followings(self, instance): return instance.follows.all() def get_followers(self, instance): return instance.followed_by.all()
class OrganizationSerializer(serializers.HyperlinkedModelSerializer): parent = relations.ResourceRelatedField( queryset=Organization.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='organization-related', related_link_url_kwarg='pk', self_link_view_name='organization-relationships', ) children = relations.ResourceRelatedField( queryset=Organization.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='organization-related', related_link_url_kwarg='pk', self_link_view_name='organization-relationships', ) publishers = relations.ResourceRelatedField( queryset=Publisher.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='organization-related', related_link_url_kwarg='pk', self_link_view_name='organization-relationships', ) included_serializers = { 'parent': 'resolver.serializers.OrganizationSerializer', 'children': 'resolver.serializers.OrganizationSerializer', 'publishers': 'resolver.serializers.PublisherSerializer', } class Meta: model = Organization fields = ('url', 'parent', 'children', 'name', 'abbreviation', 'category', 'href', 'publishers', 'added', 'modified') read_only_fields = ('added', 'modified') meta_fields = ('added', 'modified') def create(self, validated_data: Dict): children = validated_data.pop('children', None) publishers = validated_data.pop('publishers', None) self.is_valid(raise_exception=True) try: organization = Organization.objects.get(**validated_data) except Organization.DoesNotExist: organization = Organization.create(**validated_data) try: organization.save() except IntegrityError as e: raise ResourceExistsError( "organization resource already exists", code=409) if children: organization.children.add(*children, bulk=True) if publishers: organization.publishers.add(*publishers, bulk=True) return organization def update(self, instance: Organization, validated_data: Dict): if 'name' in validated_data or 'parent' in validated_data: raise IntegrityError( "fields 'name' and 'parent' are immutable for the organizations resource" ) children = validated_data.pop('children', None) publishers = validated_data.pop('publishers', None) instance.abbreviation = validated_data.get('abbreviation', instance.abbreviation) instance.category = validated_data.get('category', instance.category) instance.href = validated_data.get('href', instance.href) instance.save() if children: instance.children.bulk_update(children, bulk=True, clear=True) else: instance.children.clear(bulk=True) if publishers: instance.publishers.bulk_update(publishers, bulk=True, clear=True) else: instance.publishers.clear(bulk=True) return instance
class MediaTypeSerializer(serializers.HyperlinkedModelSerializer): accepting_endpoints = relations.ResourceRelatedField( queryset=EndPoint.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='mediatype-related', related_link_url_kwarg='pk', self_link_view_name='mediatype-relationships', ) delivering_endpoints = relations.ResourceRelatedField( queryset=EndPoint.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='mediatype-related', related_link_url_kwarg='pk', self_link_view_name='mediatype-relationships', ) included_serializers = { 'accepting_endpoints': 'resolver.serializers.EndPointSerializer', 'delivering_endpoints': 'resolver.serializers.EndPointSerializer', } class Meta: model = MediaType fields = ('url', 'name', 'description', 'accepting_endpoints', 'delivering_endpoints', 'added', 'modified') read_only_fields = ('added', 'modified') meta_fields = ('added', 'modified') def create(self, validated_data: Dict): accepting_endpoints = validated_data.pop('accepting_endpoints', None) delivering_endpoints = validated_data.pop('delivering_endpoints', None) self.is_valid(raise_exception=True) try: mediatype = MediaType.objects.get(**validated_data) except MediaType.DoesNotExist: mediatype = MediaType.create(**validated_data) try: mediatype.save() except IntegrityError as e: raise ResourceExistsError("mediatype resource already exists", code=409) if accepting_endpoints: mediatype.accepting_endpoints.add(*accepting_endpoints, bulk=True) if delivering_endpoints: mediatype.delivering_endpoints.add(*delivering_endpoints, bulk=True) return mediatype def update(self, instance: MediaType, validated_data: Dict): if 'name' in validated_data: raise IntegrityError( "field 'name', is immutable for the mediatypes resource") accepting_endpoints = validated_data.pop('accepting_endpoints', None) delivering_endpoints = validated_data.pop('delivering_endpoints', None) instance.description = validated_data.get('description', instance.description) instance.save() if accepting_endpoints: instance.accepting_endpoints.bulk_update(accepting_endpoints, bulk=True, clear=True) else: instance.accepting_endpoints.clear(bulk=True) if delivering_endpoints: instance.delivering_endpoints.bulk_update(delivering_endpoints, bulk=True, clear=True) else: instance.delivering_endpoints.clear(bulk=True) return instance
class EndPointSerializer(serializers.HyperlinkedModelSerializer): accept_header_media_types = relations.ResourceRelatedField( queryset=MediaType.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='endpoint-related', related_link_url_kwarg='pk', self_link_view_name='endpoint-relationships', ) content_media_types = relations.ResourceRelatedField( queryset=MediaType.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='endpoint-related', related_link_url_kwarg='pk', self_link_view_name='endpoint-relationships', ) request_schema_endpoint = relations.ResourceRelatedField( queryset=MediaType.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='endpoint-related', related_link_url_kwarg='pk', self_link_view_name='endpoint-relationships', ) response_schema_endpoint = relations.ResourceRelatedField( queryset=MediaType.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='endpoint-related', related_link_url_kwarg='pk', self_link_view_name='endpoint-relationships', ) full_path_uri = serializers.CharField() included_serializers = { 'entrypoint': 'resolver.serializers.EntryPointSerializer', 'accept_header_media_types': 'resolver.serializers.MediaTypeSerializer', 'content_media_types': 'resolver.serializers.MediaTypeSerializer', 'request_schema_endpoint': 'resolver.serializers.EndPointSerializer', 'response_schema_endpoint': 'resolver.serializers.EndPointSerializer', } request_methods = MultipleChoiceField(choices=defaults.http_verbs, default=['GET']) class Meta: model = EndPoint fields = ('url', 'entrypoint', 'uri', 'full_path_uri', 'description', 'category', 'request_methods', 'accept_header_media_types', 'content_media_types', 'request_schema_endpoint', 'response_schema_endpoint', 'full_path_uri', 'added', 'modified') read_only_fields = ('full_path_uri', 'added', 'modified') meta_fields = ('added', 'modified') def create(self, validated_data: Dict): accept_header_mediatypes = validated_data.pop( 'accept_header_mediatypes', None) content_mediatypes = validated_data.pop('content_mediatypes', None) request_schema_endpoint = validated_data.pop('request_schema_endpoint', None) response_schema_endpoint = validated_data.pop( 'response_schema_endpoint', None) self.is_valid(raise_exception=True) try: endpoint = EndPoint.objects.get(**validated_data) except EndPoint.DoesNotExist: endpoint = EndPoint.create(**validated_data) try: endpoint.save() except IntegrityError as e: raise ResourceExistsError("endpoint resource already exists", code=409) if accept_header_mediatypes: endpoint.accept_header_mediatypes.add( *accept_header_mediatypes, bulk=True) if content_mediatypes: endpoint.content_mediatypes.add(*content_mediatypes, bulk=True) if request_schema_endpoint: endpoint.request_schema_endpoint.add(*request_schema_endpoint, bulk=True) if response_schema_endpoint: endpoint.response_schema_endpoint.add( *response_schema_endpoint, bulk=True) return endpoint def update(self, instance: EndPoint, validated_data: Dict): if 'entrypoint' in validated_data or 'uri' in validated_data: raise IntegrityError( "fields 'entrypoint', and 'uri' are immutable \ for the endpoints resource") accept_header_media_types = validated_data.pop( 'accept_header_mediatypes', None) content_media_types = validated_data.pop('content_mediatypes', None) request_schema_endpoint = validated_data.pop('request_schema_endpoint', None) response_schema_endpoint = validated_data.pop( 'response_schema_endpoint', None) instance.category = validated_data.get('category', instance.category) instance.request_methods = validated_data.get('request_methods', instance.request_methods) instance.description = validated_data.get('description', instance.description) instance.save() if accept_header_media_types: instance.accept_header_media_types.bulk_update( accept_header_media_types, bulk=True, clear=True) else: instance.accept_header_media_types.clear(bulk=True) if content_media_types: instance.content_media_types.bulk_update(content_media_types, bulk=True, clear=True) else: instance.content_media_types.clear(bulk=True) if request_schema_endpoint: instance.request_schema_endpoint.bulk_update( request_schema_endpoint, bulk=True, clear=True) else: instance.request_schema_endpoint.clear(bulk=True) if content_media_types: instance.response_schema_endpoint.bulk_update( response_schema_endpoint, bulk=True, clear=True) else: instance.response_schema_endpoint.clear(bulk=True) return instance
class EntryPointSerializer(serializers.HyperlinkedModelSerializer): parent = relations.ResourceRelatedField( queryset=EntryPoint.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='entrypoint-related', related_link_url_kwarg='pk', self_link_view_name='entrypoint-relationships', ) publisher = relations.ResourceRelatedField( queryset=Publisher.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='entrypoint-related', related_link_url_kwarg='pk', self_link_view_name='entrypoint-relationships', ) children = relations.ResourceRelatedField( queryset=EntryPoint.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='entrypoint-related', related_link_url_kwarg='pk', self_link_view_name='entrypoint-relationships', ) endpoints = relations.ResourceRelatedField( queryset=EndPoint.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='entrypoint-related', related_link_url_kwarg='pk', self_link_view_name='entrypoint-relationships', ) included_serializers = { 'publisher': 'resolver.serializers.PublisherSerializer', 'endpoints': 'resolver.serializers.EndPointSerializer', 'parent': 'resolver.serializers.EntryPointSerializer', 'children': 'resolver.serializers.EntryPointSerializer', } class Meta: model = EntryPoint fields = ('url', 'parent', 'children', 'publisher', 'name', 'description', 'category', 'href', 'entrypoint_href', 'endpoints', 'added', 'modified') read_only_fields = ('added', 'modified') meta_fields = ('added', 'modified') def create(self, validated_data: Dict): children = validated_data.pop('children', None) publishers = validated_data.pop('publishers', None) endpoints = validated_data.pop('endpoints', None) self.is_valid(raise_exception=True) try: entrypoint = EntryPoint.objects.get(**validated_data) except EntryPoint.DoesNotExist: entrypoint = EntryPoint.create(**validated_data) try: entrypoint.save() except IntegrityError as e: raise ResourceExistsError("entrypoint resource already exists", code=409) if children: entrypoint.children.add(*children, bulk=True) if publishers: entrypoint.publishers.add(*publishers, bulk=True) if endpoints: entrypoint.endpoints.add(*endpoints, bulk=True) return entrypoint def update(self, instance: EntryPoint, validated_data: Dict): if 'parent' in validated_data \ or 'publisher' in validated_data \ or 'href' in validated_data: raise IntegrityError( "fields 'parent', 'publisher', 'href' are immutable \ for the entrypoints resource") children = validated_data.pop('children', None) endpoints = validated_data.pop('endpoints', None) instance.publisher = validated_data.get('publisher', instance.publisher) instance.entrypoint_href = validated_data.get('entrypoint_href', instance.entrypoint_href) instance.name = validated_data.get('name', instance.name) instance.description = validated_data.get('description', instance.description) instance.category = validated_data.get('category', instance.category) instance.save() if children: instance.children.bulk_update(children, bulk=True, clear=True) else: instance.children.clear(bulk=True) if endpoints: instance.children.bulk_update(endpoints, bulk=True, clear=True) else: instance.endpoints.clear(bulk=True) return instance
class PublisherSerializer(serializers.HyperlinkedModelSerializer): parent = relations.ResourceRelatedField( queryset=Publisher.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='publisher-related', related_link_url_kwarg='pk', self_link_view_name='publisher-relationships', ) organization = relations.ResourceRelatedField( queryset=Organization.objects, many=False, read_only=False, required=False, default=None, related_link_view_name='publisher-related', related_link_url_kwarg='pk', self_link_view_name='publisher-relationships', ) children = relations.ResourceRelatedField( queryset=Publisher.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='publisher-related', related_link_url_kwarg='pk', self_link_view_name='publisher-relationships', ) entrypoints = relations.ResourceRelatedField( queryset=EntryPoint.objects, many=True, read_only=False, required=False, default=None, related_link_view_name='publisher-related', related_link_url_kwarg='pk', self_link_view_name='publisher-relationships', ) included_serializers = { 'organization': 'resolver.serializers.OrganizationSerializer', 'entrypoints': 'resolver.serializers.EntryPointSerializer', 'parent': 'resolver.serializers.PublisherSerializer', 'children': 'resolver.serializers.PublisherSerializer', } class Meta: model = Publisher fields = ('url', 'parent', 'children', 'organization', 'entrypoints', 'name', 'category', 'email', 'address', 'href', 'orcid', 'added', 'modified') read_only_fields = ('added', 'modified') meta_fields = ('added', 'modified') def create(self, validated_data: Dict): children = validated_data.pop('children', None) entrypoints = validated_data.pop('entrypoints', None) self.is_valid(raise_exception=True) try: publisher = Publisher.objects.get(**validated_data) except Publisher.DoesNotExist: publisher = Publisher.create(**validated_data) try: publisher.save() except IntegrityError as e: raise ResourceExistsError( "organization resource already exists", code=409) if children: publisher.children.add(*children, bulk=True) if entrypoints: publisher.entrypoints.add(*entrypoints, bulk=True) return publisher def update(self, instance: Publisher, validated_data: Dict): if 'organization' in validated_data or 'parent' in validated_data or 'name' in validated_data: raise IntegrityError( "fields 'organization', 'parent', and 'name' are immutable for the publishers resource" ) children = validated_data.pop('children', None) entrypoints = validated_data.pop('entrypoints', None) instance.category = validated_data.get('category', instance.category) instance.name = validated_data.get('name', instance.name) instance.email = validated_data.get('email', instance.email) instance.address = validated_data.get('address', instance.address) instance.href = validated_data.get('href', instance.href) instance.orcid = validated_data.get('orcid', instance.orcid) instance.save() if children: instance.children.bulk_update(children, bulk=True, clear=True) else: instance.children.clear(bulk=True) if entrypoints: instance.entrypoints.bulk_update(entrypoints, bulk=True, clear=True) else: instance.entrypoints.clear(bulk=True) return instance