feat(api): initial work on API

!1
This commit is contained in:
2024-05-14 09:24:39 +09:30
parent 50cc050adf
commit 102aa981ce
9 changed files with 171 additions and 2 deletions

0
app/api/__init__.py Normal file
View File

6
app/api/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'

View File

@ -0,0 +1,30 @@
from rest_framework import serializers
from access.models import Organization, Team
class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = (
"group_ptr_id",
"name",
)
class OrganizationSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name="_api_organization", format="html"
)
class Meta:
model = Organization
fields = (
"id",
"name",
'url',
)

16
app/api/urls.py Normal file
View File

@ -0,0 +1,16 @@
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import access, index
urlpatterns = [
path("", index.IndexView.as_view(), name='_api_home'),
path("organization/", access.OrganizationList.as_view(), name='_api_orgs'),
path("organization/<int:pk>/", access.OrganizationDetail.as_view(), name='_api_organization'),
path("organization/<int:organization_id>/team/<int:group_ptr_id>/", access.TeamDetail.as_view(), name='_api_team'),
path("organization/team/", access.TeamList.as_view(), name='_api_teams'),
]
urlpatterns = format_suffix_patterns(urlpatterns)

42
app/api/views/access.py Normal file
View File

@ -0,0 +1,42 @@
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from rest_framework import generics
from access.models import Organization, Team
from api.serializers.access import OrganizationSerializer, TeamSerializer
class OrganizationList(PermissionRequiredMixin, LoginRequiredMixin, generics.ListCreateAPIView):
permission_required = 'access.view_organization'
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
def get_view_name(self):
return "Organizations"
class OrganizationDetail(PermissionRequiredMixin, LoginRequiredMixin, generics.RetrieveUpdateDestroyAPIView):
permission_required = 'access.view_organization'
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
def get_view_name(self):
return "Organization"
class TeamList(generics.ListCreateAPIView):
queryset = Team.objects.all()
serializer_class = TeamSerializer
class TeamDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Team.objects.all()
serializer_class = TeamSerializer
lookup_field = 'group_ptr_id'

33
app/api/views/index.py Normal file
View File

@ -0,0 +1,33 @@
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from django.contrib.auth.models import User
from django.utils.safestring import mark_safe
from rest_framework import generics, permissions, routers
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
class IndexView(PermissionRequiredMixin, LoginRequiredMixin, routers.APIRootView):
permission_required = 'access.view_organization'
def get_view_name(self):
return "My API"
def get_view_description(self, html=False) -> str:
text = "My REST API"
if html:
return mark_safe(f"<p>{text}</p>")
else:
return text
def get(self, request, *args, **kwargs):
return Response(
{
"organizations": reverse("_api_orgs", request=request),
"teams": reverse("_api_teams", request=request),
}
)

View File

@ -38,6 +38,8 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework_json_api',
'social_django',
'core.apps.CoreConfig',
'access.apps.AccessConfig',
@ -153,4 +155,36 @@ STATICFILES_DIRS = [
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
SITE_TITLE = "Site Title"
SITE_TITLE = "Site Title"
REST_FRAMEWORK = {
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
'DEFAULT_PARSER_CLASSES': (
'rest_framework_json_api.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework_json_api.renderers.JSONRenderer',
'rest_framework_json_api.renderers.BrowsableAPIRenderer',
),
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
'DEFAULT_FILTER_BACKENDS': (
'rest_framework_json_api.filters.QueryParameterValidationFilter',
'rest_framework_json_api.filters.OrderingFilter',
'rest_framework_json_api.django_filters.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
),
'SEARCH_PARAM': 'filter[search]',
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework_json_api.renderers.JSONRenderer',
),
'TEST_REQUEST_DEFAULT_FORMAT': 'vnd.api+json'
}

View File

@ -23,6 +23,7 @@ from .views import HomeView
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path("api/", include("api.urls")),
path('admin/', admin.site.urls, name='_administration'),
path('account/password_change/', auth_views.PasswordChangeView.as_view(template_name="password_change.html.j2"),
name="change_password"),

View File

@ -1,3 +1,10 @@
Django==5.0.4
Django==5.0.6
django-debug-toolbar==4.3.0
social-auth-app-django==5.4.1
djangorestframework==3.15.1
djangorestframework-jsonapi==7.0.0
# DRF
pyyaml==6.0.1
django-filter==24.2