-
-
Notifications
You must be signed in to change notification settings - Fork 102
feature: DJango Ninja and drf cleanup #1646
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
base: main
Are you sure you want to change the base?
Changes from all commits
51248a0
5eb2a34
2cd9a71
bc4f8b5
441d6e3
d8e089e
b0a4437
ee9659b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,29 +1,30 @@ | ||||||
"""Issue API.""" | ||||||
|
||||||
from rest_framework import serializers, viewsets | ||||||
from datetime import datetime | ||||||
|
||||||
from django.http import HttpRequest | ||||||
from ninja import Router | ||||||
from pydantic import BaseModel | ||||||
|
||||||
from apps.github.models.issue import Issue | ||||||
|
||||||
router = Router() | ||||||
|
||||||
|
||||||
# Serializers define the API representation. | ||||||
class IssueSerializer(serializers.HyperlinkedModelSerializer): | ||||||
"""Issue serializer.""" | ||||||
class IssueSchema(BaseModel): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why base on this instead of |
||||||
"""Schema for Issue.""" | ||||||
|
||||||
class Meta: | ||||||
model = Issue | ||||||
fields = ( | ||||||
"title", | ||||||
"body", | ||||||
"state", | ||||||
"url", | ||||||
"created_at", | ||||||
"updated_at", | ||||||
) | ||||||
model_config = {"from_attributes": True} | ||||||
|
||||||
body: str | ||||||
created_at: datetime | ||||||
title: str | ||||||
state: str | ||||||
updated_at: datetime | ||||||
url: str | ||||||
|
||||||
# ViewSets define the view behavior. | ||||||
class IssueViewSet(viewsets.ReadOnlyModelViewSet): | ||||||
"""Issue view set.""" | ||||||
|
||||||
queryset = Issue.objects.all() | ||||||
serializer_class = IssueSerializer | ||||||
@router.get("/", response=list[IssueSchema]) | ||||||
def get_issue(request: HttpRequest) -> list[IssueSchema]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be plural and probably |
||||||
"""Get all issues.""" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
return Issue.objects.all() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,25 @@ | ||
"""Label API.""" | ||
|
||
from rest_framework import serializers, viewsets | ||
from django.http import HttpRequest | ||
from ninja import Router | ||
from pydantic import BaseModel | ||
|
||
from apps.github.models.label import Label | ||
|
||
router = Router() | ||
|
||
# Serializers define the API representation. | ||
class LabelSerializer(serializers.HyperlinkedModelSerializer): | ||
"""Label serializer.""" | ||
|
||
class Meta: | ||
model = Label | ||
fields = ( | ||
"name", | ||
"description", | ||
"color", | ||
) | ||
class LabelSchema(BaseModel): | ||
"""Schema for Label.""" | ||
|
||
model_config = {"from_attributes": True} | ||
|
||
# ViewSets define the view behavior. | ||
class LabelViewSet(viewsets.ReadOnlyModelViewSet): | ||
"""Label view set.""" | ||
color: str | ||
description: str | ||
name: str | ||
|
||
queryset = Label.objects.all() | ||
serializer_class = LabelSerializer | ||
|
||
@router.get("/", response=list[LabelSchema]) | ||
def get_label(request: HttpRequest) -> list[LabelSchema]: | ||
"""Get all labels.""" | ||
return Label.objects.all() | ||
abhayymishraa marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,30 @@ | ||
"""Organization API.""" | ||
|
||
from rest_framework import serializers, viewsets | ||
from datetime import datetime | ||
|
||
from django.http import HttpRequest | ||
from ninja import Router | ||
from pydantic import BaseModel | ||
|
||
from apps.github.models.organization import Organization | ||
|
||
router = Router() | ||
|
||
|
||
# Serializers define the API representation. | ||
class OrganizationSerializer(serializers.HyperlinkedModelSerializer): | ||
"""Organization serializer.""" | ||
class OrganizationSchema(BaseModel): | ||
"""Schema for Organization.""" | ||
|
||
class Meta: | ||
model = Organization | ||
fields = ( | ||
"name", | ||
"login", | ||
"company", | ||
"location", | ||
"created_at", | ||
"updated_at", | ||
) | ||
model_config = {"from_attributes": True} | ||
|
||
company: str | ||
created_at: datetime | ||
location: str | ||
login: str | ||
name: str | ||
updated_at: datetime | ||
|
||
# ViewSets define the view behavior. | ||
class OrganizationViewSet(viewsets.ReadOnlyModelViewSet): | ||
"""Organization view set.""" | ||
|
||
queryset = Organization.objects.filter(is_owasp_related_organization=True) | ||
serializer_class = OrganizationSerializer | ||
@router.get("/", response=list[OrganizationSchema]) | ||
def get_organization(request: HttpRequest) -> list[OrganizationSchema]: | ||
"""Get all organizations.""" | ||
return Organization.objects.filter(is_owasp_related_organization=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,29 @@ | ||
"""Release API.""" | ||
|
||
from rest_framework import serializers, viewsets | ||
from datetime import datetime | ||
|
||
from django.http import HttpRequest | ||
from ninja import Router | ||
from pydantic import BaseModel | ||
|
||
from apps.github.models.release import Release | ||
|
||
router = Router() | ||
|
||
|
||
# Serializers define the API representation. | ||
class ReleaseSerializer(serializers.HyperlinkedModelSerializer): | ||
"""Release serializer.""" | ||
class ReleaseSchema(BaseModel): | ||
"""Schema for Release.""" | ||
|
||
class Meta: | ||
model = Release | ||
fields = ( | ||
"name", | ||
"tag_name", | ||
"description", | ||
"created_at", | ||
"published_at", | ||
) | ||
model_config = {"from_attributes": True} | ||
|
||
created_at: datetime | ||
description: str | ||
name: str | ||
published_at: datetime | ||
tag_name: str | ||
|
||
# ViewSets define the view behavior. | ||
class ReleaseViewSet(viewsets.ReadOnlyModelViewSet): | ||
"""Release view set.""" | ||
|
||
queryset = Release.objects.all() | ||
serializer_class = ReleaseSerializer | ||
@router.get("/", response=list[ReleaseSchema]) | ||
def get_release(request: HttpRequest) -> list[ReleaseSchema]: | ||
"""Get all releases.""" | ||
return Release.objects.all() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,28 @@ | ||
"""Repository API.""" | ||
|
||
from rest_framework import serializers, viewsets | ||
from datetime import datetime | ||
|
||
from django.http import HttpRequest | ||
from ninja import Router | ||
from pydantic import BaseModel | ||
|
||
from apps.github.models.repository import Repository | ||
|
||
router = Router() | ||
|
||
|
||
# Serializers define the API representation. | ||
class RepositorySerializer(serializers.HyperlinkedModelSerializer): | ||
"""Repository serializer.""" | ||
class RepositorySchema(BaseModel): | ||
"""Schema for Repository.""" | ||
|
||
class Meta: | ||
model = Repository | ||
fields = ( | ||
"name", | ||
"description", | ||
"created_at", | ||
"updated_at", | ||
) | ||
model_config = {"from_attributes": True} | ||
|
||
created_at: datetime | ||
description: str | ||
name: str | ||
updated_at: datetime | ||
|
||
# ViewSets define the view behavior. | ||
class RepositoryViewSet(viewsets.ReadOnlyModelViewSet): | ||
"""Repository view set.""" | ||
|
||
queryset = Repository.objects.all() | ||
serializer_class = RepositorySerializer | ||
@router.get("/", response=list[RepositorySchema]) | ||
def get_repository(request: HttpRequest) -> list[RepositorySchema]: | ||
"""Get all repositories.""" | ||
return Repository.objects.all() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
"""GitHub API URLs.""" | ||
|
||
from rest_framework import routers | ||
from ninja import Router | ||
|
||
from apps.github.api.issue import IssueViewSet | ||
from apps.github.api.label import LabelViewSet | ||
from apps.github.api.organization import OrganizationViewSet | ||
from apps.github.api.release import ReleaseViewSet | ||
from apps.github.api.repository import RepositoryViewSet | ||
from apps.github.api.user import UserViewSet | ||
from apps.github.api.issue import router as issue_router | ||
from apps.github.api.label import router as label_router | ||
from apps.github.api.organization import router as organization_router | ||
from apps.github.api.release import router as release_router | ||
from apps.github.api.repository import router as repository_router | ||
from apps.github.api.user import router as user_router | ||
|
||
router = routers.SimpleRouter() | ||
router = Router() | ||
|
||
router.register(r"github/issues", IssueViewSet) | ||
router.register(r"github/labels", LabelViewSet) | ||
router.register(r"github/organizations", OrganizationViewSet) | ||
router.register(r"github/releases", ReleaseViewSet) | ||
router.register(r"github/repositories", RepositoryViewSet) | ||
router.register(r"github/users", UserViewSet) | ||
router.add_router(r"/issues", issue_router) | ||
router.add_router(r"/labels", label_router) | ||
router.add_router(r"/organizations", organization_router) | ||
router.add_router(r"/releases", release_router) | ||
router.add_router(r"/repositories", repository_router) | ||
router.add_router(r"/users", user_router) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,49 @@ | ||
"""User API.""" | ||
|
||
from rest_framework import serializers, viewsets | ||
from rest_framework.decorators import action | ||
from rest_framework.response import Response | ||
from datetime import datetime | ||
|
||
from django.http import HttpRequest | ||
from ninja import Router | ||
from ninja.responses import Response | ||
from pydantic import BaseModel | ||
|
||
from apps.github.models.user import User | ||
|
||
router = Router() | ||
|
||
|
||
class UserSchema(BaseModel): | ||
"""Schema for User.""" | ||
|
||
model_config = {"from_attributes": True} | ||
|
||
avatar_url: str | ||
bio: str | ||
company: str | ||
created_at: datetime | ||
email: str | ||
followers_count: int | ||
following_count: int | ||
location: str | ||
login: str | ||
name: str | ||
public_repositories_count: int | ||
title: str | ||
twitter_username: str | ||
updated_at: datetime | ||
url: str | ||
|
||
|
||
@router.get("/", response=list[UserSchema]) | ||
def list_users(request: HttpRequest) -> list[UserSchema]: | ||
"""Get all users.""" | ||
return User.objects.all() | ||
|
||
|
||
# Serializers define the API representation. | ||
class UserSerializer(serializers.HyperlinkedModelSerializer): | ||
"""User serializer.""" | ||
|
||
class Meta: | ||
model = User | ||
fields = ( | ||
"avatar_url", | ||
"bio", | ||
"company", | ||
"email", | ||
"followers_count", | ||
"following_count", | ||
"location", | ||
"login", | ||
"name", | ||
"public_repositories_count", | ||
"title", | ||
"twitter_username", | ||
"url", | ||
"created_at", | ||
"updated_at", | ||
) | ||
|
||
|
||
# ViewSets define the view behavior. | ||
class UserViewSet(viewsets.ReadOnlyModelViewSet): | ||
"""User view set.""" | ||
|
||
queryset = User.objects.all() | ||
serializer_class = UserSerializer | ||
|
||
@action(detail=False, methods=["get"], url_path="login/(?P<login>[^/.]+)") | ||
def get_user_by_login(self, request, login=None): | ||
"""Retrieve a user by their login. | ||
|
||
Args: | ||
request (Request): The HTTP request object. | ||
login (str, optional): The login of the user to retrieve. | ||
|
||
Returns: | ||
Response: The serialized user data or a 404 error if the user is not found. | ||
|
||
""" | ||
try: | ||
user = User.objects.get(login=login) | ||
serializer = self.get_serializer(user) | ||
data = serializer.data | ||
return Response(data) | ||
except User.DoesNotExist: | ||
return Response({"detail": "User not found."}, status=404) | ||
@router.get("/{login}", response=UserSchema) | ||
def get_user(request: HttpRequest, login: str) -> UserSchema | None: | ||
"""Get user by login.""" | ||
try: | ||
return User.objects.get(login=login) | ||
except User.DoesNotExist: | ||
return Response({"detail": "User not found."}, status=200) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is generally 404, something like from ninja.errors import HttpError
@router.get("/{login}", response={200: UserSchema, 404: dict})
def get_user(request: HttpRequest, login: str):
user = User.objects.filter(login=login).first()
if not user:
raise HttpError(404, "User not found")
return user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should add
/v1/
for consistent versioning approach w/ API urls (/api/v1
)