عالم تطوير واجهات برمجة التطبيقات (APIs) أصبح أكثر أهمية من أي وقت مضى، حيث تعد APIs الجسر الأساسي بين التطبيقات المختلفة. ومع ظهور أدوات متقدمة مثل Django REST Framework (DRF)، أصبح بناء واجهات برمجة قوية ومرنة أسهل وأكثر كفاءة. إذا كنت مطورًا يعمل على إنشاء RESTful APIs باستخدام Django، فإن فهم الفئات المختلفة التي يقدمها DRF، مثل APIView وViewSets، يعتبر خطوة أساسية نحو إنشاء حلول فعالة ومتقنة. في هذا المقال، سنستعرض تفاصيل هذه الفئات، ميزاتها، وأمثلة عملية لاستخدامها، لنساعدك على اختيار الأنسب لمشروعك.
Generic Views:
Django REST framework يوفر مجموعة من الـ Generic Views التي تسهّل إنشاء واجهات برمجية API باستخدام أقل قدر من الكود. إليك شرحًا باللغة العربية لكل منها:
1. CreateAPIView
- تُستخدم لإنشاء كائن جديد في قاعدة البيانات.
- تتيح فقط طريقة الطلب HTTP
POST
.
مثال:
from rest_framework.generics import CreateAPIView
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelCreateView(CreateAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
2. DestroyAPIView
- تُستخدم لحذف كائن معين.
- تتيح فقط طريقة الطلب HTTP
DELETE
.
مثال:
from rest_framework.generics import DestroyAPIView
from .models import MyModel
class MyModelDestroyView(DestroyAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
3. GenericAPIView
- تعتبر كصفّ أساسي يمكن توسيعه لإضافة سلوك مخصص.
- توفر الوظائف الأساسية مثل التعامل مع querysets و serializers.
- تُستخدم عادة كأساس للـ Generic Views الأخرى.
مثال:
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelCustomView(GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def get(self, request, *args, **kwargs):
obj = self.get_object()
serializer = self.get_serializer(obj)
return Response(serializer.data)
4. ListAPIView
- تُستخدم لعرض قائمة من الكائنات.
- تتيح طريقة الطلب HTTP
GET
.
مثال:
from rest_framework.generics import ListAPIView
from .models import MyModel
class MyModelListView(ListAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
5. ListCreateAPIView
- تُستخدم لعرض قائمة الكائنات وأيضًا لإنشاء كائن جديد.
- تتيح طريقتي الطلب HTTP
GET
وPOST
.
مثال:
from rest_framework.generics import ListCreateAPIView
class MyModelListCreateView(ListCreateAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
6. RetrieveAPIView
- تُستخدم لاسترجاع كائن واحد فقط.
- تتيح طريقة الطلب HTTP
GET
.
مثال:
from rest_framework.generics import RetrieveAPIView
class MyModelRetrieveView(RetrieveAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
7. RetrieveDestroyAPIView
- تُستخدم لاسترجاع وحذف كائن واحد.
- تتيح طريقتي الطلب HTTP
GET
وDELETE
.
مثال:
from rest_framework.generics import RetrieveDestroyAPIView
class MyModelRetrieveDestroyView(RetrieveDestroyAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
8. RetrieveUpdateAPIView
- تُستخدم لاسترجاع وتحديث كائن واحد.
- تتيح طريقتي الطلب HTTP
GET
وPUT/PATCH
.
مثال:
from rest_framework.generics import RetrieveUpdateAPIView
class MyModelRetrieveUpdateView(RetrieveUpdateAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
9. RetrieveUpdateDestroyAPIView
- تُستخدم لاسترجاع، تحديث، وحذف كائن واحد.
- تتيح طريقت الطلب HTTP
GET
، وPUT/PATCH
، وDELETE
.
مثال:
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class MyModelRetrieveUpdateDestroyView(RetrieveUpdateDestroyAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
10. UpdateAPIView
- تُستخدم لتحديث كائن معين.
- تتيح طريقتي الطلب HTTP
PUT
وPATCH
.
مثال:
from rest_framework.generics import UpdateAPIView
class MyModelUpdateView(UpdateAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
مزايا Generic Views
- توفر وقتًا كبيرًا أثناء كتابة الكود.
- تُستخدم لإنشاء واجهات برمجية قياسية (CRUD APIs) بسهولة.
- تدعم التخصيص إذا كنت بحاجة إلى وظائف إضافية.
يمكنك اختيار الـ Generic View المناسبة بناءً على الاحتياجات الخاصة بـ API الذي تبنيه.
Mixins:
Django REST Framework توفر mixins وهي مكونات قابلة لإعادة الاستخدام تضيف وظائف محددة لتنفيذ عمليات CRUD. يتم استخدام هذه الميكسينات عادة مع GenericAPIView
لإنشاء عروض (Views) مخصصة تجمع بين سلوكيات معينة. إليك شرحًا للميكسينات التي ذكرتها:
1. CreateModelMixin
- تضيف وظيفة إنشاء كائن جديد باستخدام طريقة الطلب HTTP
POST
. - تُستخدم عادةً مع
GenericAPIView
.
مثال:
from rest_framework.mixins import CreateModelMixin
from rest_framework.generics import GenericAPIView
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelCreateView(CreateModelMixin, GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
2. DestroyModelMixin
- تضيف وظيفة حذف الكائن باستخدام طريقة الطلب HTTP
DELETE
. - تُستخدم عادةً مع
GenericAPIView
.
مثال:
from rest_framework.mixins import DestroyModelMixin
class MyModelDestroyView(DestroyModelMixin, GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
3. ListModelMixin
- توفر وظيفة عرض قائمة بالكائنات باستخدام طريقة الطلب HTTP
GET
. - تُستخدم غالبًا مع
GenericAPIView
.
مثال:
from rest_framework.mixins import ListModelMixin
class MyModelListView(ListModelMixin, GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
4. RetrieveModelMixin
- تضيف وظيفة استرجاع كائن واحد باستخدام طريقة الطلب HTTP
GET
. - تُستخدم بشكل مثالي مع
GenericAPIView
.
مثال:
from rest_framework.mixins import RetrieveModelMixin
class MyModelRetrieveView(RetrieveModelMixin, GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
5. UpdateModelMixin
- تضيف وظيفة تحديث الكائنات باستخدام طريقتي الطلب HTTP
PUT
أوPATCH
. - تُستخدم عادةً مع
GenericAPIView
.
مثال:
from rest_framework.mixins import UpdateModelMixin
class MyModelUpdateView(UpdateModelMixin, GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
مثال على الجمع بين الميكسينات
يمكنك دمج عدة ميكسينات لإنشاء عرض مخصص يجمع بين أكثر من وظيفة.
مثال:
from rest_framework.mixins import (
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
)
from rest_framework.generics import GenericAPIView
class MyModelCustomView(
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
GenericAPIView,
):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
return self.retrieve(request, *args, **kwargs)
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
متى تستخدم الميكسينات؟
- استخدم الميكسينات عندما تحتاج إلى تحكم أكبر وتخصيص للسلوكيات دون كتابة الكود بالكامل يدويًا.
- إذا كنت تحتاج إلى وظائف CRUD بسيطة، فمن الأفضل استخدام العروض الجاهزة مثل
RetrieveUpdateDestroyAPIView
لأنها أكثر اختصارًا وأسهل استخدامًا.
Paginations:
تُعد التقسيم (Pagination) في Django REST Framework وسيلة مهمة للتحكم في عدد السجلات التي يتم إرجاعها في استجابات API، مما يساعد على إدارة مجموعات البيانات الكبيرة بسهولة. فيما يلي شرح لأنواع التقسيم الأساسية:
1. BasePagination
- هي الأساس لجميع أنواع التقسيم في Django REST Framework.
- يمكنك استخدامها لإنشاء تقسيم مخصص يلبي احتياجاتك.
- لا تحتوي على وظائف مدمجة مسبقًا؛ عليك تنفيذ الدوال
paginate_queryset()
وget_paginated_response()
يدويًا.
مثال: تقسيم مخصص باستخدام BasePagination
from rest_framework.pagination import BasePagination
from rest_framework.response import Response
class CustomPagination(BasePagination):
def paginate_queryset(self, queryset, request, view=None):
page_size = 10
page = int(request.query_params.get('page', 1))
start = (page - 1) * page_size
end = start + page_size
self.page = queryset[start:end]
return self.page
def get_paginated_response(self, data):
return Response({
'count': len(self.page),
'results': data
})
2. CursorPagination
- يعتمد على "المؤشر" (Cursor) لتقسيم البيانات.
- مناسب لمجموعات البيانات الكبيرة لأنه يتجنب الحاجة إلى عد السجلات.
- يتطلب وجود حقل فريد للترتيب (مثل
created_at
).
المزايا:
- يُوفر روابط
next
وprevious
للانتقال بين الصفحات. - يضمن تقسيمًا ثابتًا حتى مع تغييرات البيانات الديناميكية.
الإعدادات:
cursor_query_param
: اسم معلمة الطلب للمؤشر (الافتراضي:cursor
).ordering
: الحقل الافتراضي للترتيب (مثل-created_at
).
مثال:
from rest_framework.pagination import CursorPagination
class MyCursorPagination(CursorPagination):
page_size = 5
ordering = '-created_at' # يجب أن يحتوي النموذج على هذا الحقل.
3. LimitOffsetPagination
- يُوفر التحكم في عدد السجلات (
limit
) وموقع البدء (offset
). - مفيد عندما يحتاج العميل إلى التحكم في حجم الصفحة.
المزايا:
- معلمات الطلب:
limit
(الافتراضي: 10)،offset
(الافتراضي: 0).
الإعدادات:
default_limit
: عدد السجلات الافتراضي لكل صفحة.max_limit
: الحد الأقصى لعدد السجلات التي يمكن طلبها.
مثال:
from rest_framework.pagination import LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5
max_limit = 100
4. PageNumberPagination
- يُقسم السجلات إلى صفحات باستخدام أرقام الصفحات.
- يُعتبر النوع الأكثر استخدامًا والأكثر سهولة.
المزايا:
- معلمة الطلب:
page
(الافتراضي: 1). - يُتيح تخصيص
page_size
(عدد السجلات لكل صفحة).
الإعدادات:
page_size
: عدد السجلات لكل صفحة.page_query_param
: معلمة الطلب للصفحة (الافتراضي:page
).page_size_query_param
: تتيح للعميل تحديد حجم الصفحة.max_page_size
: تحدد الحد الأقصى لحجم الصفحة.
مثال:
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 5
page_size_query_param = 'page_size'
max_page_size = 100
إعداد التقسيم عالميًا
لتطبيق التقسيم على مستوى المشروع بالكامل، يمكن ضبطه في ملف settings.py
:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10, # حجم الصفحة الافتراضي
}
كيفية اختيار نوع التقسيم المناسب؟
- BasePagination: إذا كنت بحاجة إلى تنفيذ تقسيم مخصص تمامًا.
- CursorPagination: للمجموعات الكبيرة من البيانات أو البيانات الديناميكية التي تحتاج إلى تقسيم مستقر.
- LimitOffsetPagination: عندما يحتاج العميل إلى التحكم في حجم الصفحة وموقع البدء.
- PageNumberPagination: للتقسيم البسيط والقائم على أرقام الصفحات، وهو الأسهل للاستخدام.
Serializers:
يوفر Django REST Framework (DRF) فئات مختلفة من الـ Serializers لتحويل أنواع البيانات المعقدة (مثل نماذج Django) إلى أنواع بيانات بايثون الأصلية والعكس صحيح. إليك شرحًا لأنواع الـ Serializers التي ذكرتها:
1. BaseSerializer
- الفئة الأساسية (الأقل مستوى) لتصميم Serializer مخصص بالكامل.
- لا تعتمد على نموذج معين أو بنية بيانات، مما يمنحك تحكمًا كاملًا في عمليات التحويل.
- تُستخدم عند الحاجة إلى Serializer مخصص للغاية.
مثال:
from rest_framework.serializers import BaseSerializer
class CustomSerializer(BaseSerializer):
def to_representation(self, instance):
# تحويل الكائن إلى قاموس
return {
'id': instance.id,
'name': instance.name,
'description': instance.description,
}
def to_internal_value(self, data):
# تحويل البيانات المدخلة إلى كائن أو قاموس مُتحقق منه
return {
'name': data.get('name'),
'description': data.get('description'),
}
2. HyperlinkedModelSerializer
- فئة مشتقة من
ModelSerializer
. - تمثل العلاقات باستخدام روابط (URLs) بدلاً من استخدام المفاتيح الأساسية (Primary Keys).
- مناسبة لـ APIs التي تعتمد على علاقات مفرططة (Hyperlinked).
المزايا:
- تضيف حقل
url
تلقائيًا. - تتطلب حقل
HyperlinkedIdentityField
للعلاقات.
مثال:
from rest_framework.serializers import HyperlinkedModelSerializer
from .models import MyModel
class MyModelHyperlinkedSerializer(HyperlinkedModelSerializer):
class Meta:
model = MyModel
fields = ['url', 'id', 'name', 'description']
3. ListSerializer
- تُستخدم مع قوائم الكائنات (Collections).
- تُعتبر الفئة الأساسية عند استخدام خيار
many=True
في Serializers. - تتيح تخصيص سلوك العمل مع قوائم الكائنات.
تخصيص ListSerializer:
from rest_framework.serializers import ListSerializer, Serializer
class MyObjectSerializer(Serializer):
name = serializers.CharField()
class MyListSerializer(ListSerializer):
def update(self, instance, validated_data):
# منطق مخصص لتحديث كائنات متعددة
pass
class CustomListSerializer(Serializer):
child = MyObjectSerializer(many=True, list_serializer_class=MyListSerializer)
4. ModelSerializer
- Serializer عالي المستوى مخصص لنماذج Django.
- يقوم تلقائيًا بإنشاء الحقول بناءً على تعريف النموذج.
- يُبسط المهام الشائعة مثل عمليات CRUD.
المزايا:
- إنشاء الحقول تلقائيًا للسمات والعلاقات.
- يدعم إضافة الحقول والأساليب المخصصة.
مثال:
from rest_framework.serializers import ModelSerializer
from .models import MyModel
class MyModelSerializer(ModelSerializer):
class Meta:
model = MyModel
fields = '__all__' # تضمين جميع الحقول في النموذج
5. Serializer
- الفئة الأكثر استخدامًا لتعريف Serializers.
- تُوفر تحكمًا أكبر مقارنة بـ
ModelSerializer
. - تتطلب تعريف الحقول يدويًا.
المزايا:
- تُستخدم لبيانات غير مرتبطة بالنماذج أو عند الحاجة إلى تخصيص عالي.
- تُتيح تعريف أساليب مخصصة لـ
create
وupdate
.
مثال:
from rest_framework import serializers
class MyCustomSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=100)
description = serializers.CharField()
def create(self, validated_data):
# إنشاء كائن جديد وإرجاعه
return MyModel.objects.create(**validated_data)
def update(self, instance, validated_data):
# تحديث كائن موجود وإرجاعه
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.save()
return instance
مقارنة بين الـ Serializers
Serializer | الاستخدام |
---|---|
BaseSerializer | عند الحاجة إلى التحكم الكامل في عملية التحويل. |
HyperlinkedModelSerializer | لواجهات API التي تستخدم روابط لتمثيل العلاقات. |
ListSerializer | للتعامل مع قوائم الكائنات مع متطلبات مخصصة. |
ModelSerializer | لتبسيط عمليات التحويل للبيانات المعتمدة على نماذج Django. |
Serializer | للاستخدامات العامة أو البيانات غير المرتبطة بالنماذج أو عندما تحتاج إلى منطق مخصص. |
متى تستخدم كل نوع؟
- استخدم BaseSerializer للتحكم الكامل عند تصميم Serializers مخصصة للغاية.
- استخدم ModelSerializer إذا كنت بحاجة إلى واجهات API بسيطة وسريعة تعتمد على النماذج.
- استخدم Serializer للبيانات غير المرتبطة بالنماذج أو عند الحاجة إلى تخصيص كبير.
- استخدم HyperlinkedModelSerializer عند الحاجة إلى تمثيل العلاقات باستخدام روابط.
- استخدم ListSerializer للتعامل مع قوائم الكائنات التي تتطلب سلوكًا مخصصًا.
الخاتمة
سواء كنت تطور واجهات برمجة بيانات بسيطة أو أنظمة API معقدة، فإن Django REST Framework يوفر الأدوات اللازمة لتلبية احتياجاتك. من خلال APIView للمرونة الكاملة، أو ModelViewSet لإنشاء APIs قياسية بسهولة، يمكنك اختيار الفئة المناسبة لكل حالة. إن فهم هذه الفئات واستخدامها بشكل صحيح يساعدك على تحسين كفاءة التطوير وضمان جودة الخدمة التي تقدمها. الآن، حان الوقت لتطبيق هذه المعرفة في مشاريعك القادمة وتحقيق أقصى استفادة من DRF!