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