فصل ۱۸ — ساخت API با Django REST Framework

۱. مقدمه — چرا API بسازیم؟
APIهایی که ما میسازیم معمولاً برای این کارها استفاده میشوند:
- اپلیکیشن موبایل (Android/iOS) پروژهمون از API ما داده بگیره
- دادهها رو به سرویسهای دیگر بدیم (مثلاً همکاری با یک مارکتپلیس)
- جداسازی Frontend از Backend (مثلاً React یا Vue داده رو از API میگیره)
📌 تفاوت این فصل با فصل قبلی:
- فصل ۱۷ → مصرف APIهای دیگر
- فصل ۱۸ → ساخت API و ارائه داده به دیگران
۲. Django REST Framework چیست؟
Django REST Framework (یا DRF) یک فریمورک قدرتمند روی جنگو هست که:
- کار با JSON رو ساده میکنه
- احراز هویت، فیلتر، صفحهبندی، حقوق دسترسی رو راحت میکنه
- به سرعت میشه CRUD API ساخت
📌 نصب DRF:
pip install djangorestframework
۳. ایجاد پروژه و پیکربندی اولیه DRF
فرض کنیم پروژه فروشگاه داریم.
settings.py
INSTALLED_APPS = [
# اپهای جنگو
'rest_framework',
'store', # اپلیکیشن فروشگاه ما
]
برای این فصل از قبل مدل Product داریم.
۴. مدل نمونه (Product)
# store/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
📌 ما میخوایم این مدل رو به صورت JSON در API بدهیم.
۵. Serializers — تبدیل مدل به JSON
در DRF یک کلاس خاص به اسم Serializer دادههای مدل رو به JSON تبدیل میکنه (و برعکس).
# store/serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__' # همه فیلدهای مدل
📌 ModelSerializer خودش فیلدها رو از مدل میخونه، نیازی نیست دستی تعریف کنیم مگر اینکه بخوایم شخصیسازی کنیم.
۶. اولین API ساده با DRF — Function-based View
# store/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import Product
from .serializers import ProductSerializer
@api_view(['GET'])
def product_list(request):
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
📌 many=True یعنی داریم یک لیست از اشیا رو سریالایز میکنیم.
۷. تنظیم URL برای API
# store/urls.py
from django.urls import path
from .views import product_list
urlpatterns = [
path('api/products/', product_list, name='product_list')
]
۸. Test — نتیجه اولین API
وقتی /api/products/ رو باز کنیم، خروجی JSON میبینیم:
[
{
"id": 1,
"name": "کفش ورزشی",
"price": "50.00",
"description": "مناسب دویدن",
"created_at": "2025-09-27T10:00:00Z"
},
...
]
۹. افزودن API برای جزئیات یک محصول
@api_view(['GET'])
def product_detail(request, pk):
try:
product = Product.objects.get(pk=pk)
except Product.DoesNotExist:
return Response({"error": "محصول یافت نشد"}, status=404)
serializer = ProductSerializer(product)
return Response(serializer.data)
۱۰. ساخت API CRUD کامل با CBV (Class-based Views) — ViewSet
DRF قابلیتهای زیادی داره، یکی از مهمترینهاش ViewSet هست که چند عملیات رو یکجا انجام میده.
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
۱۱. استفاده از Router برای تنظیم خودکار URLها
# store/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet
router = DefaultRouter()
router.register(r'products', ProductViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
📌 با این کد، خودکار مسیرهای زیر ایجاد میشه:
/api/products/→ لیست + ایجاد محصول/api/products/{id}/→ جزئیات + ویرایش + حذف
۱۲. افزودن Pagination (صفحهبندی) به API
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 5
}
📌 حالا /api/products/ به جای کل لیست، داده رو صفحهبندی میکنه:
{
"count": 20,
"next": "http://localhost:8000/api/products/?page=2",
"previous": null,
"results": [...]
}
۱۳. افزودن قابلیت جستجو و فیلتر
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter'
],
'SEARCH_PARAM': 'q',
}
# views.py
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
search_fields = ['name', 'description']
ordering_fields = ['price', 'created_at']
📌 حالا /api/products/?q=کفش جستجو میکنه، و /api/products/?ordering=-price مرتبسازی نزولی قیمت رو انجام میده.
۱۴. احراز هویت (Authentication)
برای حفاظت از API میتونیم روشهای مختلف بذاریم:
- Token Authentication
- OAuth2 / JWT
نمونه Token Authentication:
pip install djangorestframework-authtoken
# settings.py
INSTALLED_APPS += ['rest_framework.authtoken']
REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = [
'rest_framework.authentication.TokenAuthentication',
]
📌 الان برای درخواست باید Header:
Authorization: Token your_token_here
بفرستیم.
۱۵. مدیریت دسترسی (Permissions)
DRF میتونه تعیین کنه چه کسی میتونه چه کاری انجام بده.
from rest_framework.permissions import IsAuthenticated
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
permission_classes = [IsAuthenticated]
📌 الان فقط کاربر لاگینشده میتونه API رو استفاده کنه.
۱۶. سناریوی واقعی — API فروشگاه آنلاین
مسیرها:
/api/products/→ لیست همه محصولات (GET)، افزودن محصول (POST)/api/products/{id}/→ جزئیات محصول (GET)، ویرایش (PUT/PATCH)، حذف (DELETE)- جستجو (
?q=text) - مرتبسازی (
?ordering=priceیا?ordering=-price) - صفحهبندی خودکار (
?page=2)
مزایای این API:
- میشه ازش توی یک اپ موبایل استفاده کرد
- میشه به همکارها یا خدمات دیگه داد
- همهچیز استاندارد و ساختاریافته است
۱۷. مشکلات رایج در DRF
| مشکل | علت | راهحل |
|---|---|---|
| JSON ناقص یا خالی | سریالایزر فیلدها رو نپوشش داده | مطمئن شو fields = '__all__' یا دستی همه رو تعریف کردی |
| 403 Permission Denied | کاربر مجوز نداره یا احراز هویت اشتباهه | بررسی permission_classes و Token |
| API کند | Query زیاد به دیتابیس | استفاده از select_related یا prefetch_related |
۱۸. بهترین روشها (Best Practices)
- استفاده از ViewSet + Router برای راحتی
- اضافه کردن Pagination در همه APIها
- احراز هویت مناسب (Token یا JWT)
- استفاده از throttling برای جلوگیری از سوءاستفاده
- نگهداری API Keys در
.env - تست API با Postman یا ابزارهای مشابه
۱۹. نتیجهگیری فصل ۱۸
در این فصل یاد گرفتیم:
- DRF رو نصب و پیکربندی کنیم
- مدل رو با Serializer به JSON تبدیل کنیم
- API CRUD کامل با ViewSet بسازیم
- Pagination، جستجو، مرتبسازی، احراز هویت و مجوزها اضافه کنیم
- سناریوی واقعی فروشگاه را به صورت API ارائه کنیم