ساخت یک API با Django Rest Framework (DRF): آموزش پروژه محور
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 12 دقیقه

ساخت یک API با Django Rest Framework (DRF): آموزش پروژه محور

ساخت API يکی از نيازهای اصلی در توسعه نرم‌افزارهای امروزی است. بسياری از سرويس‌ها، چه در مقياس کوچک و چه در معماری‌های پيچيده، برای تبادل داده ميان بخش‌های مختلف خود به يک API استاندارد، امن و قابل توسعه متکی هستند. Django Rest Framework يا DRF به عنوان يکی از قدرتمندترين ابزارهای موجود در اکوسيستم Python، اين امکان را فراهم می‌کند که بدون درگيری با پيچيدگی‌های غيرضروری، يک API حرفه‌ای و ساختارمند ايجاد شود.

هدف اين مطلب آموزشی، ارائه يک مسير پروژه‌محور است، مسيری که در آن به جای تمرکز صرف بر مفاهيم تئوريک، يک پروژه واقعی را از مرحله راه‌اندازی تا ساخت endpointهای کاربردی پيش می‌بريم. در اين فرآيند با مفاهيمی مانند Serializer ،View ،ViewSet، احراز هويت، فيلترگذاری، مستندسازی و بهينه‌سازی آشنا می‌شويم و می‌بينيم که چگونه DRF اين مراحل را ساده و منسجم می‌کند.

پيش‌نيازها

برای شروع توسعه يک API با استفاده از Django Rest Framework، لازم است مجموعه‌ای از مهارت‌ها و ابزارهای اوليه در اختيار داشته باشيم تا بتوانيم بدون سردرگمی وارد مراحل عملی شويم. اين بخش به صورت خلاصه و شفاف مواردی را که پيش از آغاز پروژه بايد فراهم کنيم، مشخص می‌کند.

مهارت‌های مورد نياز

  • آشنايی مقدماتی با Python
  • آشنايی کلی با Django و ساختار پروژه‌های آن
  • درک مفاهيم پايه‌ای مربوط به API و HTTP مانند GET ،POST ،PUT و DELETE

ابزارهای مورد نياز

  • Python نصب‌شده روی سيستم
  • pip برای مديريت بسته‌ها
  • يک محيط مجازی برای جداسازی وابستگی‌های پروژه
  • يک ويرايشگر مناسب مانند VS Code يا PyCharm

نسخه‌های مورد استفاده در پروژه

برای جلوگيری از ناسازگاری‌ها، بهتر است نسخه‌های مشخصی از Django و DRF را نصب کنيم. در ادامه مقاله، از نسخه‌های به‌روز و پايدار استفاده خواهد شد تا روند توسعه بدون مشکل پيش برود. با فراهم بودن اين پيش‌نيازها، می‌توانيم وارد مرحله راه‌اندازی محيط توسعه شويم و ساخت پروژه را آغاز کنيم.

ايجاد محيط توسعه

پس از فراهم شدن پيش‌نيازها، نخستين گام برای شروع پروژه، آماده‌سازی محيط توسعه است. هدف از اين مرحله، ايجاد يک ساختار منظم و قابل مديريت برای نصب وابستگی‌ها و اجرای پروژه است تا در ادامه بتوانيم بدون تداخل نسخه‌ها يا بسته‌های سيستمی، توسعه را پيش ببريم.

ايجاد محيط مجازی

استفاده از محيط مجازی باعث می‌شود وابستگی‌های پروژه از ساير پروژه‌ها و بسته‌های نصب‌شده روی سيستم جدا بماند. برای ايجاد آن:

python -m venv venv

و سپس فعال‌سازی:

Windows

venv\Scripts\activate

macOS / Linux

source venv/bin/activate

نصب Django و DRF

پس از فعال شدن محيط مجازی، Django و Django Rest Framework را نصب می‌کنيم:

pip install django djangorestframework

ايجاد پروژه Django

اکنون پروژه اصلی را ايجاد می‌کنيم:

django-admin startproject config

و وارد پوشه پروژه می‌شويم:

cd config

ايجاد يک اپليکيشن برای API

برای سازمان‌دهی بهتر، يک اپليکيشن جداگانه برای API می‌سازيم:

python manage.py startapp api

پس از ساخت اپليکيشن، بايد آن را در بخش INSTALLED_APPS در فايل settings.py اضافه کنيم تا Django آن را شناسايی کند.

طراحی مدل ديتابيس

در اين مرحله ساختار داده‌های پروژه را مشخص می‌کنيم. طراحی صحيح مدل‌ها نقش مهمی در توسعه يک API قابل اعتماد و قابل توسعه دارد، زيرا تمام بخش‌های بعدی مانند Serializerها، Viewها و فيلترگذاری بر اساس همين مدل‌ها شکل می‌گيرند.

تعريف مدل‌ها

برای نمونه، فرض می‌کنيم قصد داريم يک API ساده برای مديريت مطالب یک وبلاگ ايجاد کنيم. در اين صورت می‌توانيم مدلی با ويژگی‌های اصلی مانند عنوان، متن، زمان ايجاد و زمان به‌روزرسانی تعريف کنيم:

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

اجرای migrations

پس از تعريف مدل، بايد تغييرات را به ديتابيس اعمال کنيم:

python manage.py makemigrations
python manage.py migrate

نکات مهم در طراحی مدل

  • انتخاب نوع داده مناسب برای هر فيلد
  • استفاده از auto_now و auto_now_add برای ثبت زمان‌ها
  • تعريف متد str برای نمايش خوانا در بخش مديريت
  • در نظر گرفتن روابط احتمالی مانند ForeignKey يا ManyToMany در پروژه‌های بزرگ‌تر

با تکميل مدل‌ها، ساختار داده‌ای پروژه آماده است و می‌توانيم وارد مرحله بعدی، يعنی ساخت Serializerها شويم تا داده‌ها را برای ارسال و دريافت در API آماده کنيم.

ساخت Serializerها

پس از تعريف مدل‌ها، گام بعدی آماده‌سازی داده‌ها برای ارسال و دريافت از طريق API است. در Django Rest Framework اين وظيفه بر عهده Serializerها قرار دارد. Serializerها داده‌های مدل را به ساختارهای قابل انتقال مانند JSON تبديل می‌کنند و همچنين داده‌های ورودی را اعتبارسنجی کرده و به مدل‌ها برمی‌گردانند.

معرفی مفهوم Serializer

Serializer در DRF نقشی مشابه فرم‌ها در Django دارد، با اين تفاوت که برای کار با داده‌های API طراحی شده است. اين ابزار به ما کمک می‌کند داده‌ها را به شکلی استاندارد و قابل پردازش در اختيار کلاینت قرار دهيم.

ساخت اولين Serializer

برای مدل Article که در بخش قبل تعريف شد، يک Serializer ساده می‌سازيم:

from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'created_at', 'updated_at']

تفاوت ModelSerializer و Serializer

  • ModelSerializer: سريع‌تر و مناسب برای مواردی که مدل مشخص است. فيلدها را به صورت خودکار بر اساس مدل می‌سازد.
  • Serializer: انعطاف‌پذيرتر و مناسب برای زمانی که ساختار داده مستقل از مدل باشد يا نياز به کنترل کامل روی فيلدها داشته باشيم.

اعتبارسنجی داده‌ها

Serializerها امکان تعريف اعتبارسنجی سفارشی را فراهم می‌کنند. برای نمونه:

def validate_title(self, value):
    if len(value) < 5:
        raise serializers.ValidationError("عنوان بايد حداقل 5 کاراکتر باشد")
    return value

نکات مهم

  • Serializerها نقطه اتصال ميان مدل و API هستند
  • اعتبارسنجی داده‌ها بهتر است در Serializer انجام شود
  • استفاده از ModelSerializer در پروژه‌های معمولی سرعت توسعه را بالا می‌برد

با تکميل Serializerها، اکنون می‌توانيم وارد مرحله ساخت Viewها شويم تا منطق پردازش درخواست‌ها را تعريف کنيم.

ساخت Viewها

پس از آماده‌سازی Serializerها، نوبت به تعريف منطق پردازش درخواست‌ها می‌رسد. Viewها در Django Rest Framework مسئول دريافت درخواست، پردازش داده و بازگرداندن پاسخ مناسب هستند. DRF چندين روش برای ساخت View ارائه می‌دهد که هر کدام سطح متفاوتی از انعطاف‌پذيری و سادگی را فراهم می‌کنند.

معرفی APIView

APIView پايه‌ای‌ترين روش برای ساخت View در DRF است. اين کلاس کنترل کامل روی منطق درخواست‌ها را در اختيار ما قرار می‌دهد و برای مواردی مناسب است که نياز به پياده‌سازی رفتارهای سفارشی داريم.

نمونه ساده:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer

class ArticleListAPIView(APIView):
    def get(self, request):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

معرفی Generic Views

Generic Views برای سرعت بخشيدن به توسعه طراحی شده‌اند. اين کلاس‌ها منطق‌های تکراری مانند ليست کردن، ايجاد، به‌روزرسانی و حذف را به صورت آماده ارائه می‌کنند.

نمونه:

from rest_framework import generics
from .models import Article
from .serializers import ArticleSerializer

class ArticleListCreateView(generics.ListCreateAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

معرفی ViewSetها

ViewSetها سطح بالاتری از انتزاع را فراهم می‌کنند. به جای تعريف چند View جداگانه برای عمليات مختلف، می‌توانيم همه آن‌ها را در يک کلاس قرار دهيم. اين روش در کنار Routerها ساختار API را بسيار منسجم می‌کند.

نمونه:

from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

انتخاب بهترين روش

  • اگر نياز به کنترل کامل داريد: APIView
  • اگر سرعت توسعه مهم است: Generic Views
  • اگر ساختار استاندارد و قابل توسعه می‌خواهيد: ViewSet

ساخت Router و URLها

پس از تعريف Viewها، نوبت به مشخص کردن مسيرهای دسترسی به API می‌رسد. Django Rest Framework با فراهم کردن Routerها اين فرآيند را ساده و ساختارمند می‌کند. Routerها به صورت خودکار URLهای لازم را برای ViewSetها ايجاد می‌کنند و باعث می‌شوند ساختار API منظم، قابل پيش‌بينی و قابل توسعه باقی بماند.

معرفی Routerها

دو نوع Router پرکاربرد در DRF وجود دارد:

  • SimpleRouter: مسيرهای اصلی CRUD را ايجاد می‌کند
  • DefaultRouter: علاوه بر مسيرهای CRUD، يک مسير برای مستندات مرورگرپذير DRF نيز اضافه می‌کند

اتصال ViewSet به Router

برای مثال، اگر از ArticleViewSet استفاده کرده باشيم، می‌توانيم آن را به Router متصل کنيم:

from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')

افزودن Router به urls.py پروژه

پس از تعريف Router، بايد آن را در فايل urls.py اصلی پروژه قرار دهيم:

from django.urls import path, include
from api.urls import router

urlpatterns = [
    path('api/', include(router.urls)),
]

مزايای استفاده از Router

  • ايجاد خودکار مسيرهای استاندارد
  • کاهش کدهای تکراری
  • ساختار يکپارچه و قابل توسعه
  • مناسب برای پروژه‌های بزرگ با چندين ViewSet

تست API

در اين مرحله، پس از تعريف مدل‌ها، Serializerها، Viewها و مسيرها، زمان آن رسيده است که عملکرد API را بررسی کنيم. تست کردن يک API بخش مهمی از فرآيند توسعه است، زيرا به ما اطمينان می‌دهد که درخواست‌ها به درستی پردازش می‌شوند و پاسخ‌ها مطابق انتظار بازگردانده می‌شوند.

تست با استفاده از DRF Browsable API

يکی از مزيت‌های Django Rest Framework، رابط مرورگرپذير آن است. با اجرای سرور توسعه:

python manage.py runserver

و مراجعه به مسيری مانند:

http://localhost:8000/api/articles/

می‌توانيد ليست داده‌ها را مشاهده کنيد، درخواست‌های POST ارسال کنيد و حتی داده‌ها را ويرايش يا حذف کنيد. اين رابط برای توسعه و تست بسيار کاربردی است.

تست با استفاده از curl

برای تست از طريق خط فرمان می‌توانيد از curl استفاده کنيد. نمونه درخواست GET:

curl http://localhost:8000/api/articles/

نمونه درخواست POST:

curl -X POST -H "Content-Type: application/json" \
-d "{\"title\": \"نمونه\", \"content\": \"متن مقاله\"}" \
http://localhost:8000/api/articles/

تست با Postman

Postman يکی از ابزارهای محبوب برای تست API است. با آن می‌توانيد:

  • درخواست‌های مختلف ارسال کنيد
  • هدرها و پارامترها را مديريت کنيد
  • مجموعه‌ای از تست‌ها را ذخيره و اجرا کنيد

اين ابزار برای پروژه‌های بزرگ و تيمی بسيار مفيد است.

تست با Swagger يا مستندات خودکار

اگر در بخش‌های بعدی مستندسازی را فعال کنيم، می‌توانيم از رابط‌های تعاملی مانند Swagger برای تست API استفاده کنيم. اين رابط‌ها امکان ارسال درخواست و مشاهده پاسخ را در يک محيط گرافيکی فراهم می‌کنند.

نکات مهم در تست

  • بررسی صحت کدهای وضعيت مانند 200، 201، 400 و 404
  • تست ورودی‌های نامعتبر برای اطمينان از عملکرد صحيح اعتبارسنجی
  • بررسی پاسخ‌ها برای مطابقت با ساختار JSON مورد انتظار

احراز هويت و سطح دسترسی

پس از آنکه API به درستی کار کرد، نوبت به يکی از مهم‌ترين بخش‌های هر سرويس می‌رسد: کنترل دسترسی. در يک API واقعی، نمی‌توان همه داده‌ها را بدون محدوديت در اختيار کاربران قرار داد. Django Rest Framework امکانات متنوعی برای احراز هويت و مديريت سطح دسترسی ارائه می‌دهد که در اين بخش به آن‌ها می‌پردازيم.

معرفی روش‌های احراز هويت

DRF چندين روش برای احراز هويت ارائه می‌کند. برخی از مهم‌ترين آن‌ها عبارت‌اند از:

  • Token Authentication
  • Session Authentication
  • JWT Authentication (از طريق ابزارهای جانبی مانند SimpleJWT)

برای پروژه‌های API محور، استفاده از Token يا JWT معمول‌تر است.

فعال‌سازی Token Authentication

برای استفاده از Token Authentication ابتدا بايد بسته مربوط به آن را فعال کنيم:

در فايل settings.py:

INSTALLED_APPS = [
    ...
    'rest_framework.authtoken',
]

سپس migration مربوط به آن را اجرا می‌کنيم:

python manage.py migrate

برای دريافت توکن کاربر:

python manage.py drf_create_token <username>

استفاده از JWT

JWT يکی از محبوب‌ترين روش‌های احراز هويت در APIهای مدرن است. برای استفاده از آن معمولا از بسته SimpleJWT استفاده می‌شود:

pip install djangorestframework-simplejwt

و سپس افزودن آن به تنظيمات:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

تعريف Permissionها

Permissionها مشخص می‌کنند چه کسی به چه داده‌ای دسترسی دارد. DRF چند Permission پيش‌فرض دارد:

  • AllowAny: همه کاربران دسترسی دارند
  • IsAuthenticated: فقط کاربران وارد شده
  • IsAdminUser: فقط ادمين‌ها
  • IsAuthenticatedOrReadOnly: کاربران مهمان فقط می‌توانند داده‌ها را بخوانند

نمونه استفاده در ViewSet:

from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets

class ArticleViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]

ساخت Permission سفارشی

برای کنترل دقيق‌تر سطح دسترسی می‌توانيم Permission سفارشی بسازيم. نمونه ساده:

from rest_framework.permissions import BasePermission

class IsOwner(BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.owner == request.user

نکات مهم

  • احراز هويت و Permissionها بايد متناسب با نوع پروژه انتخاب شوند
  • برای APIهای عمومی، محدوديت‌های مناسب برای عمليات حساس ضروری است
  • JWT برای پروژه‌های موبايل و SPA بسيار مناسب است

فيلترگذاری، جستجو و مرتب‌سازی

يکی از ويژگی‌های مهم در طراحی APIهای حرفه‌ای، امکان جستجو، فيلتر کردن و مرتب‌سازی داده‌هاست. Django Rest Framework ابزارهای قدرتمندی برای اين منظور فراهم می‌کند تا کاربران بتوانند داده‌ها را بر اساس نياز خود دريافت کنند. اين قابليت‌ها به‌ويژه در پروژه‌های بزرگ و داده‌محور اهميت زيادی دارند.

فعال‌سازی فيلترگذاری

برای استفاده از فيلترگذاری، ابتدا بايد بسته django-filter را نصب کنيم:

pip install django-filter

سپس آن را در تنظيمات فعال می‌کنيم:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend'
    ]
}

افزودن فيلتر به View

برای مثال، اگر بخواهيم امکان فيلتر کردن مقالات بر اساس عنوان را فراهم کنيم:

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['title']

جستجو در داده‌ها

برای فعال‌سازی جستجو، بايد SearchFilter را اضافه کنيم:

from rest_framework.filters import SearchFilter

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [SearchFilter]
    search_fields = ['title', 'content']

اکنون کاربران می‌توانند با استفاده از پارامتر search جستجو انجام دهند:

/api/articles/?search=نمونه

مرتب‌سازی داده‌ها

برای مرتب‌سازی، از OrderingFilter استفاده می‌کنيم:

from rest_framework.filters import OrderingFilter

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ['created_at', 'title']

نمونه درخواست:

/api/articles/?ordering=created_at

يا برای مرتب‌سازی نزولی:

/api/articles/?ordering=-created_at

نکات مهم

  • فيلترگذاری و جستجو بايد متناسب با نيازهای واقعی پروژه انتخاب شوند
  • استفاده از فيلدهای مناسب در search باعث بهبود کارايی می‌شود
  • مرتب‌سازی بهتر است فقط روی فيلدهای شاخص انجام شود

بهينه‌سازی API

پس از آنکه API به‌درستی کار کرد و امکاناتی مانند فيلترگذاری و جستجو به آن افزوده شد، نوبت به بهينه‌سازی عملکرد می‌رسد. در پروژه‌های واقعی، به‌ويژه زمانی که حجم داده‌ها افزايش می‌يابد يا تعداد درخواست‌ها بالا می‌رود، بهينه‌سازی نقش مهمی در سرعت، کارايی و تجربه کاربری ايفا می‌کند. Django و DRF ابزارهای متعددی برای بهبود عملکرد ارائه می‌دهند که در اين بخش به مهم‌ترين آن‌ها می‌پردازيم.

استفاده از select_related و prefetch_related

يکی از رايج‌ترين دلايل کندی API، تعداد زياد کوئری‌های ديتابيس است. برای کاهش تعداد کوئری‌ها، می‌توانيم از اين دو متد استفاده کنيم:

  • select_related برای روابط ForeignKey
  • prefetch_related برای روابط ManyToMany يا مجموعه‌ای از آبجکت‌ها

نمونه:

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.select_related('category').all()
    serializer_class = ArticleSerializer

مديريت pagination

بازگرداندن حجم زيادی از داده‌ها در يک درخواست می‌تواند باعث کاهش سرعت API شود. DRF امکان صفحه‌بندی داده‌ها را فراهم می‌کند:

در settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
}

استفاده از caching

برای داده‌هایی که تغيير کمی دارند، می‌توانيم از کش استفاده کنيم تا پاسخ‌ها سريع‌تر بازگردانده شوند. Django از چندين backend کش پشتيبانی می‌کند، مانند Redis.

نمونه ساده:

from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator

@method_decorator(cache_page(60), name='dispatch')
class ArticleListCreateView(generics.ListCreateAPIView):
    ...

کاهش حجم پاسخ‌ها

در برخی موارد، ارسال همه فيلدهای مدل ضروری نيست. می‌توانيم:

  • Serializerهای سبک‌تر بسازيم
  • فيلدهای غيرضروری را حذف کنيم
  • از Serializerهای متفاوت برای ليست و جزئيات استفاده کنيم

استفاده از throttling

برای جلوگيری از سوءاستفاده و کنترل بار روی سرور، می‌توانيم محدوديت نرخ درخواست‌ها را فعال کنيم:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.UserRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'user': '1000/day',
    }
}

جمع‌بندی

در اين آموزش، مسير ساخت يک API کامل با Django Rest Framework به‌صورت مرحله‌به‌مرحله مرور شد، از راه‌اندازی محيط توسعه و طراحی مدل‌ها تا ساخت Serializer، تعريف Viewها، تنظيم Routerها، تست API، افزودن احراز هويت، فيلترگذاری، بهينه‌سازی و... . نتيجه اين مسير، يک API استاندارد و قابل توسعه است که می‌تواند مبنای ساخت سرويس‌های بزرگ‌تر قرار بگيرد. اين آموزش نقطه شروع خوبی برای ورود به مباحث پيشرفته‌تر مانند مستندسازی، تست خودکار و ديپلوی در محيط‌های واقعی محسوب می‌شود.

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
5 از 1 رای

/@arastoo
ارسطو عباسی
کارشناس تست نرم‌افزار و مستندات

...

دیدگاه و پرسش
برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

ارسطو عباسی

کارشناس تست نرم‌افزار و مستندات