Django Ninja, une alternative à Django Rest Framework inspirée par FastAPI
Django Ninja
VS
Rest Framework

            app = FastAPI()
            
            
            @app.get("/")
            def read_root():
                return {"Hello": "World"}
            
            
            @app.get("/items/{item_id}")
            def read_item(item_id: int, q: Union[str, None] = None):
                return {"item_id": item_id, "q": q}
          

            import time

            @api.get("/say-after")
            def say_after(request, delay: int, word: str):
                time.sleep(delay)
                return {"saying": word}
	  

            import asyncio

            @api.get("/say-after")
            async def say_after(request, delay: int, word: str):
                await asyncio.sleep(delay)
                return {"saying": word}
	  

            def get_user:
                self.user = UserProfile.objects.filter(
                    name="django"
                ).first()
            await sync_to_async(sync_function)

            ...

            self.user = await UserProfile.objects.filter(
                name="django"
            ).afirst()
          

            def test_profile_detail_view_get(self):
        
                response = self.client.get(self.url)
        
                self.assertEqual(response.status_code, status.HTTP_200_OK)
          

            class ProfileDetailViewTestCase(APITestCase):
                def setUp(self):
                    ...
            
                def test_profile_detail_view_get_self(self):
                    response = self.client.get(self.url)
                    self.assertEqual(
                        response.status_code,
                        status.HTTP_200_OK,
                    )
                    self.assertEqual(loads(response.content), self.dict)
          

                def test_profile_detail_view_get_other_not_followed(self):
                    response = self.client.get(self.other_url)
                    self.assertEqual(
                        response.status_code,
                        status.HTTP_200_OK,
                    )
                    self.assertEqual(
                        loads(response.content),
                        self.other_dict,
                    )
          

                def test_profile_detail_view_get_other_followed(self):
                    self.other_user.followers.add(self.user)
                    response = self.client.get(self.other_url)
                    self.assertEqual(
                        response.status_code,
                        status.HTTP_200_OK,
                    )
                    self.assertEqual(
                        loads(response.content),
                        {**self.other_dict, 'following': True},
                    )
          

            class ProfileDetailView(viewsets.ModelViewSet):
                
                queryset = User.objects.all()
                serializer_class = ProfileSerializer
                permission_classes = [IsAuthenticated]
                lookup_field = 'username'
                http_method_names = ['get', 'post', 'delete']
                
                def get_permissions(self):
                    if self.action == 'list':
                        return [IsAuthenticatedOrReadOnly(),]
                    return super().get_permissions()
          

                def list(self, request, username=None, *args, **kwargs):
                    try: 
                        profile = User.objects.get(username=username)
                        serializer = self.get_serializer(profile)
                        return Response({"profile": serializer.data})
            
                    except Exception:
                        return Response({"errors": {
                            "body": [
                                "Invalid User"
                            ]
                        }})
          

            class ProfileSerializer(serializers.ModelSerializer):
                following = serializers.SerializerMethodField()
                
                class Meta:
                    model = User 
                    fields = ('username', 'bio', 'image', 'following')
          

                def get_following(self, obj):
                    user = self.context.get('request').user
                    if user.is_authenticated:
                        return obj.followers.filter(pk=user.id).exists()
                    return False
          

           @router.get('/profiles/{username}', auth=AuthJWT(pass_even=True), response={200: Any, 401: Any, 404: Any})
           def get_profiles(request, username: str):
               user = get_object_or_404(User, username=username)
               return {
                   'username': user.username,
                   'bio': user.bio,
                   'image': user.image,
                   'following': (
                       request.user is not None
                       and request.user.is_authenticated
                       and user.followers.filter(
                           pk=request.user.id
                       ).exists()
                   )
               }
          

           @router.get('/profiles/{username}', auth=AuthJWT(pass_even=True), response={200: UserResponseSchema, 401: Any, 404: Any})
           def get_profiles(request, username: str):
               return ProfileSchema.from_orm(
                   user = get_object_or_404(User, username=username),
                   context={"request": request},
               ).dict()
          

            class ProfileSchema(ModelSchema):
                following: bool
            
                class Meta:
                    model = User
                    fields = ["username", "bio", "image"]
            
                @staticmethod
                def resolve_following(obj, context) -> str:
                    user = context.get("request").user
                    if user.is_authenticated:
                        return obj.followers.filter(pk=user.id).exists()
                    return False
          

class AuthJWT(HttpBearer, JWTBaseAuthentication):
    openapi_scheme = "token"
    user_model = User

    def __init__(self, *args, pass_even=False, **kwargs):
        self.pass_even = pass_even
        super().__init__(*args, **kwargs)

    def authenticate(self, request, key):
        return (
            self.jwt_authenticate(request, token=key)
            or self.pass_even
        )
          

api = NinjaAPI()
api.add_router("/", "accounts.views.router")
api.add_router("/", "comments.api.router")

...

urlpatterns = [
    path('admin/', admin.site.urls),
    ...
    path(f'{api_prefix}/', include('articles.urls')),
    path(f'{api_prefix}/', api.urls),
]
          
github.com/c4ffein/realworld-django-ninja