diff --git a/django_api/views.py b/django_api/views.py index 8ec97e5c..b4dc36e6 100644 --- a/django_api/views.py +++ b/django_api/views.py @@ -1,233 +1,235 @@ 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 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 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() serializer_class = JournalLightSerializer class OrgaViewSet(viewsets.ModelViewSet): authentification_classes = (BasicAuthentication,) permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = OrgaSerializer queryset = Organization.objects.filter( is_funder=False ) class ConditionSetFilters(RQLFilterClass): #Frontend api 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 ConditionSetViewSet(viewsets.ModelViewSet): +class ConditionSetViewSet(LoggingMixin, viewsets.ModelViewSet): 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(viewsets.ModelViewSet): +class ConditionSetLightViewSet(LoggingMixin, viewsets.ModelViewSet): 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 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() # 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 diff --git a/django_app/settings.py b/django_app/settings.py index c4441575..0268d271 100644 --- a/django_app/settings.py +++ b/django_app/settings.py @@ -1,172 +1,173 @@ """ Django settings for django_api project. Generated by 'django-admin startproject' using Django 3.1.3. For more information on this file, see https://docs.djangoproject.com/en/3.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.1/ref/settings/ """ import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'SECRET_KEY' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = ['0.0.0.0', '127.0.0.1', ] INTERNAL_IPS = [ # ... '127.0.0.1', # ... ] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'import_export', 'django_api', 'corsheaders', 'rest_framework', 'rql_filter', 'django_extensions', 'debug_toolbar', + 'rest_framework_tracking', # Not necessary at this point but let's keep it as a possible idea # 'inline_actions', ] MIDDLEWARE = [ #'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'django_app.urls' CORS_ORIGIN_ALLOW_ALL = False TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'staticfiles') ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] TEMPLATE_LOADERS = ( ('django.template.loaders.cached.Loader', ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', )), ) WSGI_APPLICATION = 'django_app.wsgi.application' # Database # https://docs.djangoproject.com/en/3.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Europe/Zurich' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # static file for production use only STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['dj_rql.drf.RQLFilterBackend'] } # will this be enough to set 2 validity dates for all journals? DATA_UPLOAD_MAX_NUMBER_FIELDS = 40000 # Provide Django 3.2 with a safe default DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' diff --git a/requirements.txt b/requirements.txt index 755e31f1..02b7b004 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,37 +1,38 @@ asgiref certifi==2020.12.5 chardet==4.0.0 coreschema==0.0.4 Django>=3.2,<4.0 django-coreapi==2.3.0 django-cors-headers==3.6.0 djangorestframework==3.12.2 +drf-api-tracking==1.8.0 idna==2.10 itypes==1.2.0 Jinja2==2.11.2 MarkupSafe==1.1.1 pytz==2020.4 requests==2.25.1 sqlparse==0.4.1 uritemplate==3.0.1 urllib3==1.26.2 Pillow==8.0.1 django-import-export psycopg2-binary>=2.8 django-environ django-mssql mysqlclient==2.0.3 mysql-connector-python whitenoise django-rql django-rql-filter django-extensions django-debug-toolbar Werkzeug sphinx sphinx-rtd-theme myst-parser drf-writable-nested # not necessary for the application, more useful for the data loading scripts ipython nbconvert