Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 62 - REST API Feature #70

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions dbdb/api/pagination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# third-party imports
from rest_framework.pagination import LimitOffsetPagination


# classes

class StandardPagination(LimitOffsetPagination):

default_limit = 10
max_limit = 100

pass
9 changes: 9 additions & 0 deletions dbdb/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# django imports
from django.urls import path
from django.urls import include
from django.conf.urls import url


urlpatterns = [
path('v202004/', include('dbdb.api.v202004.urls')),
]
Empty file added dbdb/api/v202004/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions dbdb/api/v202004/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class ApiV202004Config(AppConfig):
name = 'api_v202004'
177 changes: 177 additions & 0 deletions dbdb/api/v202004/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# stdlib imports
import collections
# third-party imports
from rest_framework import serializers
from rest_framework.reverse import reverse
# project imports
from dbdb.core.models import FeatureOption
from dbdb.core.models import System
from dbdb.core.models import SystemFeature


# abstracts

class AbstractSystemSerializer:


def get_acquired_by(self, obj):
current = obj.get_current()
return current.acquired_by

def get_countries(self, obj):
current = obj.get_current()
return list( map(str, current.countries) )

def get_description(self, obj):
current = obj.get_current()
return current.description

def get_developer(self, obj):
current = obj.get_current()
return current.developer

def get_features(self, obj):
current = obj.get_current()

sysfeatures = SystemFeature.objects \
.filter(system=current) \
.select_related('feature') \
.order_by('feature__slug')

items = collections.OrderedDict()
for sysfeature in sysfeatures:
empty = True

f = {
'name': sysfeature.feature.label,
}

if sysfeature.feature.multivalued:
f['values'] = []
pass
else:
f['value'] = None
pass

if sysfeature.feature.multivalued:
for option in sysfeature.options.all().order_by('slug'):
f['values'].append(option.value)
empty = False
else:
option = sysfeature.options.first()
if option:
f['value'] = option.value
empty = False
pass

if not empty:
items[sysfeature.feature_id] = f
pass

return list( items.values() )

def get_former_names(self, obj):
current = obj.get_current()
return current.former_names if current.former_names else None

def get_history(self, obj):
current = obj.get_current()
return current.history

def get_href(self, obj):
request = self.context['request']
return reverse('system', args=[obj.slug], request=request)

def get_end_year(self, obj):
current = obj.get_current()
return current.end_year

def get_project_types(self, obj):
current = obj.get_current()
return list( map(str, current.project_types.all()) )

def get_urls(self, obj):
current = obj.get_current()
data = {
'docs': None if not current.tech_docs else current.tech_docs,
'homepage': None if not current.url else current.url,
'source': None if not current.source_url else current.source_url,
'wikipedia': None if not current.wikipedia_url else current.wikipedia_url,
}
return data

def get_start_year(self, obj):
current = obj.get_current()
return current.start_year

pass


# serializers

class SystemBriefSerializer(AbstractSystemSerializer, serializers.HyperlinkedModelSerializer):

class Meta:
model = System
fields = [
'url',
'href',
'name',
'start_year',
'end_year',
'description',
'history',
'acquired_by',
'developer',
'project_types',
]

href = serializers.SerializerMethodField()
start_year = serializers.SerializerMethodField()
end_year = serializers.SerializerMethodField()
description = serializers.SerializerMethodField()
history = serializers.SerializerMethodField()
acquired_by = serializers.SerializerMethodField()
developer = serializers.SerializerMethodField()
project_types = serializers.SerializerMethodField()
url = serializers.HyperlinkedIdentityField(lookup_field='slug', read_only=True, view_name='api_v202004:systems_view')

pass

class SystemSerializer(AbstractSystemSerializer, serializers.HyperlinkedModelSerializer):

class Meta:
model = System
fields = [
'href',
'name',
'former_names',
'start_year',
'end_year',
'description',
'history',
'acquired_by',
'developer',
'countries',
'features',
'project_types',
'urls',
'version',
]

href = serializers.SerializerMethodField()
former_names = serializers.SerializerMethodField()
start_year = serializers.SerializerMethodField()
end_year = serializers.SerializerMethodField()
description = serializers.SerializerMethodField()
history = serializers.SerializerMethodField()
acquired_by = serializers.SerializerMethodField()
developer = serializers.SerializerMethodField()
countries = serializers.SerializerMethodField()
features = serializers.SerializerMethodField()
project_types = serializers.SerializerMethodField()
urls = serializers.SerializerMethodField()
version = serializers.IntegerField(source='ver', read_only=True)

pass

17 changes: 17 additions & 0 deletions dbdb/api/v202004/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# django imports
from django.urls import path
# third-party imports
from rest_framework.urlpatterns import format_suffix_patterns
# local imports
from . import views


app_name = 'api_v202004'

urlpatterns = [
path('', views.APIRootView.as_view(), name='root'),
path('systems', views.SystemsView.as_view(), name='systems'),
path('systems/<slug:slug>', views.SystemView.as_view(), name='systems_view'),
]

urlpatterns = format_suffix_patterns(urlpatterns)
59 changes: 59 additions & 0 deletions dbdb/api/v202004/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# django imports
from django.shortcuts import render
# third-party imports
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.views import APIView
# project imports
from dbdb.core.models import System
from dbdb.core.models import SystemVersion
# local imports
from .serializers import SystemBriefSerializer
from .serializers import SystemSerializer


# class based views

class APIRootView(APIView):
"""
Welcome to Database of Databases RESTful API, a public API for accessing out data.
"""

def get(self, request):

data = {
'systems': reverse('api_v202004:systems', request=request)
}

return Response(data)

class SystemView(generics.RetrieveAPIView):

lookup_field = 'slug'
queryset = System.objects.all()
serializer_class = SystemSerializer

pass

class SystemsView(generics.ListAPIView):

queryset = System.objects.all()
serializer_class = SystemBriefSerializer

def paginate_queryset(self, queryset):
if self.paginator is None:
return None

items = self.paginator.paginate_queryset(queryset, self.request, view=self)

# db optimizations - versions
ids = { item.id for item in items }
versions = SystemVersion.objects.filter(system_id__in=ids, is_current=True)
versions_map = { sv.system_id : sv for sv in versions }
for item in items:
item._current = versions_map[item.id]

return items

pass
11 changes: 11 additions & 0 deletions dbdb/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ def current(self):
def get_absolute_url(self):
return reverse('system', args=[self.slug])

def get_current(self):
if not hasattr(self, '_current'):
if self.id is None:
self._current = SystemVersion(system=self)
else:
self._current = self.versions.get(is_current=True)
pass

return self._current

pass

# ==============================================
Expand Down Expand Up @@ -459,6 +469,7 @@ def create_twitter_card(self):
text_size = [0, 0]
for line in name.split("\n"):
line_size = font.getsize(line)

text_size[0] = max(text_size[0], line_size[0])
text_size[1] += line_size[1] + 5

Expand Down
Loading