diff --git a/django_api/serializers.py b/django_api/serializers.py index dd3140b0..758e1fad 100644 --- a/django_api/serializers.py +++ b/django_api/serializers.py @@ -1,380 +1,395 @@ """ This is the Open Access Check Tool (OACT). The publication of scientific articles as Open Access (OA), usually in the variants "Green OA" and "Gold OA", allows free access to scientific research results and their largely unhindered dissemination. Often, however, the multitude of available publication conditions makes the decision in favor of a particular journal difficult: requirements of the funding agencies and publication guidelines of the universities and colleges must be carefully compared with the offers of the publishing houses, and separately concluded publication agreements can also offer additional benefits. The "OA Compliance Check Tool" provides a comprehensive overview of the possible publication conditions for a large number of journals, especially for the Swiss university landscape, and thus supports the decision-making process. © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, Scientific Information and Libraries, 2022 See LICENSE.TXT for more details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . """ """ REST API serializers All serializers inherit from WritableNestedModelSerializer to allow writing nested objects through the API as per https://github.com/beda-software/drf-writable-nested and RQLMixin to support the Resource Query Language (RQL) https://django-rql.readthedocs.io/en/latest/ """ from rest_framework import serializers from dj_rql.drf.serializers import RQLMixin from .models import * from drf_writable_nested.serializers import WritableNestedModelSerializer class CountrySerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for Countries """ id = serializers.IntegerField(required=False) name = serializers.CharField(required=False) iso_code = serializers.CharField(required=False) class Meta: model = Country fields = '__all__' depth = 4 class LanguageSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for Languages """ id = serializers.IntegerField(required=False) name = serializers.CharField(required=False) iso_code = serializers.CharField(required=False) class Meta: model = Language fields = '__all__' depth = 4 class PublisherSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for Publishers """ id = serializers.IntegerField(required=False) country = CountrySerializer(required=False, many=True) class Meta: model = Publisher fields = '__all__' depth = 4 class OaSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for OA statuses """ id = serializers.IntegerField(required=False, allow_null=True) description = serializers.CharField(required=False, allow_null=True) subscription = serializers.BooleanField(required=False) accepted_manuscript = serializers.BooleanField(required=False) apc = serializers.BooleanField(required=False) final_version = serializers.BooleanField(required=False) class Meta: model = Oa fields = '__all__' depth = 4 class IssnSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for ISSNs """ id = serializers.IntegerField(required=False) class Meta: model = Issn fields = '__all__' depth = 1 class JournalSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for Journals """ id = serializers.IntegerField(required=False) issn = IssnSerializer(required=False, source='classIssn', many=True) publisher = PublisherSerializer(required=False, many=True) language = LanguageSerializer(required=False, many=True) # allow update via post request --> "oa_status": {2}, # oa_status = serializers.PrimaryKeyRelatedField(queryset=Oa.objects.all()) oa_status = OaSerializer(required=False,allow_null=True) class Meta: model = Journal fields = '__all__' depth = 4 class LicenceSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for Licences """ id = serializers.IntegerField(required=False) name_or_abbrev = serializers.CharField() website = serializers.URLField(allow_null=True, required=False) class Meta: model = Licence fields = '__all__' depth = 4 class Cost_factor_typeSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for cost factor types """ id = serializers.IntegerField(required=False) name = serializers.CharField() class Meta: model = Cost_factor_type fields = '__all__' depth = 4 class VersionSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for article versions """ id = serializers.IntegerField(required=False) description = models.CharField() class Meta: model = Version fields = '__all__' depth = 4 class OrgaSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for organizations """ id = serializers.IntegerField(required=False) country = CountrySerializer(required=False, many=True) class Meta: model = Organization fields = '__all__' depth = 4 class Cost_factorSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for cost factors """ id = serializers.IntegerField(required=False) cost_factor_type = Cost_factor_typeSerializer(required=False, allow_null=True) amount = serializers.IntegerField() symbol = serializers.CharField() comment = serializers.CharField(required=False) class Meta: model = Cost_factor fields = '__all__' depth = 4 class TermSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for terms """ id = serializers.IntegerField(required=False) version = VersionSerializer(required=False, many=True) cost_factor = Cost_factorSerializer(required=False, many=True) licence = LicenceSerializer(required=False, many=True) class Meta: model = Term fields = '__all__' depth = 4 +class TermLightSerializer(WritableNestedModelSerializer, RQLMixin): + """ REST API serializer for terms in writing mode, using IDs for relationships + """ + id = serializers.IntegerField(required=False) + version = serializers.PrimaryKeyRelatedField(queryset=Version.objects.all(), many=True) + cost_factor = serializers.PrimaryKeyRelatedField(queryset=Cost_factor.objects.all(), many=True) + licence = serializers.PrimaryKeyRelatedField(queryset=Licence.objects.all(), many=True) + + class Meta: + model = Term + fields = '__all__' + depth = 4 + + + class ConditionTypeSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for condition types """ id = serializers.IntegerField(required=False) condition_issuer = serializers.CharField() class Meta: model = ConditionType fields = '__all__' depth = 4 class ConditionSubTypeSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for condition subtypes """ id = serializers.IntegerField(required=False) label = serializers.CharField() class Meta: model = ConditionSubType fields = '__all__' depth = 4 class ConditionSetSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for condition sets """ id = serializers.IntegerField(required=False) term = TermSerializer(many=True, read_only=False) condition_type = ConditionTypeSerializer(read_only=False) subtype = ConditionSubTypeSerializer(read_only=False) organization = OrgaSerializer(many=True, read_only=False) journal = JournalSerializer(many=True, read_only=False) comment = serializers.CharField(read_only=False) source = serializers.URLField(read_only=False) class Meta: model = ConditionSet # pre filter for rql # fields = ['id','condition_type','term','journal','organization'] # add for informations purpose fields = '__all__' depth = 4 class JournalIdSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API light-weight serializer for journals, using only the ID. Used by the frontend when building the query """ id = serializers.IntegerField(required=False) # allow update via post request --> "oa_status": {2}, class Meta: model = Journal fields = ['id'] class OrganizationIdSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API light-weight serializer for organizations, using only the ID. For use in other serializers """ id = serializers.IntegerField(required=False) # allow update via post request --> "oa_status": {2}, class Meta: model = Organization fields = ['id'] class ConditionSetIdSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API light-weight serializer for condition sets, using only the ID. For use in other serializers """ id = serializers.IntegerField(required=False) # allow update via post request --> "oa_status": {2}, class Meta: model = ConditionSet fields = ['id'] class ConditionSetLightSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API serializer for condition sets, providing only the information needed in the frontend to improve performance """ id = serializers.IntegerField(required=False) term = TermSerializer(many=True, read_only=False) condition_type = ConditionTypeSerializer(read_only=False) subtype = ConditionSubTypeSerializer(read_only=False) organization = OrgaSerializer(many=True, read_only=False) # No journals in this one. journal = JournalIdSerializer(many=True, read_only=False) comment = serializers.CharField(read_only=False) source = serializers.URLField(read_only=False) class Meta: model = ConditionSet # pre filter for rql # fields = ['id','condition_type','term','journal','organization'] # add for informations purpose fields = ['id', 'condition_type', 'subtype', 'term', 'organization', 'journal', 'comment', 'source'] depth = 4 class JournalLightSerializer(WritableNestedModelSerializer, RQLMixin): """ REST API lighter serializer for journals """ id = serializers.IntegerField(required=False) # allow update via post request --> "oa_status": {2}, oa_status = serializers.PrimaryKeyRelatedField(queryset=Oa.objects.all()) language = serializers.PrimaryKeyRelatedField(queryset=Language.objects.all(), many=True) publisher = serializers.PrimaryKeyRelatedField(queryset=Publisher.objects.all(), many=True) starting_year = serializers.IntegerField(required=False) end_year = serializers.IntegerField(required=False) class Meta: model = Journal fields = ['id', 'name', 'oa_status', 'language', 'publisher', 'starting_year', 'end_year'] depth = 1 class OaSerializer(WritableNestedModelSerializer,RQLMixin): """ REST API serializers for OA statuses """ id = serializers.IntegerField(required=False) status = serializers.CharField(allow_null=True) description = serializers.CharField(allow_null=True) subscription = serializers.BooleanField(required=False) accepted_manuscript = serializers.BooleanField(required=False) apc = serializers.BooleanField(required=False) final_version = serializers.BooleanField(required=False) class Meta: model = Oa fields = '__all__' depth = 4 class OrganizationConditionSerializer(serializers.ModelSerializer, RQLMixin): """ REST API serializers for Organisation-condition connections """ id = serializers.IntegerField(required=False) organization = OrgaSerializer(required=False) condition_set = ConditionSetSerializer(required=False) class Meta: model = OrganizationCondition fields = '__all__' depth = 4 class OrganizationConditionBasicSerializer(serializers.ModelSerializer, RQLMixin): """ REST API serializers for Organisation-condition connections """ id = serializers.IntegerField(required=False) organization = OrganizationIdSerializer(required=False) condition_set = ConditionSetIdSerializer(required=False) valid_from = serializers.DateField(required=False) valid_until = serializers.DateField(required=False) class Meta: model = OrganizationCondition fields = '__all__' depth = 1 class JournalConditionSerializer(serializers.ModelSerializer, RQLMixin): """ REST API serializers for Journal-condition connections """ id = serializers.IntegerField(required=False) journal = JournalSerializer(required=False) condition_set = ConditionSetSerializer(required=False) class Meta: model = JournalCondition fields = '__all__' depth = 4 class JournalConditionBasicSerializer(serializers.ModelSerializer, RQLMixin): """ REST API serializers for minimal Journal-condition connections """ id = serializers.IntegerField(required=False) journal = JournalIdSerializer(required=False) condition_set = ConditionSetIdSerializer(required=False) valid_from = serializers.DateField(required=False) valid_until = serializers.DateField(required=False) class Meta: model = JournalCondition fields = '__all__' depth = 1 diff --git a/django_api/urls.py b/django_api/urls.py index 13d0f107..b329803d 100644 --- a/django_api/urls.py +++ b/django_api/urls.py @@ -1,58 +1,59 @@ """ This is the Open Access Check Tool (OACT). The publication of scientific articles as Open Access (OA), usually in the variants "Green OA" and "Gold OA", allows free access to scientific research results and their largely unhindered dissemination. Often, however, the multitude of available publication conditions makes the decision in favor of a particular journal difficult: requirements of the funding agencies and publication guidelines of the universities and colleges must be carefully compared with the offers of the publishing houses, and separately concluded publication agreements can also offer additional benefits. The "OA Compliance Check Tool" provides a comprehensive overview of the possible publication conditions for a large number of journals, especially for the Swiss university landscape, and thus supports the decision-making process. © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, Scientific Information and Libraries, 2022 See LICENSE.TXT for more details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . """ from django.urls import path, re_path, include from django.conf.urls.static import static from django.conf import settings from .views import * from rest_framework import routers from rest_framework.schemas import get_schema_view router = routers.DefaultRouter() router.register(r'journal', JournalViewSet) router.register(r'journal_light', JournalLightViewSet) router.register(r'organization', OrgaViewSet) router.register(r'funder', FunderViewSet) router.register(r'conditionset', ConditionSetViewSet) router.register(r'conditionset_light', ConditionSetLightViewSet) router.register(r'term', TermViewSet) +router.register(r'term_light', TermLightViewSet) # show table details in the API router.register(r'country', CountryViewSet) router.register(r'language', LanguageViewSet) router.register(r'issn', IssnViewSet) router.register(r'oa', OaViewSet) router.register(r'publisher', PublisherViewSet) router.register(r'version', VersionViewSet) router.register(r'licence', LicenceViewSet) router.register(r'cost_factor_type', Cost_factor_typeViewSet) router.register(r'cost_factor', Cost_factorViewSet) router.register(r'conditiontype', ConditionTypeViewSet) router.register(r'JournalCondition', JournalConditionViewSet) router.register(r'organizationCondition', OrganizationConditionViewSet) router.register(r'organizationConditionBasic', OrganizationConditionBasicViewSet) router.register(r'journalConditionBasic', JournalConditionBasicViewSet) urlpatterns = [ path('', include(router.urls)), path('openapi', get_schema_view( title="OACT API", description="API of the Open Access Check Tool (OACT)", version ="1.0" ), name='openapi-schema'), ] diff --git a/django_api/views.py b/django_api/views.py index 5f44c070..2e8afc29 100644 --- a/django_api/views.py +++ b/django_api/views.py @@ -1,370 +1,377 @@ """ This is the Open Access Check Tool (OACT). The publication of scientific articles as Open Access (OA), usually in the variants "Green OA" and "Gold OA", allows free access to scientific research results and their largely unhindered dissemination. Often, however, the multitude of available publication conditions makes the decision in favor of a particular journal difficult: requirements of the funding agencies and publication guidelines of the universities and colleges must be carefully compared with the offers of the publishing houses, and separately concluded publication agreements can also offer additional benefits. The "OA Compliance Check Tool" provides a comprehensive overview of the possible publication conditions for a large number of journals, especially for the Swiss university landscape, and thus supports the decision-making process. © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, Scientific Information and Libraries, 2022 See LICENSE.TXT for more details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . """ from django.contrib.auth.models import AbstractUser from django.shortcuts import render from django.contrib.auth import authenticate, login, logout from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonResponse from .models import * from .serializers import * from rest_framework import viewsets, filters, generics from django.utils.decorators import method_decorator from django.views.decorators.cache import cache_page from rest_framework.authentication import BasicAuthentication from rest_framework.permissions import IsAuthenticatedOrReadOnly from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework_tracking.mixins import LoggingMixin from itertools import chain from django.db.models import Count, Max from dj_rql.filter_cls import RQLFilterClass from urllib.parse import unquote from datetime import date import ipaddress class JournalViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] search_fields = ['name'] filter_backends = (filters.SearchFilter,) queryset = Journal.objects.all() serializer_class = JournalSerializer class JournalLightViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] search_fields = ['name'] filter_backends = (filters.SearchFilter,) queryset = Journal.objects.all().prefetch_related('publisher', 'language', 'oa_status') serializer_class = JournalLightSerializer @method_decorator(cache_page(4 * 60 * 60)) def dispatch(self, request, *args, **kwargs): # print('dispatch() called') return super().dispatch(request, *args, **kwargs) @method_decorator(cache_page(4 * 60 * 60)) def list(self, request): # print('list() called') serializer = self.serializer_class(self.queryset, many=True) return Response(serializer.data) class OrgaViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrgaSerializer queryset = Organization.objects.filter( is_funder=False ) class ConditionSetFilters(RQLFilterClass): """ API filters for the essential query on ConditionSets Arguments can include a journal id, zero to two organization ids, validity dates and a condition type. Request examples: http://127.0.0.1:8000/api/conditionset/?and(eq(journalcondition.journal.id,3),eq(organizationcondition.organization.id,11),eq(condition_type.id,1)) http://127.0.0.1:8000/api/conditionset/?and(eq(journalcondition.journal.id,14),ne(condition_type.id,2),ge(journalcondition.valid_until,2021-08-20),le(journalcondition.valid_from,2021-08-20),ge(organizationcondition.valid_until,2021-08-20),le(organizationcondition.valid_from,2021-08-20)) """ MODEL = ConditionSet DISTINCT = True FILTERS = ( 'id', { 'namespace': 'journalcondition', 'filters': ['id', 'valid_from', 'valid_until', { 'namespace': 'journal', 'filters': ['id', ], } ], }, { 'namespace': 'organizationcondition', 'filters': ['id', 'valid_from', 'valid_until', { 'namespace': 'organization', 'filters': ['id', ] } ], }, { 'namespace': 'condition_type', 'filters': ['id', ], }, ) class JournalConditionFilters(RQLFilterClass): MODEL = JournalCondition FILTERS = ( 'id', { 'namespace': 'condition_set', 'filters': ['id', ], }, { 'namespace': 'journal', 'filters': ['id', ], }, ) class OrganizationConditionFilters(RQLFilterClass): MODEL = OrganizationCondition FILTERS = ( 'id', { 'namespace': 'condition_set', 'filters': ['id', ], }, { 'namespace': 'organization', 'filters': ['id', ], }, ) class MyLoggingMixin(LoggingMixin): """ Supercharge drf_tracking.LoggingMixin to get the real IP address in the OpenShift infrastructure """ def _get_ip_address(self, request): """Get the remote ip address the request was generated from.""" # print(request.META) ipaddr = request.META.get("X-Real-IP", None) if ipaddr: ipaddr = ipaddr.split(",")[0] else: ipaddr = request.META.get("HTTP_X_FORWARDED_FOR", None) if ipaddr: ipaddr = ipaddr.split(",")[0] else: ipaddr = request.META.get("REMOTE_ADDR", "").split(",")[0] # Account for IPv4 and IPv6 addresses, each possibly with port appended. Possibilities are: # # # :port # []:port # Note that ipv6 addresses are colon separated hex numbers possibles = (ipaddr.lstrip("[").split("]")[0], ipaddr.split(":")[0]) for addr in possibles: try: return str(ipaddress.ip_address(addr)) except ValueError: pass return ipaddr class ConditionSetViewSet(MyLoggingMixin, viewsets.ModelViewSet): """ ViewSet for ConditionSets The QuerySet obtained from the database is annotated to obtain the desired sorting order, i.e. by condition_type, then subtype, then a calculated score so that institutions receive more attention than funders within a given type/subtype """ authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] queryset = ConditionSet.objects.all().annotate(include_funder=Max('organization__is_funder')).order_by('condition_type','subtype', 'include_funder','comment') # queryset = ConditionSet.objects.values('term__version__description') serializer_class = ConditionSetSerializer # serializer_class = ConditionGroupedSerializer rql_filter_class = ConditionSetFilters #.objects.values('term__version.description') class ConditionSetLightViewSet(MyLoggingMixin, viewsets.ModelViewSet): """ Light-weight ViewSet for ConditionSets The QuerySet obtained from the database is annotated to obtain the desired sorting order, i.e. by condition_type, then subtype, then a calculated score so that institutions receive more attention than funders within a given type/subtype """ authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] queryset = ConditionSet.objects.all().annotate(include_funder=Max('organization__is_funder')).order_by('condition_type','subtype','include_funder','comment') serializer_class = ConditionSetLightSerializer rql_filter_class = ConditionSetFilters class FunderViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrgaSerializer queryset = Organization.objects.filter( is_funder=True ) class TermViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = TermSerializer queryset = Term.objects.all() +class TermLightViewSet(viewsets.ModelViewSet): + authentification_classes = (BasicAuthentication,) + permission_classes = [IsAuthenticatedOrReadOnly] + serializer_class = TermLightSerializer + queryset = Term.objects.all() + + class CountryViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = CountrySerializer queryset = Country.objects.all() class LanguageViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = LanguageSerializer queryset = Language.objects.all() class IssnViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = IssnSerializer queryset = Issn.objects.all() class OaViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OaSerializer queryset = Oa.objects.all() class PublisherViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = PublisherSerializer queryset = Publisher.objects.all() class VersionViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = VersionSerializer queryset = Version.objects.all() class LicenceViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = LicenceSerializer queryset = Licence.objects.all() class Cost_factor_typeViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = Cost_factor_typeSerializer queryset = Cost_factor_type.objects.all() class Cost_factorViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = Cost_factorSerializer queryset = Cost_factor.objects.all() class ConditionTypeViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = ConditionTypeSerializer queryset = ConditionType.objects.all() class OrganizationConditionViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrganizationConditionSerializer queryset = OrganizationCondition.objects.all() class JournalConditionViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = JournalConditionSerializer queryset = JournalCondition.objects.all() class OrganizationConditionViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrganizationConditionSerializer queryset = OrganizationCondition.objects.all() class JournalConditionBasicViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = JournalConditionBasicSerializer rql_filter_class = JournalConditionFilters queryset = JournalCondition.objects.all() class OrganizationConditionBasicViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrganizationConditionBasicSerializer rql_filter_class = OrganizationConditionFilters queryset = OrganizationCondition.objects.all() # Count number of different version # OrganizationCondition.objects.annotate(version_count=Count('condition_set__term__version')) # OrganizationCondition.objects # .values('condition_set__term__version') #what to group by # .annotate(version_count=Count('condition_set__term__version')) # what to aggregate # group by version and count # OrganizationCondition.objects.values('condition_set__term__version').annotate(version_count=Count('condition_set__term__version')) # source https://hakibenita.com/django-group-by-sql # https://docs.djangoproject.com/en/3.2/topics/db/aggregation/ # OrganizationCondition.objects.values('condition_set__term__version').filter(organization_id=1).annotate(version_count=Count('condition_set__term__version')) \ No newline at end of file