في هذا الدرس سنتعلم إيطار العمل Django Rest والذي يعمل مع كل من نظامي التشغيل Windows وmacOS.
الإعدادات الأولية
ستحتاج إلى تثبيت أحدث إصدار من Python. و بمجرد الانتهاء من ذلك، قم بإنشاء دليل على سطح المكتب أو أي مكان أخر يسهل الوصول إليه ثم قم بإعداد البيئة الافتراضية.
# Windows
$ cd onedrive\desktop\code
$ mkdir drf
$ cd drf
$ python -m venv .venv
$ .venv\Scripts\Activate.ps1
(.venv) $
داخل الدليل الجديد، قم بتثبيت django
, djangorestframework
و pygments
.
(.venv) $ python -m pip install django
(.venv) $ python -m pip install djangorestframework
(.venv) $ python -m pip install pygments
إذا قمت بعد ذلك بكتابة الأمر pip freeze
، فسترى جميع الحزم المثبتة على البيئة الافتراضية الخاصة بك :
(.venv) $ pip freeze
asgiref==3.6.0
Django==4.1.5
djangorestframework==3.14.0
Pygments==2.14.0
pytz==2022.7.1
sqlparse==0.4.3
سنطلق على مشروعنا الجديد اسم tutorial
ويوجد بداخله تطبيق يسمى snippets
لواجهة برمجة تطبيقات الويب الخاصة بنا.
يحب إضافة .
في نهاية الأمر اختياري ولكن يوصى به وإلا فسيقوم Django بإنشاء دليل إضافي باستخدام الأمر startproject
.
(.venv) $ django-admin startproject tutorial .
(.venv) $ python manage.py startapp snippets
أضف تطبيق snippets
و rest_framework
إلى INSTALLED_APPS
في ملفنا tutorial/settings.py
.
# tutorial/settings.py
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework", # جديد
"snippets", # جديد
]
النماذج
يعد النموذج مكانًا جيدًا للبدء في أي مشروع جديد. في ملف snippets/models.py
قم بإنشاء نموذج جديد يسمى Snippet
.
# snippets/models.py
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default="")
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(
choices=LANGUAGE_CHOICES, default="python", max_length=100
)
style = models.CharField(choices=STYLE_CHOICES, default="friendly", max_length=100)
class Meta:
ordering = ["created"]
def __str__(self):
return self.title
ثم قم بإنشاء ملف ترحيل أولي وقم بمزامنة قاعدة البيانات لأول مرة.
(.venv) $ python manage.py makemigrations snippets
(.venv) $ python manage.py migrate
نحتاج إلى إضافة بعض البيانات إلى نموذجنا حتى يبدو “حقيقيًا”.
نحتاج أولاً إلى تحديث snippets/admin.py
حتى يظهر التطبيق لوحة التحكم! تمامًا كما هو الحال مع إعداد INSTALLED_APPS
، يجب إضافة التطبيقات بشكل صريح إلى admin.
# snippets/admin.py
from django.contrib import admin
from .models import Snippet
admin.site.register(Snippet)
الآن قم بإنشاء حساب مستخدم متميز لتسجيل الدخول. اتبع جميع التعليمات لإعداد اسم المستخدم والبريد الإلكتروني وكلمة المرور. لقد استخدمت admin
, admin@email.com
, و testpass123
.
(.venv) $ python manage.py createsuperuser
بعد ذلك نقوم بتشغيل خادم الويب المحلي لدينا لأول مرة.
(.venv) $ python manage.py runserver
انتقل إلى صفحة Django الرئيسية على http://127.0.0.1:8000/ للتأكد من أن كل شيء يعمل.

بعد ذلك نتوجه إلى صفحة المسؤول على http://127.0.0.1:8000/admin/. قم بتسجيل الدخول باستخدام حساب المستخدم المتميز الخاص بك.

انقر فوق الزر “+ إضافة” بجوار المقتطفات. وإنشاء مقتطفين جديدين.


انقر فوق زر “حفظ” في الجزء السفلي الأيسر لكل مقتطف. سيكون كلاهما مرئيًا على صفحة المقتطفات الرئيسية.

التسلسل
يقوم Serializer بتحويل حالات النموذج إلى JSON، و هذا هو “السحر” الذي يوفره لنا Django Rest Framework.
المواقع التقليدي هي صفحات HTML وCSS ومحتوى من قاعدة البيانات. لكن واجهة برمجة التطبيقات (API) لا تهتم بذلك: فهي مجرد بيانات أولية عند نقاط النهاية، وهو ما يعني JSON، و خصائص HTTP المصاحبة هي التي تخبر واجهة برمجة التطبيقات (API) بالإجراءات التي يمكن اتخاذها (المزيد حول هذا قريبًا).
قم بإنشاء ملف snippets/serializers.py
جديد وقم بتحديثه على النحو التالي.
يمكننا توسيع ModelSerializer الخاص بـ DRF لإنشاء فئة SnippetSerializer
التي تستخدم نموذجنا وتخرج حقول الجدول.
# snippets/serializers
from rest_framework import serializers
from .models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = (
"id",
"title",
"code",
"linenos",
"language",
"style",
)
نحتاج بعد ذلك إلى عرض يتعامل مع منطق دمج النموذج والمُسلسل وعنوان URL معًا في النهاية.
تمامًا كما يأتي Django التقليدي مع العديد من العروض العامة المستندة إلى الفئات للتعامل مع الوظائف الشائعة، كذلك فإن Django Rest Framework لديه مجموعته الخاصة من العروض العامة القوية المستندة إلى الفئات والتي يمكننا استخدامها.
على وجه التحديد، سنستخدم ListCreateAPIView لإنشاء نقطة نهاية للقراءة والكتابة تسرد جميع مثيلات Snippet المتاحة ثم RetrieveUpdateDestroyAPIView لنقطة نهاية القراءة والكتابة والحذف لكل مقتطف فردي.
# snippets/views.py
from rest_framework import generics
from .models import Snippet
from .serializers import SnippetSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
عناوين URL
الخطوة الأخيرة هي إعداد عناوين URL الخاصة بنا.
في الجزء العلوي من ملف tutorial/urls.py
على مستوى المشروع نكتب مايلي :
# tutorial/urls.py
from django.contrib import admin
from django.urls import include, path # new
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("snippets.urls")), # new
]
ثم قم بإنشاء ملف snippets/urls.py
وأضف الكود التالي:
# snippets/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path("snippets/", views.SnippetList.as_view()),
path("snippets/<int:pk>/", views.SnippetDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
يعد تضمين format_suffix_patterns خيارًا اختياريًا يوفر طريقة بسيطة للإشارة إلى تنسيق ملف محدد لنقطة نهاية URL.
وهذا يعني أن واجهة برمجة التطبيقات الخاصة بنا ستكون قادرة على التعامل مع عناوين URL مثل http://example.com/api/items/4.json و http://example.com/api/items/4.
Browsable API
يأتي Django Rest Framework مزودًا بواجهة برمجة تطبيقات قابلة للتصفح يمكننا استخدامها الآن. تأكد من تشغيل الخادم المحلي.
(.venv) $ python manage.py runserver
نقوم بفتح المتصفح على http://127.0.0.1:8000/snippets/.

يمكننا أيضًا الانتقال إلى عرض تفاصيل لكل مقتطف. على سبيل المثال، المقتطف الأول موجود على http://127.0.0.1:8000/snippets/1/.

للتذكير، يتم تعيين id
تلقائيًا بواسطة Django عند كل إدخال في قاعدة البيانات.
الطلبات والردود
حاليًا، لا يوجد لدى واجهة برمجة التطبيقات الخاصة بنا أي قيود على من يمكنه تعديل المقتطفات أو حذفها. في هذا القسم سوف نتأكد من ذلك:
- ترتبط المقتطفات دائمًا بمنشئ المحتوى.
- يمكن للمستخدمين المصادق عليهم فقط إنشاء مقتطفات.
- لا يجوز لأحد سوى منشئ المقتطف تحديثه أو حذفه.
إضافة معلومات إلى نموذجنا
دعونا أولاً نضيف حقلين إلى فئة نموذج Snippet
الموجودة لدينا: owner
الذي سيمثل المستخدم الذي أنشأ مقتطف التعليمات البرمجية و highlighted
لتخزين تمثيل HTML المميز للتعليمات البرمجية.
نريد أيضًا التأكد من أنه عند حفظ النموذج، نستخدم مكتبة تمييز كود pygments
لملء الحقل المميز لدينا.
لذلك سنحتاج إلى إستدعاء بعض الحزم الإضافية بالإضافة إلى طريقة .save().
# snippets/models.py
from django.db import models
from pygments import highlight # جديد
from pygments.formatters.html import HtmlFormatter # جديد
from pygments.lexers import get_all_lexers, get_lexer_by_name # جديد
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default="")
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(
choices=LANGUAGE_CHOICES, default="python", max_length=100
)
style = models.CharField(choices=STYLE_CHOICES, default="friendly", max_length=100)
owner = models.ForeignKey(
"auth.User", related_name="snippets", on_delete=models.CASCADE
) # جديد
highlighted = models.TextField() # جديد
class Meta:
ordering = ("created",)
def save(self, *args, **kwargs): # جديد
"""
Use the `pygments` library to create a highlighted HTML
representation of the code snippet.
"""
lexer = get_lexer_by_name(self.language)
linenos = "table" if self.linenos else False
options = {"title": self.title} if self.title else {}
formatter = HtmlFormatter(
style=self.style, linenos=linenos, full=True, **options
)
self.highlighted = highlight(self.code, lexer, formatter)
super(Snippet, self).save(*args, **kwargs)
def __str__(self):
return self.title
عادةً ما نقوم بإنشاء عملية ترحيل ومزامنتها لتحديث جداول قاعدة البيانات الخاصة بنا. و نظرًا لأننا أضفنا owner
ولدينا محتوى موجود، فمن السهل حذف قاعدة البيانات والبدء من جديد.
تأكد من إيقاف الخادم المحلي باستخدام Control+c
.
(.venv) $ rm db.sqlite3
(.venv) $ rm -r snippets/migrations
(.venv) $ python manage.py makemigrations snippets
(.venv) $ python manage.py migrate
أعد إنشاء الخطوة السابقة لإنشاء حساب مستخدم متميز جديد، سنحتاج أيضًا إلى حساب مستخدم متميز ثانٍ.
لذا قم بتشغيل createsuperuser
مرتين ثم قم بتشغيل الخادم المحلي.
(.venv) $ python manage.py createsuperuser
(.venv) $ python manage.py createsuperuser
(.venv) $ python manage.py runserver
إفتح صفحة مسؤول Django على http://127.0.0.1:8000/admin/ وقم بتسجيل الدخول باستخدام حساب admin
.
إذا نقرت على رابط Users
، ستتم إعادة توجيهك إلى صفحة المستخدمين و التي ينبغي أن تظهر مستخدمين.

نحن بحاجة إلى إعادة إنشاء مقتطفاتنا أيضًا بعد أن قمنا بحذف قاعدة البيانات الأولية.
أنشئ مقتطفًا جديدًا وحدد Owner
كأحد مستخدمينا. سأقوم بإختيار testuser
.
ولكن هناك مشكلة عندما نحاول “الحفظ”.

لقد حصلنا على خطأ ValidationError
. في الدروس الرسمية يتم استخدام Django Shell لإدخال البيانات، أما نحن فإستخدمنا صفحة admin. لذا فإن الكود الموجود لا يعمل كما هو.
تذكر أن highlighted
يتم تعيينه تلقائيًا بواسطة طريقة save()
المخصصة الخاصة بنا في النموذج، لكن المسؤول لا يعرف ذلك. و هو يتوقع منا إدخال قيمة هنا. و لحل المشكلة قم بتحديث ملف admin.py
الخاص بنا وقم بتعيين highlighted
كحقل للقراءة فقط.
# snippets/admin.py
from django.contrib import admin
from .models import Snippet
class SnippetAdmin(admin.ModelAdmin):
readonly_fields = ("highlighted",)
admin.site.register(Snippet, SnippetAdmin)
حاول النقر على الزر “حفظ” مرة أخرى. و ينبغي أن تعمل هذه المرة.
الخطوة الأخيرة هي النقر على رابط تسجيل الخروج في الركن الأيمن العلوي من صفحة المسؤول.

سنقوم قريبًا بإضافة أذونات إلى واجهة برمجة التطبيقات الخاصة بنا بحيث لا يتمكن سوى المستخدمين المصادقين (المسجلين الدخول) من الوصول.
إضافة نقاط النهاية إلى نماذج المستخدم لدينا
الآن بعد أن أصبح لدينا بعض المستخدمين للعمل معهم، فلنضيف نقاط النهاية لهم إلى واجهة برمجة التطبيقات (API) الخاصة بنا. أضف فئة UserSerializer
جديدة إلى ملف snippets/serializers.py
.
# snippets/serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = (
"id",
"title",
"code",
"linenos",
"language",
"style",
)
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(
many=True, queryset=Snippet.objects.all()
)
class Meta:
model = User
fields = ("id", "username", "snippets")
و نظرًا لأن snippets
هي علاقة عكسية في نموذج User
، فلن يتم تضمينها افتراضيًا باستخدام فئة ModelSerializer
، و لهذا نحتاج إلى إضافة حقل صريح لها.
نحتاج أيضًا إلى إضافة عرضين جديدتين للقراءة فقط لقائمة بجميع المستخدمين وعرض تفصيلي للمستخدمين الفرديين.
لاحظ أننا نستخدم RetrieveAPIView
العام القائم على الفئة لعرض التفاصيل للقراءة فقط. وأننا نقوم باستيراد كل من User
و UserSerializer
في الأعلى.
# snippets/views.py
from django.contrib.auth.models import User # جديد
from rest_framework import generics
from .models import Snippet
from .serializers import SnippetSerializer, UserSerializer # جديد
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class UserList(generics.ListAPIView): # جديد
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView): # جديد
queryset = User.objects.all()
serializer_class = UserSerializer
وأخيرًا، نحتاج إلى إضافة العروض الجديدة إلى واجهة برمجة التطبيقات (API) عن طريق إعداد مسارات URL الخاصة بها. أضف النمط التالي إلى snippets/urls.py
.
# snippets/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path("snippets/", views.SnippetList.as_view()),
path("snippets/<int:pk>/", views.SnippetDetail.as_view()),
path("users/", views.UserList.as_view()), # جديد
path("users/<int:pk>/", views.UserDetail.as_view()), # جديد
]
urlpatterns = format_suffix_patterns(urlpatterns)
ربط المقتطفات بالمستخدمين
لا توجد حاليًا طريقة لربط المستخدم الذي قام بتسجيل الدخول تلقائيًا والذي أنشأ مقتطفًا. يمكننا ضبط هذا تلقائيًا عن طريق تجاوز .perform_create()
في عروض المقتطف الخاصة بنا والتي تتيح لنا تعديل كيفية الحفظ .
أضف الطريقة التالية إلى فئة عرض SnippetList
الموجودة لدينا.
# snippets/views.py
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def perform_create(self, serializer): # جديد
serializer.save(owner=self.request.user)
تحديث التسلسل
الآن بعد أن أصبحت المقتطفات مرتبطة بالمستخدم الذي أنشأها، فلنقم بتحديث SnippetSerializer
ب owner
ليعكس ذلك. تأكد أيضًا من تضمين owner
في قائمة الحقول أيضًا.
# snippets/serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source="owner.username") # جديد
class Meta:
model = Snippet
fields = (
"id",
"title",
"code",
"linenos",
"language",
"style",
"owner",
) # new
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(
many=True, queryset=Snippet.objects.all()
)
class Meta:
model = User
fields = ("id", "username", "snippets")
تتحكم وسيطة source
المستخدمة هنا في السمة المستخدمة لملء الحقل ويمكن أن تشير إلى أي سمة في التسلسل. لاحظ أيضًا أننا نستخدم ReadOnlyField
الذي يكون دائمًا للقراءة فقط؛ ولا يمكن استخدامه لتحديث النموذج عندما يتم تسلسله.
كان بإمكاننا أيضًا استخدامCharField(read_only=True)
لإنجاز نفس الشيء.
إضافة الأذونات المطلوبة للعروض
الآن بعد أن أصبحت مقتطفات التعليمات البرمجية مرتبطة بالمستخدمين، نريد التأكد من أن المستخدمين الذين تمت مصادقتهم فقط هم القادرون على إنشاء مقتطفات التعليمات البرمجية وتحديثها وحذفها.
يأتي Django Rest Framework مزودًا بعدد من فئات الأذونات التي يمكننا استخدامها لتقييد الوصول إلى عرض معين.
سنستخدم هنا IsAuthenticatedOrReadOnly
للتأكد من أن الطلبات المصادق عليها تتمتع بحق الوصول للقراءة والكتابة وأن الطلبات غير المصادق عليها لها حق الوصول للقراءة فقط.
# snippets/views.py
from django.contrib.auth.models import User
from rest_framework import generics, permissions # جديد
from .models import Snippet
from .serializers import SnippetSerializer, UserSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # جديد
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # جديد
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
إضافة تسجيل الدخول إلى واجهة برمجة التطبيقات القابلة للتصفح
انتقل الآن إلى واجهة برمجة التطبيقات القابلة للتصفح لدينا على http://127.0.0.1:8000/snippets/.

و نظرًا لأنه تم تسجيل خروجنا، لاحظ أنك لم تعد قادرًا على إنشاء مقتطفات برمجية جديدة. للقيام بذلك، يجب عليك تسجيل الدخول كمستخدم.
يمكننا إضافة عرض تسجيل الدخول إلى واجهة برمجة التطبيقات القابلة للتصفح عن طريق تحرير URLconf في ملف tutorial/urls.py
على مستوى المشروع. أضف rest_framework.urls
إلى مسار api-auth/
.
# tutorial/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("api-auth/", include("rest_framework.urls")), # جديد
path("", include("snippets.urls")),
]
لاحظ أن المسار الفعلي للمستخدم لا يهم و بدلا من api-auth/
كان بإمكاننا أيضًا استخدام something-else/
.
الشيء المهم هو أنه تم تضمين rest_framework.urls
.
افتح المتصفح مرة أخرى وقم بتحديث الصفحة. سيظهر لك رابط تسجيل الدخول في أعلى يمين الصفحة.

قم بتسجيل الدخول باستخدام حساب المستخدم الخاص بك. ثم انتقل إلى http://127.0.0.1:8000/users/ ولاحظ أن معرفات المقتطفات مرتبطة بكل مستخدم.

لدينا مقتطف واحد فقط، تم إنشاؤه باستخدام حساب المستخدم testuser
ويحتوي على المعرف الأساسي 1. إذا أضفنا مقتطفات إضافية لكل مستخدم، فستظهر هنا أيضًا. لذا فإن الأمور تسير على ما يرام.
أكتفي يهذا القدر ليكون لنا جزء أخر نكمل فيه البقية
اكتشاف المزيد من بايثون العربي
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.