|
DRF |
Ninja |
| Définition des routes |
ViewSets / Routers |
Décorateurs |
DRF
# serializers.py + views.py + urls.py
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
permission_classes = [IsAuthenticated]
router = DefaultRouter()
router.register(r"items", ItemViewSet)
urlpatterns = router.urls
DRF
class OrderViewSet(viewsets.ModelViewSet):
serializer_class = OrderSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
return Order.objects.filter(owner=self.request.user)
@action(detail=True, methods=["post"],
permission_classes=[IsAdminUser])
def refund(self, request, pk=None):
order = self.get_object()
order.refund()
return Response({"status": "refunded"})
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}
api = NinjaAPI()
@api.get("/items/{item_id}")
def read_item(request, item_id: int):
return {"item_id": item_id}
# urls.py
from django.contrib import admin
from django.urls import path
from ninja import NinjaAPI
api = NinjaAPI()
api.add_router("/items", "myapp.api.router")
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", api.urls),
]
|
DRF |
Ninja |
| Validation |
Serializers |
Pydantic |
DRF
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ["id", "name", "price"]
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = 'John Doe'
signup_ts: Optional[datetime] = None
friends: list[int] = []
external_data = {
'id': '123',
'signup_ts': '2017-06-01 12:22',
'friends': [1, '2', b'3'],
}
user = User(**external_data)
print(user)
#> id=123 name='John Doe'
#> signup_ts=datetime.datetime(2017, 6, 1, 12, 22)
#> friends=[1, 2, 3]
print(user.id)
#> 123
from ninja import ModelSchema
class ItemSchema(ModelSchema):
class Meta:
model = Item
fields = ["id", "name", "price"]
— DRF
Tests existants
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},
)
— DRF
Views
DRF
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()
DRF
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"
]
}})
DRF
class ProfileSerializer(serializers.ModelSerializer):
following = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('username', 'bio', 'image', 'following')
DRF
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: ProfileSchema,
401: Any,
404: Any,
},
)
def get_profiles(request, username: str):
return ProfileSchema.from_orm(
get_object_or_404(User, username=username),
context={"request": request},
)
class ProfileSchema(ModelSchema):
following: bool
class Meta:
model = User
fields = ["username", "bio", "image"]
@staticmethod
def resolve_following(obj, context) -> bool:
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.api.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),
]