In Django, the choice of how to create views
2024
In Django, the choice of how to create views depends on the complexity of your application, the functionality you need, and your preferred level of abstraction. Below is a detailed comparison of the primary approaches—@api_view
decorator, Generic Views, and ViewSets—with examples and situations where each is suitable:
1. @api_view
Decorator (Function-Based Views)
What it is:
- Provided by Django REST Framework (DRF).
- A decorator to create simple function-based API views that can handle specific HTTP methods like
GET
,POST
, etc.
When to Use:
- For simple or small APIs.
- When you need full control over the request-response cycle.
- When you’re handling a single resource and don’t want to use DRF’s abstraction layers.
Example:
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET', 'POST'])
def product_list(request):
if request.method == 'GET':
products = Product.objects.all()
data = [ { 'title': product.title, 'price': product.price, 'id': product.id } for product in products]
return Response(data)
elif request.method == "POST":
data = request.data ## dictionary
if data:
new_product = Product.objects.create(**data)
return Response({"id": new_product.id, "message":"Sucessfully created"})
Pros:
- Simple and straightforward for small APIs.
- Easy to understand and debug.
- Full control over the logic.
Cons:
- It can become repetitive and verbose for larger projects.
- Lacks reusability and scalability compared to class-based views.
2. Generic Views (Class-Based Views)
What it is:
- DRF’s pre-built class-based views for common patterns like listing, creating, retrieving, updating, and deleting objects.
When to Use:
- When you want to save development time and use DRF’s built-in behavior.
- For CRUD operations on resources.
- When you want a good balance between customization and DRF abstraction.
from rest_framework.generics import ListCreateView, RetrieveUpdateDestoryAPIView
from .models import Product
from .serilizers impor ProductSerilizer
class ListProducts(ListCreateView):
queryset = Product.objects.all()
serializer_class = ProductSerilizer
class PorductDetailedView(RetrieveUpdateDestoryAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
URL mapping
from django.urls import path
from .view import ListProducts, PorductDetailedView
urlpatterns = [
path('products', ListProducts.as_view(), name='product-list-create'),
path('products/<int:pk>', PorductDetailedView.as_view(), name = 'product-detail-update-delete')
]
Pros:
- Saves time by handling common patterns like
GET
,POST
,PUT
, andDELETE
. - Built-in query optimizations and easy integration with serializers.
- Easier to maintain for standard CRUD operations.
Cons:
- Less flexible compared to function-based views.
- Can become harder to debug if too much customization is needed.
3. ViewSets
What it is:
- A higher-level abstraction provided by DRF that combines the logic for handling multiple HTTP methods (e.g.,
list
,create
,retrieve
, etc.) into a single class.
When to Use:
- For complex APIs where resources have multiple endpoints (e.g.,
/products/
and/products/<id>/
). - When you want to utilize DRF’s Router to automatically generate URL routes.
- For APIs that benefit from adhering to RESTful standards.
Example:
from rest_framework.viewsets import ModelViewSet
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerialize
Routing Example:
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet
router = DefaultRouter()
router.register(r'products', ProductViewSet, basename='product')
urlpatterns = [
# Other URLs
] + router.urls
Pros:
- Simplifies API development by managing routing automatically.
- Great for adhering to RESTful design principles.
- Combines functionality for multiple HTTP methods in a single class.
Cons:
- Requires more understanding of DRF abstractions.
- Overkill for very simple APIs.
When to Choose Each
Approach | When to Use |
---|---|
@api_view | – Small, simple APIs. – Full control over logic. – Minimal abstractions are desired. |
Generic Views | – Standard CRUD operations. – Moderate complexity. – When you want to leverage DRF’s built-in behavior. |
ViewSets | – Large, complex APIs. – RESTful endpoints with multiple HTTP methods. – You want to use DRF’s routing system. |
Summary Table
Feature | @api_view | Generic Views | ViewSets |
---|---|---|---|
Ease of Use | Simple | Moderate | Advanced |
Customization | High | Moderate | Low |
Best For | Small APIs | CRUD operations | RESTful APIs with routing |
Routing | Manual | Manual | Automatic (with Router) |
Abstraction Level | Low | Medium | High |
Recommendation
- Start with
@api_view
for learning or very simple APIs. - Use Generic Views for CRUD operations to save time and reduce code.
- Opt for ViewSets when building larger, more complex APIs where you can take advantage of routers.