البحث في الموقع
المحتوى عن 'django'''.
-
سنوضح في مقال اليوم الخطوات اللازمة لربط الواجهة الخلفية backend مع الواجهة الأمامية frontend من سلسلة مقالات تطوير تطبيق مدونة حديث باستخدام جانغو وفيو. هذا المقال هو جزء من سلسلة مقالات تتحدث حول كيفية إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue: إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الأول. إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الثاني. إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الثالث. إن الشائع حاليًا في ربط الواجهتين الأمامية والخلفية لتطبيق ما هو استخدام تقنية تسمى REST API. ومصطلح API هو اختصار للواجهة البرمجية للتطبيقات Application Programming Interface، وهي تشير إلى الاتصال بين تطبيقين برمجيين، أما REST فهو اختصار لنقل الحالة التمثيلية Representational State Transfer، وهو يشير إلى بنية محددة يتبعها هذا النوع من الاتصال. يتكون طلب REST API عادةً من نقطة وصول endpoint تتصل مع الخادم، إضافةً إلى طريقة HTTP وترويسة Head وجسم Body. تحتوي الترويسة على عناصر التعريف meta، مثل التخبئة caching واستيثاق المستخدم user authentication واختبار AB، بينما يحتوي الجسم على البيانات التي يريد العميل إرسالها إلى الخادم. ومع ذلك، فإنه ثمة خلل بسيط في REST API، وهو أنه من المستحيل تصميم واجهات برمجية تجلب البيانات التي يحتاجها العميل بالضبط، إذ من الشائع أن تجلب REST API بيانات زائدة أو ناقصة. ولذلك، طُوّرت لغة الاستعلام غراف كيو إل GraphQL بهدف حل هذه المشكلة، إذ تستخدم المخططات schemas للتأكد من جلب البيانات المحددة فقط لكل طلب، وسنرى كيف يحدث ذلك لاحقًا. إعداد غراف كيو إل GraphQL باستخدام جانغو Django لنبدأ بإعداد غراف كيو إل GraphQL في الواجهة الخلفية، ستحتاج إلى تثبيت حزمة جديدة تسمى graphene-django وهي حزمة توفر مجموعة من الأدوات والميزات التي تسهل عملية تطوير واجهات GraphQL داخل تطبيقات Django عبر تفعيل الأمر التالي: pip install graphene-django انتقل بعد ذلك إلى مجلد settings.py وابحث عن المتغير INSTALLED_APPS. يجب عليك إضافة graphene-django داخل المجلد لكي يتمكن جانغو من العثور على هذه الحزمة. INSTALLED_APPS = [ . . . "blog", "graphene_django", ] إعداد graphene-django ما زال هناك بعض المهام التي يجب عليك إنجازها قبل أن تتمكن من استخدام GraphQL. أولاً، ستحتاج إلى إعداد نمط الرابط URL pattern لخدمة الواجهات البرمجية للتطبيقات APIs في GraphQL، والذي يحدد كيفية تطابق عناوين URL مع عرض معين في تطبيق Django ويستخدم لتحويل طلبات المستخدم إلى العرض المناسب لمعالجتها. للقيام بذلك انتقل إلى الملف urls.py وأضف الشيفرة التالية: from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView urlpatterns = [ . . . path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))), ] وبعد ذلك، أنشئ المخططات schemas وحدد لجانغو مكان العثور عليها في مجلد settings.py. تتبع مخططات GraphQL نمطًا يسمح لجانغو بترجمة نماذج قاعدة البيانات database إلى GraphQL وبالعكس، ولنأخذ فيما يلي نموذج الموقع Site model كمثال: class Site(models.Model): name = models.CharField(max_length=200) description = models.TextField() logo = models.ImageField(upload_to='site/logo/') class Meta: verbose_name = 'site' verbose_name_plural = '1. Site' def __str__(self): return self.name أنشئ ملف schema.py داخل مجلد المدونة blog. import graphene from graphene_django import DjangoObjectType from blog import models # Define type class SiteType(DjangoObjectType): class Meta: model = models.Site # The Query class class Query(graphene.ObjectType): site = graphene.Field(types.SiteType) def resolve_site(root, info): return ( models.Site.objects.first() ) كما هو واضح، يُقسم هذا الملف إلى ثلاثة أجزاء. أولًا، يجب عليك استيراد الحزم والنماذج اللازمة. ثم يُصرّح عن صنف SiteType ويُربط مع نموذج الموقع. وأخيرًا، يستخدم الصنف Query الذي يسمح لك باسترداد المعلومات عبر GraphQL API. أما لإنشاء معلومات أو تحديثها، فستحتاج إلى استخدام صنف آخر يُدعى Mutation والذي سنتحدث عنه بالتفصيل في المقال الثالث من السلسلة. توجد الدالة Resolve_site داخل الصنف Query وهي تعمل على استرجاع السجل الأول من النموذج Site model (أي تعيد الكائن الأول الموجود في قاعدة البيانات المرتبطة بهذا النموذج). ترتبط هذه الدالة تلقائيًا مع متغير يحمل نفس الاسم site، هذا يعني أنه عند استدعاء الدالة، ستكون النتيجة متاحة مباشرةً من خلال المتغير site دون الحاجة إلى تحديد اسم جديد له، إذ يعمل هذا الجزء تمامًا مثل Django QuerySet لاسترجاع البيانات من قاعدة البيانات. إذَا عندما تستدعي الدالة Resolve_site فإنها سترجع لك السجل الأول من نموذج Site ووتخزنها في المتغير site تلقائيًا، مما يسهل الوصول إلى هذه البيانات لاحقًا. إنشاء المخططات Schemas يمكنك الآن تكرار نفس الطريقة لجميع النماذج، ولكي تتجنب الحجم الكبير لملف المخطط، يمكنك فصله إلى ثلاثة ملفات، وهي: schema.py types.py queries.py ملف schema.py import graphene from blog import queries schema = graphene.Schema(query=queries.Query) ملف types.py import graphene from graphene_django import DjangoObjectType from blog import models class SiteType(DjangoObjectType): class Meta: model = models.Site class UserType(DjangoObjectType): class Meta: model = models.User class CategoryType(DjangoObjectType): class Meta: model = models.Category class TagType(DjangoObjectType): class Meta: model = models.Tag class PostType(DjangoObjectType): class Meta: model = models.Post queries.py import graphene from blog import models from blog import types # The Query class class Query(graphene.ObjectType): site = graphene.Field(types.SiteType) all_posts = graphene.List(types.PostType) all_categories = graphene.List(types.CategoryType) all_tags = graphene.List(types.TagType) posts_by_category = graphene.List(types.PostType, category=graphene.String()) posts_by_tag = graphene.List(types.PostType, tag=graphene.String()) post_by_slug = graphene.Field(types.PostType, slug=graphene.String()) def resolve_site(root, info): return ( models.Site.objects.first() ) def resolve_all_posts(root, info): return ( models.Post.objects.all() ) def resolve_all_categories(root, info): return ( models.Category.objects.all() ) def resolve_all_tags(root, info): return ( models.Tag.objects.all() ) def resolve_posts_by_category(root, info, category): return ( models.Post.objects.filter(category__slug__iexact=category) ) def resolve_posts_by_tag(root, info, tag): return ( models.Post.objects.filter(tag__slug__iexact=tag) ) def resolve_post_by_slug(root, info, slug): return ( models.Post.objects.get(slug__iexact=slug) ) والآن، يجب عليك إخبار جانغو بمكان العثور على ملف المخطط، لذا انتقل إلى settings.py وأضف الشيفرة التالية: # Configure GraphQL GRAPHENE = { "SCHEMA": "blog.schema.schema", } ولكي تتأكد من عمل المخططات على النحو الصحيح، افتح المتصفح وانتقل إلى http://127.0.0.1:8000/graphql، يجب أن تشاهد واجهة GraphiQL على النحو التالي: لاحظ كيف نسترجع المعلومات في هذا المثال، هذه لغة GraphQL، وهذه هي الطريقة التي سنسترجع بها البيانات في الواجهة الأمامية، والتي سنشرحها لاحقًا. إعداد CORS قبل أن ننتقل إلى الواجهة الأمامية، ثمة شيء يجب الاهتمام به. افتراضيًا، لا يمكن نقل البيانات إلا داخل التطبيق نفسه لأسباب الحماية، ولكننا نحتاج إلى تدفق البيانات بين تطبيقين مختلفين، ولمعالجة هذه المشكلة، يجب تمكين وظيفة CORS، وهي اختصار لـ Cross Origin Resource Sharing والتي تعني مشاركة الموارد ذات الأصول المختلفة. أولاً، ثبِّت حزمة Django-cors-headers. ومن داخل تطبيق الواجهة الخلفية، فعِّل الأمر التالي: pip install django-cors-headers أضف "corsheaders" إلى المتغير INSTALLED_APPS: INSTALLED_APPS = [ . . . "corsheaders", ] ثم أضف "corsheaders.middleware.CorsMiddleware" إلى المتغير MIDDLEWARE لتمكين دعم CORS في تطبيق جانغو: MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", . . . ] وأخيرًا، أضف الشيفرة التالية إلى settings.py: CORS_ORIGIN_ALLOW_ALL = False CORS_ORIGIN_WHITELIST = ("http://localhost:8080",) # Matches the port that Vue.js is using إعداد Apollo باستخدام Vue.js والآن، حان الوقت للانتقال إلى الواجهة الأمامية. أولًا، يجب تثبيت مكتبة Apollo، إذ تتيح لك استخدام GraphQL في تطبيق Vue. ويمكنك تثبيتها من خلال تفعيل الأمر التالي: npm install --save graphql graphql-tag @apollo/client ضمن مجلد src، أنشئ ملف جديد باسم apollo-config.js وأضف له الشيفرة التالية: import { ApolloClient, createHttpLink, InMemoryCache, } from "@apollo/client/core"; // HTTP connection to the API const httpLink = createHttpLink({ uri: "http://127.0.0.1:8000/graphql", // Matches the url and port that Django is using }); // Cache implementation const cache = new InMemoryCache(); // Create the apollo client const apolloClient = new ApolloClient({ link: httpLink, cache, }); ثم انتقل إلى main.js واستورد apolloClient كي تتيح لتطبيقك القدرة على التفاعل مع واجهات GraphQL واسترجاع البيانات بشكل ديناميكي: import { apolloClient } from "@/apollo-config"; createApp(App).use(router).use(apolloClient).mount("#app"); أصبح بإمكانك الآن استخدام لغة GraphQL لاسترجاع البيانات من الواجهة الخلفية، ولتطبيق مثال عملي على ذلك، سننتقل إلى App.vue وهناك سنستعيد اسم موقعنا بكتابة الكود التالي: <template> <div class="container mx-auto max-w-3xl px-4 sm:px-6 xl:max-w-5xl xl:px-0"> <div class="flex flex-col justify-between h-screen"> <header class="flex flex-row items-center justify-between py-10"> <div class="nav-logo text-2xl font-bold"> <router-link to="/" v-if="mySite">{{ mySite.name }}</router-link> </div> . . . </header> . . . </div> </div> </template> <script> import gql from "graphql-tag"; export default { data() { return { mySite: null, }; }, async created() { const siteInfo = await this.$apollo.query({ query: gql` query { site { name } } `, }); this.mySite = siteInfo.data.site; }, }; </script> يُفضِّل البعض إنشاء ملف منفصل لجميع الاستعلامات queries، ومن ثم استيراده إلى ملف فيو كما في الكود التالي: ملف src/queries.js import gql from "graphql-tag"; export const SITE_INFO = gql` query { site { name } } `; ملف App.vue . . . <script> import { SITE_INFO } from "@/queries"; export default { data() { return { mySite: null, }; }, async created() { const siteInfo = await this.$apollo.query({ query: SITE_INFO, }); this.mySite = siteInfo.data.site; }, }; </script> صفحة الصنف Category تبقى لدينا الآن مشكلة من المقال السابق، عندما نستدعي موجه router، فكيف لهذا الموجه أن يعرف الصفحة التي يجب إعادتها؟ فعلى سبيل المثال، عندما نضغط على رابط Category One يجب إرجاع قائمة المنشورات التي تنتمي إلى الصنف الأول Category One، ولكن كيف يمكن للموجه القيام بذلك؟ دعونا نرى مثالًا. أولًا، في ملف router/index.js الذي عرفنا فيه جميع الوجهات لدينا، يجب علينا تعيين جزء من نمط الرابط URL pattern كمتغير. ففي المثال التالي، سيتم تعيين الكلمة بعد /category/ كمتغير Category. وسيكون بالإمكان الوصول إلى هذا المتغير في مكون CategoryView. import { createRouter, createWebHistory } from "vue-router"; . . . const routes = [ { path: "/", name: "Home", component: HomeView, }, { path: "/category/:category", name: "Category", component: CategoryView, }, . . . ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes, }); export default router; وبعد ذلك، في عرض AllCategories (الذي سيُظهر قائمة بجميع التصنيفات)، سنعمل على تمرير بعض المعلومات إلى المتغير Category. <template> <div class="flex flex-col place-content-center place-items-center"> <div class="py-8 border-b-2"> <h1 class="text-5xl font-extrabold">All Categories</h1> </div> <div class="flex flex-wrap py-8"> <router-link v-for="category in this.allCategories" :key="category.name" class=". . ." :to="`/category/${category.slug}`" >{{ category.name }}</router-link > </div> </div> </template> وفي عرض Category يمكننا الوصول إلى المتغير Category باستخدام الخاصية this.$route. <script> // @ is an alias to /src import PostList from "@/components/PostList.vue"; import { POSTS_BY_CATEGORY } from "@/queries"; export default { components: { PostList }, name: "CategoryView", data() { return { postsByCategory: null, }; }, async created() { const posts = await this.$apollo.query({ query: POSTS_BY_CATEGORY, variables: { category: this.$route.params.category, }, }); this.postsByCategory = posts.data.postsByCategory; }, }; </script> وأخيرًا، يمكن استرجاع المنشورات باستخدام الاستعلام POSTS_BY_CATEGORY. export const POSTS_BY_CATEGORY = gql` query ($category: String!) { postsByCategory(category: $category) { title slug content isPublished isFeatured createdAt } } `; ومع هذا المثال، من المفترض أن تكون قادرًا الآن على إنشاء صفحتي المنشور post التي تعرض محتوى منشو أو مقالة معينة، وصفحة الوسم tag التي تظهر قائمة بالمنشورات المرتبطة بوسم معين. إنشاء وتحديث المعلومات باستخدام الطفرات Mutations ذكرنا في المقال السابق من هذه السلسلة أنه يمكننا استخدام الاستعلامات queries لاسترجاع المعلومات من الواجهة الخلفية وإرسالها إلى الواجهة الأمامية. ومع ذلك، من الشائع في تطبيقات الويب الحديثة أن ترسل المعلومات من الواجهة الأمامية إلى الواجهة الخلفية. وللقيام بذلك، لا بُدّ من الحديث عن مفهوم جديد في GraphQL يُسمى الطفرة mutation. ملاحظة: تُستخدم الطفرات mutations لتغيير البيانات في الخادم. فإذا أراد المستخدم مثلًا إضافة أو تحديث أو حذف بيانات عليه أن يستخدم mutation لإرسال طلب بالتعديل المطلوب والخادم يقوم بتحديث البيانات وإرجاع النتيجة. نعود إلى الواجهة الخلفية وننتقل إلى ملف cd في مجلد blog وننشئ ملف باسم Mutations.py. سنكتشف في المثال التالي كيفية نقل البيانات إلى الواجهة الخلفية لإنشاء مستخدم جديد. import graphene from blog import models, types # Mutation sends data to the database class CreateUser(graphene.Mutation): user = graphene.Field(types.UserType) class Arguments: username = graphene.String(required=True) password = graphene.String(required=True) email = graphene.String(required=True) def mutate(self, info, username, password, email): user = models.User( username=username, email=email, ) user.set_password(password) user.save() return CreateUser(user=user) لاحظ في السطر 7 من الكود أعلاه أن UserType مرتبط بنموذج المستخدم User model. أما في الأسطر من 9 إلى 12، فلاحظ أنه لإنشاء مستخدم جديد، يجب إضافة ثلاث عناصر هي اسم المستخدم وكلمة المرور والبريد الإلكتروني. أما الأسطر من 15 إلى 18، فيجب أن تكون واضحة لك، فهي ذات الطريقة التي تنشئ من خلالها عنصرًا جديدًا باستخدام Django QuerySet. السطر 19 مسؤول عن تعيين كلمة المرور، ولأسباب تتعلق الحماية لا يمكنك حفظ كلمة المرور الأصلية للمستخدم في قاعدة البيانات لديك، ويمكن تشفيرها من خلال التابع set_password(). والآن، يجب عليك تضمين ملف Mutation.py في مخطط GraphQL، لذا انتقل إلى schema.py: import graphene from blog import queries, mutations schema = graphene.Schema(query=queries.Query, mutation=mutations.Mutation) ولتتأكد من أنه يعمل على النحو الصحيح، افتح المتصفح وانتقل إلى http://127.0.0.1:8000/graphql للوصول إلى واجهة GraphiQL. mutation { createUser( username: "testuser2022" email: "testuser2022@test.com" password: "testuser2022" ) { user { id username } } } من المفترض أنك تعرف كيفية استخدام ذلك في الواجهة الأمامية. على سبيل المثال: <script> import { USER_SIGNUP } from "@/mutations"; export default { name: "SignUpView", data() {. . .}, methods: { async userSignUp() { // Register user const user = await this.$apollo.mutate({ mutation: USER_SIGNUP, variables: { username: this.signUpDetails.username, email: this.signUpDetails.email, password: this.signUpDetails.password, }, }); // Do something with the variable user . . . }, }, }; </script> src/mutations.js import gql from "graphql-tag"; export const USER_SIGNUP = gql` mutation ($username: String!, $email: String!, $password: String!) { createUser(username: $username, email: $email, password: $password) { user { id username } } } `; استيثاق المستخدم User authentication مع جانغو وفيو جي إس والآن بعد أن تعرفت على كيفية إرسال البيانات إلى الواجهة الخلفية، لن تواجه صعوبةً كبيرةً في استيثاق المستخدم User authentication. في البداية، ستطلب من المستخدم إدخال اسم المستخدم وكلمة المرور الخاصين به وإرسال تلك المعلومات إلى الواجهة الخلفية، ثم في الواجهة الخلفية، سيعثر جانغو على المستخدم بناءً على الاسم، وسيحاول مقارنة كلمة المرور المُدخلة مع كلمة المرور المخزنة في قاعدة البيانات، وإذا تطابقت الكلمتان، سيكون بإمكان المستخدم تسجيل الدخول. ومع ذلك، قد تواجه هذه العملية بعض العقبات في الممارسة العملية. فبدايةً، تُعد عملية إرسال كلمة مرور المستخدم ذهابًا وإيابًا عملية غير آمنة تمامًا. لذا ستحتاج إلى طريقة ما لتشفير البيانات. الطريقة الأكثر استخدامًا هي تقنية JWT، وهو اختصار لـ JSON Web Token. إذ تعمل هذه الطريقة على تشفير بيانات بصيغة JSON إلى ترميز بصيغة token. يمكنك رؤية مثال عليها من هنا. سيُحتفظ بهذا الترميز ضمن التخزين المحلي للمتصفح، وطالما بقي هذا الترميز ضمن ذاكرة المتصفح، سيبقى تسجيل الدخول قائمًا. المشكلة الثانية سببها نظام مكونات فيو Vue. فكما تعلم كل مكون مستقل بذاته فإذا تغير أحد المكونات، فإنه لا يؤثر على المكونات الأخرى. لكننا في هذه الحالة نريد أن تشترك جميع المكونات في نفس الوضعية، فإذا سجل المستخدم دخوله، نريد أن تتعرف جميع المكونات الأخرى على حالة المستخدم أثناء تسجيل الدخول. لذلك ستحتاج إلى مكان مركزي لتخزين هذه المعلومات حين يقوم المستخدم بتسجيل الدخول، ويجب أن تكون جميع المكونات قادرة على قراءة البيانات من ذلك المكان. ولتحقيق بذلك، ستحتاج إلى استخدام Pinia، وهي مكتبة Vue جديدة أُنشئت من خلال Vuex. دمج JWT في الواجهة الخلفية في البداية، سندمج JWT مع الواجهة الخلفية لجانغو، لذلك ستحتاج إلى تثبيت حزمة أخرى باسم django-graphql-jwt: pip install django-graphql-jwt انتقل الآن إلى ملف settings.py وأضف برنامجًا وسيطًا، وكذلك الاستيثاق في الواجهة الخلفية. ستحل هذه الإعدادات مكان الإعدادات الافتراضية لجانغو، وهو ما يتيح استخدام JWT. MIDDLEWARE = [ "django.contrib.auth.middleware.AuthenticationMiddleware", ] # Configure GraphQL GRAPHENE = { "SCHEMA": "blog.schema.schema", 'MIDDLEWARE': [ 'graphql_jwt.middleware.JSONWebTokenMiddleware', ], } # Auth Backends AUTHENTICATION_BACKENDS = [ 'graphql_jwt.backends.JSONWebTokenBackend', 'django.contrib.auth.backends.ModelBackend', ] لاستخدام هذه الحزمة، انتقل إلى موقع muts.py وأضف الشيفرة التالية: import graphql_jwt class Mutation(graphene.ObjectType): token_auth = graphql_jwt.ObtainJSONWebToken.Field() verify_token = graphql_jwt.Verify.Field() refresh_token = graphql_jwt.Refresh.Field() يمكننا الآن اختباره في واجهة GraphiQL: في حال كلمة مرور خاطئة في حال مستخدم موثوق كما هو واضح، فإن متطلبات تسجيل الدخول هي اسم المستخدم وكلمة المرور، وإذا تم التحقق من وثوقية هذا المستخدم بنجاح (أي أدخل اسم مستخدم وكلمة مرور صحيحة) سيُرسل من الواجهة الخلفية ترميز مشفر token. ويمكن حفظ هذا الترميز في ذاكرة المتصفح. يمكنك أيضًا تخصيص سلوك ObtainJSONWebToken من خلال العودة إلى Mutions.py: # Customize the ObtainJSONWebToken behavior to include the user info class ObtainJSONWebToken(graphql_jwt.JSONWebTokenMutation): user = graphene.Field(types.UserType) @classmethod def resolve(cls, root, info, **kwargs): return cls(user=info.context.user) class Mutation(graphene.ObjectType): token_auth = ObtainJSONWebToken.Field() لاحظ أن ObtainJSONWebToken يتوسع إلى JSONWebTokenMutation الافتراضي، ومن ثم في صنف Mutation، ويمكنك استخدام ObtainJSONWebToken عوضًا عن ذلك. يمكن الآن الحصول على مزيد من المعلومات حول المستخدم عبر GraphQL. استخدام حزمة بينيا Pinia في الواجهة الأمامية حان الوقت الآن لحل المشكلة الثانية في الواجهة الأمامية. والخطوة الأولى هي تثبيت بينيا Pinia. npm install pinia اذهب الآن إلى main.js وتأكد من أن تطبيقك يستخدم بينيا Pinia. import { createPinia } from "pinia"; createApp(App).use(createPinia()).use(router).use(apolloProvider).mount("#app"); ارجع الآن إلى مجلد src وأنشئ مجلد باسم stores، وهو المجلد الذي سنخزن فيه جميع بيانات التطبيق. في الوقت الحالي، كل ما تحتاج إليه هو تخزين القيم الخاصة بالمستخدم (بيانات تسجيل الدخول) وسنحافظ على المعلومات فيه حتى بعد تحديث الصفحة، لذا أنشئ ملف باسم user.js من أجل التعامل مع التخزين كما يلي: import { defineStore } from "pinia"; export const useUserStore = defineStore({ id: "user", state: () => ({ token: localStorage.getItem("token") || null, user: localStorage.getItem("user") || null, }), getters: { getToken: (state) => state.token, getUser: (state) => JSON.parse(state.user), }, actions: { setToken(token) { this.token = token; // Save token to local storage localStorage.setItem("token", this.token); }, removeToken() { this.token = null; // Delete token from local storage localStorage.removeItem("token"); }, setUser(user) { this.user = JSON.stringify(user); // Save user to local storage localStorage.setItem("user", this.user); }, removeUser() { this.user = null; // Delete user from local storage localStorage.removeItem("user"); }, }, }); لاحظ أن هذا مخزن البيانات يتكون من ثلاثة أقسام، وهم state و getters و actions. تساعد هذه الأقسام الثلاثة في إدارة حالة التطبيق بطريقة منظمة وسهلة وإذا كنت على معرفة جيدة بكيفية إنشاء تطبيق فيو Vue فيُفترض أن يكون ذلك مفهومًا بالنسبة لك. تشبه state في Pinia الدالة data() في مكون فيو Vue، إذ تعمل على تحديد المتغيرات، باستثناء أن يمكن لجميع المكونات الوصول إلى هذه المتغيرات. في مثالنا، سيحاول فيو Vue الحصول على الترميز المشفر في ذاكرة المتصفح، فإذا لم يكن موجودًا، سيأخذ المتغير قيمة null. أما getters فهي توازي المتغيرات computed، إذ تنفذ إجراءات بسيطة، وعادةً ما يقتصر عملها على إرجاع قيمة state فحسب. وهنا أيضًا يمكن لجميع المكونات والصفحات الوصول إلى المتغيرات. وأخيرًا، يمكن تشبيه actions بـ methods الموجودة في مكون فيو Vue. كما أنها تؤدي بعض الإجراءات باستخدام الحالات states. وفي هذه الحالة، أنت تعمل على حفظ أو إزالة الترميز المشفر للمستخدم ومعلوماته. ثمة شيء آخر عليك ملاحظته، وهو أنه لا يمكنك حفظ الكائنات objects في الذاكرة المحلية، وإنما يمكنك حفظ السلاسل النصية strings فقط. لذا يجب عليك استخدام stringify() و parse() لتحويل البيانات إلى سلسلة، ومن ثم إعادتها إلى كائن. ستحتاج بعد ذلك إلى استخدام هذا المخزن عند تسجيل دخول المستخدم، وقد أنشأنا ملف SignIn.vue مثل هذا: <script> import { useUserStore } from "@/stores/user"; import { USER_SIGNIN } from "@/mutations"; export default { name: "SignInView", setup() { const userStore = useUserStore(); return { userStore }; }, data() { return { signInDetails: { username: "", password: "", }, }; }, methods: { async userSignIn() { const user = await this.$apollo.mutate({ mutation: USER_SIGNIN, variables: { username: this.signInDetails.username, password: this.signInDetails.password, }, }); this.userStore.setToken(user.data.tokenAuth.token); this.userStore.setUser(user.data.tokenAuth.user); }, }, }; </script> نلاحظ في السطر 2 استيراد مخزن المستخدم User store الذي أنشأته. في السطور 9-12، استدعاء مخزن المستخدم User store في الخطاف setup، وهو ما يجعل التعامل مع بينيا Pinia أسهل دون أي وظائف خريطة إضافية. في السطرين 32-33، استدعاء الإجراءين setToken() و setUser() اللذيْن أنشأناهما منذ قليل، وهو ما سيحفظ المعلومات داخل الذاكرة المحلية. هذه هي الطريقة التي يمكنك من خلالها تسجيل دخول المستخدم، ولكن ماذا لو كان المستخدم قد سجل دخوله أساسًا، لنلقي نظرة على هذا المثال: <script> import { SITE_INFO } from "@/queries"; import { useUserStore } from "@/stores/user"; export default { setup() { const userStore = useUserStore(); return { userStore }; }, data() { return { menuOpen: false, mySite: null, user: { isAuthenticated: false, token: this.userStore.getToken || "", info: this.userStore.getUser || {}, }, dataLoaded: false, }; }, async created() { const siteInfo = await this.$apollo.query({ query: SITE_INFO, }); this.mySite = siteInfo.data.site; if (this.user.token) { this.user.isAuthenticated = true; } }, methods: { userSignOut() { this.userStore.removeToken(); this.userStore.removeUser(); }, }, }; </script> نحاول في السطرين 18- 19 الحصول على الترميز المشفر token ومعلومات المستخدم user info من المخزن Store. في السطور 31-33، إذا كان الترميز المشفر token موجودًا، فسيُعد المستخدم مستوثقًا authentication . في السطور 38-41، ستعمل الطريقة userSignOut() على تسجيل خروج المستخدم عند استدعائها. بعد أن تعرفنا على كيفية استرجاع البيانات باستخدام الاستعلامات queries ووضحنا كيفية إرسال البيانات باستخدام الطفرات mutations، سنشرح في المقال التالي طريقة إنشاء نظام تعليقات وتفاعلات إعجاب لتطبيق المدونة الخاص بنا. ترجمة -وبتصرّف- للمقال Create a Modern Application with Django and Vue #2. اقرأ أيضًا المقال السابق: إنشاء تطبيق حديث باستخدام Django و Vue | الجزء الأول: الأساسيات تطوير الواجهة الأمامية لمواقع الويب Frontend Web Development تطوير الواجهة الخلفية لمواقع الويب Backend Web Development مقارنة بين أطر الواجهات الأمامية: Angular و React و Vue
-
يعد إطار العمل جانغو Django إطار ويب كامل full-stack قائم على لغة بايثون Python، ويتبع نمط تصميم MTV (اختصار للنمط البنائي للبرمجيات نموذج-قالب-عرض Model-Template-View). والمقصود بمصطلح إطار ويب متكامل full-stack أنه يمكننا من خلاله إنشاء كل من الواجهة الأمامية frontend والواجهة الخلفية backend معًا. ومع ذلك، ثمة عيب صغير في هذا الحل، فعندما يطلب المستخدم النهائي صفحة ويب، هنا يجب تصيير rendering الصفحة أولًا في الواجهة الخلفية، ومن ثم تُرسل صفحة HTML المُكوَّنة إلى المستخدم. وفي هذه الحالة، عندما يكون لديك عدد كبير من المستخدمين، سيضع ذلك ضغطًا كبيرًا على خادمك. لحل هذه المشكلة، عادةً ما يُقسِّم المطورون التطبيق إلى قسمين؛ الواجهة الخلفية والواجهة الأمامية. وفي هذه الحالة، عندما يطلب المستخدم صفحة ويب، لن تُكوِّن الواجهة الخلفية صفحة الويب، بل يكفي أن تجمع البيانات الضرورية فقط وتنقلها إلى الواجهة الأمامية. وهنا يأتي دور جهاز العميل الذي يتمتع عادةً بقدرات حاسوبية عالية، إذ يستخدم هذه البيانات لعرض صفحة الويب داخل المتصفح مباشرةً، وبالتالي تخفيف الضغط على الخادم. سنتحدث في سلسلة المقالات هذه حول كيفية إنشاء تطبيق حديث من صفحة واحدة باستخدام جانغو Django كواجهة خلفية، وفيو Vue كواجهة أمامية، وغراف كيو إل GraphQL كلغة معالجة API تربطهما معًا. هذا المقال هو جزء من سلسلة مقالات تتحدث حول كيفية إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue: إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الأول. إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الثاني. إنشاء تطبيق حديث باستخدام جانغو Django وفيو Vue - الجزء الثالث. مراجعة سريعة عن جانغو لنبدأ بمراجعة سريعة حول إطار عمل جانغو Django، جانغو هو إطار عمل ويب يعتمد على لغة بايثون ويتبع النمط البنائي MTV، الذي هو اختصار لثلاث كلمات: النموذج M = Model: عبارة عن واجهة تتيح لنا التفاعل مع قاعدة البيانات، مثل استرجاع السجلات أو إنشائها أو تحديثها أو حذفها. القالب T = Template: يمثل الواجهة الأمامية من إطار العمل، وهو الجزء الذي سيراه المستخدمون النهائيون. العرض V = View: يمثل الواجهة الخلفية للتطبيق، إذ يستخدم النموذج Model للتفاعل مع قاعدة البيانات، مثل استرجاع البيانات التي يطلبها المستخدم، ثم يعمل العرض View على معالجة هذه البيانات بطريقة ما، وتظهر النتيجة للمستخدم عبر القالب Template الذي عادةً ما يكون مخصصًا. في سلسلة المقالات الحالية؛ سنستخدم جانغو للواجهة الخلفية فقط، أي لن نستخدم القوالب والعروض في جانغو، ونستستخدم عوضًا عن ذلك Vue.js لبناء الواجهة الأمامية و GraphQL كطريقة للتواصل بين الواجهة الأمامية والخلفية. إنشاء مشروع جانغو جديد الطريقة التي سنعتمد عليها هي فصل مجلد الواجهة الخلفية عن مجلد الواجهة الأمامية، لذا فإن أول خطوة هي إنشاء هيكل المشروع بالطريقة التالية: blog ├── backend └── frontend انتقل إلى مجلد backend، وأنشئ بيئة بايثون افتراضية جديدة. وبيئة بايثون الافتراضية هي بيئة معزولة لكل تثبيت بايثون جديد، لذا عندما تعمل على تثبيت حزم داخل هذه البيئة الافتراضية لن يؤثر ذلك على بيئة بايثون الخاصة بنظامك، وهو أمر بالغ الأهمية لاسيما إذا كنت تستخدم نظام تشغيل لينكس Linux أو ماك أو إس macOS، ولا تريد التأثير على ملفاتهما الأساسية. cd backend python3 -m venv env سيؤدي الأمر السابق إلى إنشاء مجلد جديد يُدعى env مع إنشاء البيئة الافتراضية بداخله. ولتنشيط هذه البيئة الافتراضية، استخدم الأمر التالي: source env/bin/activate إذا كنت تستخدم نظام تشغيل ويندوز Windows، فاستخدم الأمر التالي عوضًا عن السابق، كما يُنصح بتثبيت WSL: env/Scripts/activate بعد تنشيط البيئة الافتراضية، ستبدو الطرفية Terminal كما في الشكل أدناه. لاحظ وجود (env) أمام اسم المستخدم، منا يدل على أنك تعمل حاليًا في البيئة الافتراضية. يمكنك الآن إنشاء مشروع جانغو جديد. python -m pip install Django django-admin startproject backend بعدها يمكنك إنشاء تطبيق جديد باسم blog: python manage.py startapp blog في النهاية، يجب أن يكون هيكل المشروع كما يلي: . ├── backend │ ├── backend │ ├── blog │ ├── manage.py │ └── requirements.txt └── frontend إنشاء النماذج Models تذكر أن النماذج هي عبارة عن واجهة يمكننا استخدامها للتفاعل مع قاعدة البيانات، وواحدة من المزايا الرائعة في جانغو هي أنه يمكنك تلقائيًا معرفة التغييرات التي أجريتها على النماذج، وتوليد ملفات التهجير migration files المقابلة، والتي يمكن استخدامها لإجراء تغييرات على قاعدة البيانات. نموذج الموقع Site Model لنبدأ بالنموذج Site الذي يخزن المعلومات الأساسية لموقعك على الويب. class Site(models.Model): name = models.CharField(max_length=200) description = models.TextField() logo = models.ImageField(upload_to='site/logo/') class Meta: verbose_name = 'site' verbose_name_plural = '1. Site' def __str__(self): return self.name نلاحظ في السطر الرابع الأمر ImageField الذي يخبر جانغو بتحميل الصورة إلى مجلد 'site/logo/' ولتحقيق ذلك، عليك القيام بشيئين اثنين. أولاً، يجب عليك تثبيت حزمة Pillow، إذ يحتاجها جانغو لمعالجة الصور. python -m pip install Pillow ثانيًا، ستحتاج إلى إعداد توجيه جديد لمكان التخزين في settings.py إذ يجب أن تخبر جانغو بالمكان الذي ستخزن فيه هذه الوسائط، وما هي عناوين URL التي ستستخدمها للوصول إلى هذه الملفات. import os # Media Files MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles') MEDIA_URL = '/media/' تشير الإعدادات السابقة إلى أن ملفات الوسائط ستُخزن داخل ملف /mediafiles وسنحتاج إلى استخدام البادئة /media/ قبل عنوان URL للوصول إلى الملفات. فعلى سبيل المثال، سيؤدي عنوان URL التالي http://localhost:3000/media/example.png إلى استرجاع الصورة /mediafiles/example.png. نموذج المستخدم User Model النموذج التالي هو نموذج المستخدم User model، ولحسن الحظ، فإن جانغو يأتي مزودًا بنموذج مستخدم مدمج، والذي يوفر الوظائف الأساسية المتعلقة بالأذونات permission والتراخيص authorization. ومع ذلك، سنجرب في مشروعنا هذا شيئًا أكثر تعقيدًا، مثل إضافة صور أفاتار avatar للملف الشخصي وإضافة سيرة ذاتية وبعض المعلومات الأخرى، ولتحقيق ذلك، ستحتاج إلى إنشاء نماذج مستخدم جديدة، والتي نوسع فيها الصنف AbstractUser، ومعنى نوسعه extends أي نرث منه صنف جديد لنخصصه وفق حاجتنا أو نضيف له المزيد من الميزات. from django.contrib.auth.models import AbstractUser # New user model class User(AbstractUser): avatar = models.ImageField( upload_to='users/avatars/%Y/%m/%d/', default='users/avatars/default.jpg' ) bio = models.TextField(max_length=500, null=True) location = models.CharField(max_length=30, null=True) website = models.CharField(max_length=100, null=True) joined_date = models.DateField(auto_now_add=True) class Meta: verbose_name = 'user' verbose_name_plural = '2. Users' def __str__(self): return self.username هكذا يبدو صنف AbstractUser في جانغو: from django.contrib.auth.models import AbstractUser # New user model class User(AbstractUser): avatar = models.ImageField( upload_to='users/avatars/%Y/%m/%d/', default='users/avatars/default.jpg' ) bio = models.TextField(max_length=500, null=True) location = models.CharField(max_length=30, null=True) website = models.CharField(max_length=100, null=True) joined_date = models.DateField(auto_now_add=True) class Meta: verbose_name = 'user' verbose_name_plural = '2. Users' def __str__(self): return self.username كما هو واضح، يوفر هذا النموذج بعض الحقول الأساسية، مثل الاسم الأول واسم العائلة ونحو ذلك. ستحتاج بعد ذلك إلى التأكد من أن جانغو يستخدم نموذج المستخدم الجديد كنموذج مستخدم افتراضي، لذلك انتقل إلى ملف إعدادات التطبيق settings.py وأضف له التوجيه directive التالي: # Change Default User Model AUTH_USER_MODEL = 'blog.User' نماذج الفئة Category والوسم Tag والمنشور Post class Category(models.Model): name = models.CharField(max_length=200) slug = models.SlugField() description = models.TextField() class Meta: verbose_name = 'category' verbose_name_plural = '3. Categories' def __str__(self): return self.name class Tag(models.Model): name = models.CharField(max_length=200) slug = models.SlugField() description = models.TextField() class Meta: verbose_name = 'tag' verbose_name_plural = '4. Tags' def __str__(self): return self.name class Post(models.Model): title = models.CharField(max_length=200) slug = models.SlugField() content = RichTextField() featured_image = models.ImageField( upload_to='posts/featured_images/%Y/%m/%d/') is_published = models.BooleanField(default=False) is_featured = models.BooleanField(default=False) created_at = models.DateField(auto_now_add=True) modified_at = models.DateField(auto_now=True) # Each post can receive likes from multiple users, and each user can like multiple posts likes = models.ManyToManyField(User, related_name='post_like') # Each post belong to one user and one category. # Each post has many tags, and each tag has many posts. category = models.ForeignKey( Category, on_delete=models.SET_NULL, null=True) tag = models.ManyToManyField(Tag) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) class Meta: verbose_name = 'post' verbose_name_plural = '5. Posts' def __str__(self): return self.title def get_number_of_likes(self): return self.likes.count() لاحظ كيف تنفذ ميزة الإعجاب بالمنشورات (Like system) في السطر 13، وهو لا يعتمد على النوع البسيط IntegerField (وهو حقل لتخزين القيم الصحيحة) ولكنه يعمل تمامًا مثل الوسوم Tags. ويمكنك استخدام الدالة get_number_of_likes() لتحصل على عدد الإعجابات لكل منشور. نموذج التعليقات Comment model والآن دعونا نخطو خطوةً نحو الأمام، وننشئ قسمًا مخصصًا للتعليقات لهذا التطبيق: class Comment(models.Model): content = models.TextField(max_length=1000) created_at = models.DateField(auto_now_add=True) is_approved = models.BooleanField(default=False) # Each comment can receive likes from multiple users, and each user can like multiple comments likes = models.ManyToManyField(User, related_name='comment_like') # Each comment belongs to one user and one post user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) post = models.ForeignKey(Post, on_delete=models.SET_NULL, null=True) class Meta: verbose_name = 'comment' verbose_name_plural = '6. Comments' def __str__(self): if len(self.content) > 50: comment = self.content[:50] + '...' else: comment = self.content return comment def get_number_of_likes(self): return self.likes.count() إعداد لوحة التحكم في جانغو والآن حان الوقت لإعداد لوحة التحكم أو لوحة الإدارة في جانغو، لذا افتح ملف admin.py واكتب فيه التالي: from django.contrib import admin from .models import * # Register your models here. class UserAdmin(admin.ModelAdmin): list_display = ('username', 'first_name', 'last_name', 'email', 'date_joined') class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {'slug': ('name',)} class TagAdmin(admin.ModelAdmin): prepopulated_fields = {'slug': ('name',)} class PostAdmin(admin.ModelAdmin): prepopulated_fields = {'slug': ('title',)} list_display = ('title', 'is_published', 'is_featured', 'created_at') class CommentAdmin(admin.ModelAdmin): list_display = ('__str__', 'is_approved', 'created_at') admin.site.register(Site) admin.site.register(User, UserAdmin) admin.site.register(Category, CategoryAdmin) admin.site.register(Tag, TagAdmin) admin.site.register(Post, PostAdmin) admin.site.register(Comment, CommentAdmin) فيما يتعلق بـ CommentAdmin، فإن __str__ تشير إلى الدالة __str__() في نموذج التعليق. والتي ستعيد أول 50 حرفًا في السلسلة وتدمجها مع السلسلة .... والآن، فعِّل خادم التطوير وتأكد ما إذا كانت كل وظيفة تعمل على النحو الصحيح: python manage.py runserver وقبل الانتقال إلى الخطوة التالية، لا تنسَ إضافة بعض المعلومات الجانبية إلى مدونتك. مراجعة سريعة حول فيو جي إس Vue.js والآن بعد أن انتهينا من إعداد الواجهة الخلفية، حان الوقت للانتقال إلى الواجهة الأمامية، وبذلك الانتقال سنبدأ باستخدام فيو جي إس Vue.js في الجزء الثاني من مقالنا هذا لإعداد الواجهة الأمامية في تطبيقنا. قبل الخوض عميقًا، سنبدأ بمراجعة سريعة حول فيو جي إس Vue.js في حال لم تستخدمه من قبل، ويمكنك أيضًا الاطلاع على مقال مقدمة إلى Vue.js. فيو جي إس Vue.js هو أحد إطارات عمل جافا سكريبت JavaScript المخصصة لبناء الواجهات الأمامية، إذ يوفر لك نظامًا بسيطًا معتمدًا على المكونات، ما يسمح لك بإنشاء واجهات مستخدم تفاعلية. المقصود بـ "معتمدًا على المكونات" يعني أن المكون الجذري (App.vue) بإمكانه استيراد مكونات أخرى، وهي الملفات ذات الامتداد .vue، ويمكن لهذه المكونات استيراد المزيد من المكونات الأخرى، ما يسمح لك بإنشاء أنظمة معقدة ومتطورة للغاية. يحتوي الملف النموذجي ذو الامتداد .vue على ثلاثة أقسام، القسم الأول هو <template> يتضمن شيفرات بلغة HTML أما القسم الثاني فهو <script> ويتضمن شيفرات بلغة JavaScript، والقسم الأخير <style> يتضمن شيفرات بلغة CSS. في قسم <script> يمكنك التصريح عن ارتباطات bindings جديدة داخل التابع data() ، ويمكنك بعد ذلك عرض هذه الارتباطات داخل قسم <template> باستخدام الأقواس المزدوجة المتعرجة {{Binding}}. ستُغطى هذه الارتباطات المُصرَّح عنها في التابع data() تلقائيًا داخل نظام تفاعل فيو Vue، وهذا يعني أنه عندما تتغير قيمة الارتباط Binding، سيتغير المكون المقابل تلقائيًا، دون الحاجة إلى تحديث الصفحة. يمكن أن يحتوي القسم <script> أيضًا على توابع أخرى غير data() ، مثل computed وprops. كما يتيح لنا <template> ربط البيانات باستخدام توجيهات مثل v-bind و v-on و v-model. إنشاء مشروع فيو جي إس Vue.js جديد يمكن تثبيت وإنشاء تطبيق Vue باستخدام أداة سطر الأوامر Vue، لكننا في هذه المرة سنتبع طريقةً مختلفةً، إذ سنستخدم أداة إنشاء واجهات أمامية تسمى Vite، مع ملاحظة أن الكلمة تُنطق "veet" وتعني سريع باللغة الفرنسية، والتي أنشأها ذات الشخص الذي أنشأ Vue.js. انتقل الآن إلى مجلد frontend ونفذ الأمر التالي: npm init vue@latest سيُطلب منك العديد من الخيارات، ولهذا المشروع، كل ما عليك فعله إضافة Vue Router: ✔ Project name: … <your_project_name> ✔ Add TypeScript? … No / Yes ✔ Add JSX Support? … No / Yes ✔ Add Vue Router for Single Page Application development? … No / Yes ✔ Add Pinia for state management? … No / Yes ✔ Add Vitest for Unit testing? … No / Yes ✔ Add Cypress for both Unit and End-to-End testing? … No / Yes ✔ Add ESLint for code quality? … No / Yes ✔ Add Prettier for code formating? … No / Yes Scaffolding project in ./<your_project_name>. . . Done. إذا كنت ترتاح أكثر مع لغة برمجة جيدة، فيمكنك اختيار تثبيت TypeScript وإن كنت تحتاج إلى التصحيح التلقائي والتنسيق التلقائي للتعليمات البرمجية التي تكتبها، فيمكنك تثبيت ESlint وPrettier، ستؤدي عملية التثبيت هذه إلى إنشاء ملف package.json في دليل مشروعك، والذي يقوم بتخزين الحزم المطلوبة وإصداراتها. ستحتاج بعد ذلك إلى تثبيت هذه الحزم داخل مشروعك. cd <your_project_name> npm install npm run dev ثمة شيء أخير قبل أن نبدأ في إنشاء الواجهة الأمامية للتطبيق، نحن نستخدم في مشروعنا هذا إطار عمل بلغة CSS يُدعى TailwindCSS، لذا لتثبيته، نفذ الأمر التالي: npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p سيؤدي ذلك إلى إنشاء ملفين، الأول هو tailwind.config.js والثاني postcss.config.js، وإذا كنت تريد معرفة المزيد عن Tailwind فيمكنك الاطلاع على مقال مقارنة بين Bootstrap و Tailwind CSS، كما يمكنك الاطلاع على الدليل الرسمي لـ Tailwind. انتقل إلى tailwind.config.js وأضف المسار إلى جميع ملفات قالبك: module.exports = { content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], theme: { extend: {}, }, plugins: [], }; أنشئ ملف ./src/index.css وأضف توجيهات @tailwind لكل طبقة من طبقات Tailwind’s layers. @tailwind base; @tailwind components; @tailwind utilities; والآن، استورد الملف الذي أنشأته حديثًا ./src/index.css إلى ملف ./src/main.js. import { createApp } from "vue"; import App from "./App.vue"; import router from "./router"; import "./index.css"; const app = createApp(App); app.use(router); app.mount("#app"); والآن، من المفترض أن تكون قادرًا على استخدام Tailwind داخل ملفات .vue، وللتأكد، دعنا نختبر ذلك. <template> <header> . . . <div class="wrapper"> <HelloWorld msg="You did it!" /> <h1 class="text-3xl font-bold underline">Hello world!</h1> . . . </div> </header> . . . </template> لاحظ أننا أضفنا عنوان <h1> بعد <HelloWorld>، إذ يستخدم العنوان أصناف Tailwind. مكتبة Vue Router لاحظ أن مجلد مشروعك مختلف قليلًا في هذه المرة: يوجد داخل المجلد الرئيسي src مجلد router ومجلد views، إذ يحتوي مجلد router على ملف index.js، والذي يمكنك من خلاله تحديد وُجهات مختلفة، بحيث تشير كل وجهة route إلى مكون view موجود داخل مجلد views، ويمكن أن يوسع كل view بعد ذلك إلى مكونات أخرى داخل مجلد المكونات Components. تزودنا Vue بمثال على ذلك في ملف index.js: import { createRouter, createWebHistory } from "vue-router"; import HomeView from "../views/HomeView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: "/", name: "home", component: HomeView, }, { path: "/about", name: "about", // route level code-splitting // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import("../views/AboutView.vue"), }, ], }); export default router; لاستدعاء موجه router ما، انظر في داخل ملف App.vue، وعوضًا عن الوسم <a>، يُستخدم الوسم <RouterLink> المُستورد من حزمة vue-router لإدارة التنقل بين الصفحات في تطبيق Vue.js. <script setup> import { RouterLink, RouterView } from "vue-router"; . . . </script> <template> <header> . . . <div class="wrapper"> . . . <nav> <RouterLink to="/">Home</RouterLink> <RouterLink to="/about">About</RouterLink> </nav> </div> </header> <RouterView /> </template> عند إخراج الصفحة، سيُستبدل الوسم <RouterView/> بالعرض المطابق، وإذا لم تكن ترغب في استيراد هذه المكونات، فكل ما عليك هو استخدام الوسمين router-link to="">> وكذلك <router-view> عوضًا عن ذلك. إنشاء وُجهات routes باستخدام موجه فيو Vue router سنحتاج في مدونة تطبيقنا إلى إنشاء 6 صفحات على الأقل، سنحتاج إلى صفحة رئيسية والتي تعرض قائمة بأحدث الصفحات في المدونة، كما سنحتاج إلى صفحة الأقسام والتي تعرض جميع الأقسام أو الوسوم في المدونة، وصفحة أخرى لتعرض قائمة بالمقالات التي تنتمي إلى الأقسام أو الوسوم، وأخيرًا صفحة المقال التي تعرض محتوى المقال إضافةً إلى التعليقات. فيما يلي الموجهات التي أنشأناها، إذ يوجه الوسم @ نحو مجلد src. import { createRouter, createWebHistory } from "vue-router"; import HomeView from "@/views/main/Home.vue"; import PostView from "@/views/main/Post.vue"; import CategoryView from "@/views/main/Category.vue"; import TagView from "@/views/main/Tag.vue"; import AllCategoriesView from "@/views/main/AllCategories.vue"; import AllTagsView from "@/views/main/AllTags.vue"; const routes = [ { path: "/", name: "Home", component: HomeView, }, { path: "/category", name: "Category", component: CategoryView, }, { path: "/tag", name: "Tag", component: TagView, }, { path: "/post", name: "Post", component: PostView, }, { path: "/categories", name: "Categories", component: AllCategoriesView, }, { path: "/tags", name: "Tags", component: AllTagsView, }, ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes, }); export default router; يرجى ملاحظة أننا نعمل في هذا المقال على إنشاء الواجهة الأمامية فقط، ولم نصل إلى مرحلة نقل البيانات حتى الآن، لذا لا تقلق حول كيفية العثور على المنشورات أو الأقسام أو الوسوم في الوقت الحالي. إنشاء العروض والصفحات والمكونات توضح الصور التالية واجهة المستخدم الأمامية التي أنشأناها لهذا المشروع، ويمكنك إنشاؤها لديك إما باعتماد الشيفرات البرمجية في هذا المقال، أو كتابة الشيفرات البرمجية الخاصة الخاص بك كما يمكنك العثور على الكود البرمجي الكامل من هنا. الصفحة الرئيسية Home Page جميع التصنيفات All Categories جميع الوسوم All Tags صفحة تسجيل الدخول Sign In صفحة إنشاء حساب Sign Up صفحة المنشور المفرد Post قسم التعليقات على المنشور Comments صفحة الملف الشخصي للمستخدم Profile قسم تعليقات المستخدمين User Comments ترجمة -وبتصرّف- للمقال Create a Modern Application with Django and Vue #1 اقرأ أيضًا تطبيق عملي لتعلم إطار عمل جانغو - الجزء الأول: إنشاء موقع ويب هيكلي لمكتبة محلية معالجة طلبات الويب عبر العروض views في تطبيق جانغو بناء تطبيق ويب لإدارة معلومات العملاء باستخدام جانغو Django وريآكت React إنشاء تطبيق بسيط من خلال Vue.js إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات
-
يفتقر تطبيق الاقتراعات الذي نعمل على إنشائه إلى آلية جيّدة للتصويت على الأسئلة التي يتم عرضها للمستخدم، لذا يجب علينا توفير استمارة تتيح للمستخدم التصويت على الإجابة التي يرغب بها. إضافة إلى ذلك، سنتعرف في هذا الدرس على العروض العامة التي تهدف إلى اختصار الوقت والجهد عبر التخلّص من العمليات المتكررة بصورة دائمة، مثل جلب البيانات من قاعدة البيانات وعرض النتائج في صفحة مستقلة. وفي نهاية الدرس سنتعرف على الملفات الساكنة وسنضيف بعض التنسيقات إلى تطبيق الاقتراعات. إنشاء استمارة بسيطة يفترض أن يكون المستخدم قادرًا على اختيار إحدى الإجابات الخاصة بسؤال معين، ولكن قالب detail بشكله الحالي لا يوفّر هذا اﻷمر، لذا سنحتاج إلى إضافة استمارة إلى هذا القالب. توجّه إلى الملف polls/detail.html في مجلد القوالب templates ثم أضف إليه الشيفرة التالية: <h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br /> {% endfor %} <input type="submit" value="صوّت" /> </form> يعمل السطر الأول على جلب نص السؤال ووضعه داخل وسم <h1> لعرضه بشكل واضح وكبير. في السطر الثاني يتم التحقق مما إذا كان المتغير error_message يحمل قيمة أم ﻻ، فإن كان كذلك يتم عرض هذه القيمة وإلا فلا، سنستخدم هذا المتغير بعد قليل في العرض المسؤول عن التصويت، حيث سيحمل هذا المتغير قيمة نصية وهي عبارة عن رسالة نخبر المستخدم فيها أنّه لم يقم باختيار أي إجابة من الإجابات المعروضة. في السطر الثالث أنشأنا استمارة يتم توليد قيمة الحدث action فيه بصورة ديناميكية، وذلك باستخدام الوسم url والمسار vote والمتغير question.id والذي يمثّل الرقم المعرف للسؤال، وستكون طريقة إرسال الحدث هي POST، وبما أننا نعتمد هذه الطريقة، فعلينا الانتباه إلى حماية المعلومات من تزوير الطلب عبر المواقع Cross-site request forgery والمعروف اختصارًا بـ CSRF. ولكن لا تقلق، يوفّر Django نظامًا سهل الاستخدام لتجنّب هذه المشكلة. باختصار، يجب عليك وضع الوسم {% csrf_tocken %} في أي استمارة تعتمد طريقة POST ﻹرسال اﻷحداث. تعمل الحلقة for على إضافة زر اختيار Radio button إلى الإجابات الخاصة بالسؤال الذي اختاره المستخدم، ويتم جلب هذه الإجابات من باستخدام العبارة question.choice_set.all. والآن لنقم بإنشاء العرض الذي سيتحكم في البيانات المرسلة إلى الخادوم. أعتقد أن سير العمل في Django قد أصبح واضحًا في هذه المرحلة، ففي البداية نقوم بتعريف المسار، ثم نربط هذا المسار بالعرض الذي سيكون مسؤولًا عن القيام بأي شيء نرغب به، وبعد ذلك نربط هذا العرض بالقالب الذي سيظهر النتائج. وقد قمنا فعلًا بالخطوة الأولى من سلسلة الخطوات هذه في الدرس الرابع من هذه السلسلة عندما بدأنا الحديث عن المسارات، حيث يتضمن ملف polls/urls.py المسار التالي: url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote') هذا المسار مرتبط بالعرض view والذي قمنا بإنشائه في الدرس نفسه: def vote(request, question_id): return HttpResponse("أنت تصوت على السؤال %s." % question_id) لنقم الآن بكتابة الشيفرة المسؤولة عن عملية التصويت ضمن هذا العرض، لذا توجّه إلى ملف views.py وأضف الشيفرة التالية في بداية الملف: from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from .models import Choice, Question ثم عدّل دالة vote لتصبح بالشكل التالي: def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', {'question':question, "error_message": "لم تقم بالتصويت على السؤال"}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) لنتكلم عن الشيفرة السابقة بشيء من التفصيل، فهناك عدد من الأمور الجديدة فيها: request.POST هو عنصر شبيه بالقاموس يتيح الوصول إلى البيانات المرسلة من الاستمارة بواسطة اسم المفتاح، وفي حالتنا هذا فإن request.POST['choice'] سوف يرجع قيمة المعرّف الخاص بالجواب الذي اختاره المستخدم، وتكون هذه القيمة على هيئة سلسلة نصية. وجدير بالذكر أن Django يقدّم عنصرًا آخر باسم request.GET ويستخدم عندما تكون طريقة إرسال البيانات في الاستمارة هي GET. يطلق العنصر request.POST['choice] خطأً مفتاحيًا KeyError وهذا النوع من الأخطاء يُطلق عندما لا يكون المفتاح المطلوب (ضمن القاموس) موجودًا ضمن مجموعة المفاتيح المتوفرة، وفي تطبيقنا ينطلق هذا الخطأ عندما ﻻ يختار المستخدم أي إجابة من الإجابات المعروضة أمامه، ويعمل على إعادة المستخدم إلى صفحة التصويت مرة أخرى، ولكن هذه المرة مع إضافة العبارة: “لم تقم بالتصويت على السؤال” إلى المتغير error_message، وبعد أن أصبح هذا المتغير يحمل قيمة معينة، سيقوم قالب detail بعرض الرسالة في المكان المناسب. إن تمت عملية التصويت بنجاح يتم إضافة صوت واحد إلى الأصوات الخاصة بالإجابة المختارة من قبل المستخدم، وقد استخدمنا الصنف HttpResponseRedirect بدلًا من الصنف HttpResponse لإعادة توجيه المستخدم إلى صفحة النتائج. هذا الصنف في الواقع هو أحد الأصناف الفرعية للصنف HttpResponse ويأخذ معاملًا واحدًا وهو عنوان URL الذي ستتم إعادة التوجيه إليه. والهدف من استخدام هذا الصنف هو تجنّب إرسال البيانات مرتين في حال ضغط المستخدم على زر الرجوع في المتصفح، وينصح باستخدام هذا الصنف في كل مرة يتم فيها التعامل بنجاح مع بيانات POST، وهذا الأمر ليس خاصًا بـ Django فقط، بل هو من الممارسات الجيدة في مجال تطوير الويب باستخدام أي لغة برمجية. استخدمنا الدالة reverse() في مشيّد الصنف HttpResponseRedirect لنتجنّب الإدخال اليدوي للمسار الذي نرغب بإعادة توجيه المستخدم إليه. يأخذ المعامل الأول في هذه الدالة اسم العرض أو اسم نمط URL المطلوب إعادة التوجيه إليه. في هذا المثال سيتم توجيه المستخدم إلى المسار الذي يحمل اسم polls:results، ولكن هذا المسار يتضمن متغيّرًا، لذا سنخبر Django بأن يأخذ قيمته من المتغيّر question.id وذلك من خلال المعامل args. بمعنى أنّه لو اختار المستخدم السؤال الذي يحمل الرقم 3، فإن الصنف HttpResponseRedirect سيعيد السلسلة النصية التالية: polls/3/results/ حيث أن قيمة question.id في هذه الحالة هو 3. بعد أن يقوم المستخدم بالتصويت على سؤال معين، تعمل دالة العرض vote() على إعادة توجيهه إلى صفحة النتائج الخاصة بذلك السؤال، فلنقم إذًا بكتابة دالة العرض الخاصّة بالنتائج. توجّه إلى ملف polls/views.py وعدّل الدالة results لتصبح بالشكل التالي: def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) والآن، قم بإنشاء القالب المسؤول عن عرض النتائج. في مجلد templates/polls/ أنشئ الملف results.html، وأضف إليه الشيفرة التالية: <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">صوّت مرة أخرى</a> والآن توجّه إلى العنوان التالي في متصفحك بعد تشغيل الخادوم الخاص بـ Django: 127.0.0.1:8000/polls/1/ وستحصل على نتيجة مشابهة لهذه: وبعد التصويت سيتم توجيهك إلى صفحة النتائج: وفي حال عدم التصويت على أي إجابة والضغط على زرّ التصويت، تظهر رسالة الخطأ بالشكل التالي: العروض العامة Generic Views لنلق نظرة على ملف views.py بعد إضافة جميع الدوال إليه: from django.shortcuts import render, get_object_or_404 from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from .models import Choice, Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] return render(request, 'polls/index.html', {'latest_question_list': latest_question_list}) def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', {'question':question, "error_message": "لم تقم بالتصويت على السؤال"}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) هل لاحظت أمرًا ما؟ الدالتان detail() وresults() متشابهتان كثيرًا، وفي الواقع الفارق الوحيد بينهما هو القالب الذي يرتبط بكل دالة. إضافة إلى ذلك فإن هاتين الدالتين إضافة إلى دالة index() تقوم بعمل واحد وبسيط، وهو عرض مجموعة من المعلومات على المتصفح. تمثل هذه العروض حالة شائعة جدًّا في عملية تطوير الويب، وهي الحصول على البيانات من قاعدة البيانات بالاستناد إلى معامل يتم تمريره في عنوان URL في المتصفح، ثم تحميل قالب معين، ثم تصيير ذلك القالب على متصفح الإنترنت. لقد ذكرنا في بداية هذه السلسلة أنّ إطار العمل Django يركّز على مبدأ عدم التكرار، وقد رأينا هذا بشكل واضح عند استخدامنا للدوال المختصرة render() و get_object_or_404(). كذلك يوفّر Django في حالتنا هذه طريقة مختصرة للتعامل مع هذه العمليات الشائعة، وهي العروض العامّة. تعمل هذه العروض على اختصار الأنماط المتكررة من الشيفرات إلى درجة لا تعود فيها بحاجة إلى كتابة شيفرة بايثون لكتابة التطبيق. ولاستخدام العروض العامّة يتوجّب علينا إجراء بعض التعديلات البسيطة على شيفرتنا السابقة، ويمكن تلخيص هذه التعديلات بالنقاط التالية: تعديل أنماط URL. الاستغناء عن بعض العروض التي لسنا بحاجة إليها بعد الآن. كتابة عروض جديدة بالاعتماد على عروض Django العامة. تعديل أنماط URL توجّه إلى ملف polls/urls.py وعدّله بالشكل التالي: from django.conf.urls import url from . import views app_name = 'polls' urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'), url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ] لاحظ أنّنا استبدلنا <question_id> بـ <pk> في مساري detail و results، وسنتعرف على سبب ذلك بعد قليل. تعديل العروض التعديلات التي سنجريها على العروض ستشمل دوال index(), detail(), results() أما دالة vote() فستبقى دون تغيير: from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from django.views import generic from .models import Choice, Question class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): return Question.objects.order_by('-pub_date')[:5] class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html' class ResultsView(generic.DetailView): model = Question template_name = 'polls/results.html' لاحظ كيف استغنينا بشكل كامل عن الدوال الثلاثة سابقة الذكر لتحلّ محلّها أصناف تحمل أسماءً مشابهة، ونظرًا لاستخدام الأصناف في هذا النوع من العروض، فإنّها تحمل اسم العروض المستندة إلى الأصناف Class based views. لقد استخدمنا نوعين من أنواع العروض العامة، وهما ListView و DetailView. يلخّص العرض اﻷول عملية عرض جميع العناصر، في حين يلخّص العرض الثاني عملية عرض التفاصيل المرتبطة بعنصر معيّن. يحتاج كل عرض عامٍّ إلى التعرّف على النموذج الذي سيتعامل معه، ويتم التصريح عن ذلك في المعامل model. إلى جانب ذلك، يطلب العرض DetailView أن يتم إسناد قيمة المفتاح الرئيسي المأخوذة من عنوان URL إلى متغير يحمل الاسم pk، لهذا السبب قمنا بتبديل question_id بالاسم الجديد في ملف المسارات urls.py. يبحث العرض DetailView بصورة افتراضية عن القالب المرتبط به في المسار <app name>/<model_name>_detail.html، وهذا يعني أنّ هذا العرض سيستخدم القالب polls/question_detail.html بشكل تلقائي. ويمكن تجاوز هذه القيمة التلقائية من خلال تعيين اسم القالب باستخدام المعامل template_name. ينطبق الأمر ذاته على العرض ListView والذي سيستخدم بشكل تلقائي القالب polls/question_list.html. بقي أن نشير إلى أنّنا كنا نزوّد كل قالب بمتغيرات السياق التي سيستخدمها، وفي مثالنا هذا كانت المتغيرات هي question و latest_question_list. عند استخدام العروض العامّة يتم تزويد العرض DetailView بالمتغير question تلقائيًا، وذلك ﻷننا نستخدم النموذج Question، حيث يستطيع Django تحديد اسم مناسب لمتغيرات السياق بناء على النموذج الذي يرتبط بالعرض العام. ويمكن تجاوز القيمة التلقائية هذه بسهولة وذلك بإسناد اسم المتغير الذي نرغب به إلى المعامل context_object_name، وبهذا نخبر Django بأنّنا نرغب باستخدام هذا الاسم بدلًا من الاسم الذي سينشئه بصورة تلقائية وهو في هذه الحالة question_list. كما يمكنك الإبقاء على الاسم الافتراضي question_list إن كنت ترغب في ذلك، ولكن هنا عليك تغيير اسم المتغير في أي مكان يرد فيه ضمن القوالب. الملفات الساكنة Static Files يبدو تطبيقنا بشعًا أليس كذلك؟ لنقم إذًا بإضافة بعض التنسيقات البسيطة إليه، ولنتعرف على مفهوم الملفات الساكنة. إلى جانب ملفات HTML التي ينشئها الخادوم، تحتاج تطبيقات الويب بشكل عام إلى بعض الملفات اﻹضافية - مثل الصور وملفات جافا سكربت وملفات CSS - لعرض صفحات الويب بشكل منسّق ومرتّب، ويطلق Django على هذه الملفات اسم الملفات الساكنة. سنبدأ أولًا بإنشاء مجلد باسم static في مجلد polls الرئيسي، ثم أنشئ داخل المجلد static مجلّدًا جديدًا باسم polls. بمعنى آخر يجب أن يكون مسار ملف CSS بالشكل التالي: polls/static/polls/style.css. كما هو الحال مع القوالب، فإن Django يبحث بنفس الطريقة عن الملفات الساكنة، واستخدام هذه المجلدات هو أمر تنظيمي يتيح لـ Django التمييز بين الملفات الساكنة الخاصة بكل تطبيق. والآن توجّه من خلال محرّر النصوص إلى ملف style.css وأضف إليه الشيفرة التالية: li a { color: green; text-decoration: none; font-size: 1.3em; } والآن توجّه قالب index.html وأضف الشيفرة التالية في بداية الملف: {% load staticfiles %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" /> يعمل الوسم load staticfiles في بداية الملف على تحميل الوسم static المسؤول بدوره عن توليد عنوان URL المطلق للملف الساكن المطلوب. والآن أعد تحميل الصفحة الرئيسية وستلاحظ أن الأسئلة قد تلونت باللون اﻷخضر. ولإضافة صورة للخلفية قم بإنشاء مجلد images في نفس المجلد الذي يحتوي الملف style.css ثم ضع فيه الصورة التي ترغب في جعلها خلفية للصفحة، وعلى فرض استخدام صورة باسم background.gif أضف الشيفرة التالية إلى ملف style.css: body { background: white url("images/background.gif") no-repeat right bottom; } أعد تحميل الصفحة الرئيسية، وستلاحظ أن الصورة قد أصبحت خلفية للصفحة. من الجدير بالذكر أنّه لا يمكن استخدام الوسم {% static %} استخدام داخل الملفات الساكنة والتي لا يتم توليدها بواسطة Django، لذا يجب استخدام المسارات النسبية وليست المطلقة لربط الملفات الساكنة بعضها ببعض. ختامًا تعرّفنا في هذا الدرس على كيفية استخدام نماذج الاستبيان في Django بصورة مبسطة، واستخدمنا بعد ذلك العروض العامّة التي تختصر الكثير من الوقت والجهد، وفي النهاية تعرّفنا على مفهوم الملفات الساكنة وكيفية استخدامها في تطبيقات Django. في الدرس القادم وهو الدرس اﻷخير ضمن هذه السلسلة، سنتحدّث بشيء من التفصيل عن لوحة التحكم التي يتم إنشاؤها بصورة تلقائية مع كل مشروع في Django. المصدر: توثيقات Django
-
تحدثنا في الدرسين السابقين عن كيفية تنصيب وإعداد إطار العمل Django على أنظمة التشغيل المختلفة، وتعرفنا كذلك على مفهومي المشروع والتطبيق، وقمنا بكتابة العرض الأول وتعرفنا بشكل مختصر على المساراتUrls. وفي الجزء الثالث من هذه السلسلة، سنتطرق إلى النماذج Models وكيفية التعامل مع قواعد البيانات من خلال Django، وسنتعرف خلال الدرس على طريقة ربط قواعد البيانات المختلفة مع Django، وكيفية إنشاء النماذج والتعامل معها وسنتطرق كذلك إلى مفهوم تهجير قواعد البيانات Migration، وسننشئ النموذج الخاص بتطبيق الاقتراعات والذي سيحتضن الأسئلة الخاصة بالاقتراع إضافة إلى الإجابات المرتبطة بالسؤال. النماذج Models أشرنا في الدروس السابقة إلى أن إطار العمل Django يتبع مبدأ العمل MVT، ويشير الحرف M هنا إلى النماذج Models، ويمكن تعريف النماذج بشكل مبسط على أنها وصف للبيانات الموجودة في قاعدة البيانات باستخدام لغة Python، وبمعنى آخر تمثّل النماذج في Django بنية قاعدة البيانات، أي ما ستحصل عليه من إجراء الأمر CREATE TABLE ولكن بلغة Python بدلًا من SQL. يستخدم Django النماذج في التواصل مع قواعد البيانات من خلال تنفيذ أوامر SQL خلف الكواليس وتقديم النتائج التي ترد من هذه الأوامر على هيئة بنية من البيانات تمثل الصفوف في جداول قاعدة البيانات. ولهذا الأسلوب في التعامل مع قواعد البيانات بعض الفوائد، فكتابة النماذج بلغة Python يزيد في الانتاجية، إذ لن يكون المبرمج مضطرًا إلى اتباع قواعد لغة أخرى أثناء العمل على التطبيق ويكون العمل مقتصرًا على لغة python، كما يسهل هذا الأسلوب متابعة النماذج وتتبع التغييرات الحاصلة عليها من خلال أنظمة تتبع الإصدارات كـ Git وغيرها، إضافة إلى ذلك تقدم نماذج Python بعض أنواع البيانات غير المتوفرة في SQL كالبريد الإلكتروني وعناوين URL وغيرها. ربط Django مع قواعد البيانات يستطيع Django التعامل مع أنواع مختلفة من أنظمة قواعد البيانات، ومن أشهرها SQLite، MySQL، PostgreSQL و Oracle. وفي مشروعنا هذا سنستخدم قواعد بيانات SQLite والتي تعتبر الخيار الأبسط والأسهل في حالة المشاريع البسيطة والصغيرة ويتم تثبيتها عند تثبيت Python وهذا يعني عدم الحاجة إلى تثبيت أي حزم إضافية، كما أنها ليست بحاجة إلى خادوم خاص تعمل من خلاله. يمكن اختيار نوع قاعدة البيانات التي سيعمل عليها المشروع من خلال ملف الإعدادات settings.py، وذلك ضمن القاموس DATABASES. يستخدم Django قواعد بيانات SQLite بشكل افتراضي، وستجد قاموس DATABASES بالشكل التالي: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } يتطلب ربط Django بقواعد البيانات الأخرى كـ MySQL و PostgreSQL تثبيت حزم الربط الخاصة بكل نوع منها، وإضافة العناصر ‘USER’، ‘PASSWORD’، و’HOST’ إلى القاموس، ويمكن التعرف إلى الحزم المطلوبة لكل نوع من أنواع قواعد البيانات في توثيقات Django. إنشاء النموذج الأول سيعتمد تطبيق الاقتراعات على نموذجين فقط هما نموذج الأسئلة ونموذج الإجابات، وسيتضمن النموذج الأول السؤال وتاريخ نشره، أما النموذج الثاني فسيتضمن الإجابات ومجموع الأصوات على كل إجابة، وسترتبط كل إجابة بسؤال معين. افتح ملف models.py في محرر النصوص المفضل لديك، ثم أضف الأسطر التالية: class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) يمكن أن نلاحظ أن كل نموذج في هذا الملف قد تم تمثيله بصنف والذي يمثل بدوره جدولًا في قاعدة البيانات، ويتضمن كل صنف عددًا من المتغيرات التي يمكن استخدامها في شيفرة Python حسب الحاجة إليها، كما تمثل اسم العمود في قاعدة البيانات. تمثل أسماء المتغيرات التي استخدمناها في الشيفرة السابقة أسماء الأعمدة في قواعد البيانات، وسنستخدم هذه الأسماء في شيفرة Python وستظهر كذلك في لوحة التحكم التي سنتحدث عنها مفصّلًا في الدروس القادمة، ويمكن التحكم في طريقة عرض هذه الأسماء في لوحة التحكم وذلك باستخدام معامل يجب تعيين قيمته قبل أي معامل آخر، كما فعلنا مع المتغير pub_date أعلاه، وبهذه الطريقة سيظهر هذا الحقل في لوحة التحكم بالاسم date published وليس pub_date. نلاحظ في الشيفرة السابقة أيضًا أننا عرّفنا علاقة تربط بين الإجابات وبين السؤال الخاص بها، وذلك باستخدام ForeignKey والتي تخبر Django بأن كل إجابة ترتبط بسؤال واحد فقط. تمتلك بعض أنواع الصنف Field عددًا من المعاملات الإلزامية، كما هو الحال مع CharField والذي يتطلب تحديد العدد الأقصى للحروف من خلال max_length. وبطبيعة الحالة تمتلك هذه الأصناف بعض المعاملات الاختيارية، كما هو الحال مع IntegerField الذي أضفنا إليه قيمة افتراضية مساوية للصفر من خلال default=0. يتم تمثيل كل حقل من حقول قاعدة البيانات بـ instance للصنف Field، مثل CharField لحقول الحروف، و DateTimeField لحقول التاريخ والوقت. يقدّم Django عددًا كبيرًا ومتنوعًا من أنواع الحقول، نورد فيما يلي بعضًا منها: الحقل الوظيفة BooleanField يتضمن قيمتي True و False، وعادة ما يكون مرتبطًا بمربع الاختيار Checkbox. CharField يستخدم هذا الحقل لإضافة السلاسل النصية Strings القصيرة والمتوسطة الحجم. DateField يستخدم للتعبير عن التاريخ. DateTimeField يستخدم للتعبير عن التاريخ الوقت. DecimalField يتيح استخدام الأرقام العشرية التي تحتوي على فواصل. EmailField عبارة عن حقل حرفي `CharField` ولكنه قادر على التحقق من أن القيمة المدخلة تمتلك صيغة بريد إلكتروني سليمة. FileField يستخدم هذا الحقل لاحتواء الملفات المرفوعة. IntegerField يتيح استخدام الأرقام الصحيحة، ويمكن استخدام الأرقام من -2147483648 إلى 2147483647 بشكل آمن مع أنظمة قواعد البيانات المختلفة. GenericIPAddressField عبارة عن عنوان IPv4 أو IPv6 على هيئة سلسلة نصية. SlugField حقل Slug. TextField يستخدم في لإضافة السلاسل النصية الطويلة. TimeField يستخدم للتعبير عن الوقت. URLField عبارة عن حقل حرفي يتضمن عنوان URL. تفعيل النموذج تستطيع الشيفرة السابقة القيام بأمور كثيرة، حيث يمكن لـ Django أن: ينشئ جدولًا جديدًا خاصًّا بتطبيقنا هذا وذلك بتنفيذ العبارة CREATE TABLE. إنشاء واجهة برمجية API خاصة يمكن من خلالها التعامل مع قاعدة البيانات التي تم إنشاؤها. ولكن قبل أن يشرع Django بأداء هذه المهام، يجب علينا تثبيت تطبيق polls في مشروعنا وذلك من خلال إدراج اسمه ضمن قائمة INSTALLED_APPS في ملف الإعدادات settings.py، لذا توجه إلى هذا الملف وابحث عن القائمة التي تحمل الاسم INSTALLED_APPS، ثم عدل عناصرها لتصبح بالشكل التالي: INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls', ] توجّه الآن إلى مجلد المشروع عن طريق سطر الأوامر ونفّذ الأمر التالي: python manage.py makemigrations polls يفترض أن ترى النتيجة التالية في سطر الأوامر: Migrations for 'polls': polls/migrations/0001_initial.py: - Create model Choice - Create model Question - Add field question to choice وظيفة الأمر makemigrations هي إخبار Django بأنّك قد أجريت بعض التعديلات على النماذج وأنّك ترغب في حفظ هذه التعديلات على هيئة ملف تهجير يُحفظ على القرص الصلب كملف بايثون في مجلد migrations، تحت اسم: 0001_initial.py. والآن نفّذ الأمر التالي في سطر الأوامر وذلك لتنفيذ التهجيرات وإنشاء الجداول ضمن قاعدة البيانات: python manage.py migrate يفترض أن تظهر النتيجة التالية في سطر الأوامر: Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Rendering model states... DONE Applying polls.0001_initial... OK تتلخص وظيفة الأمر migrate في البحث عن التهجيرات غير المنفّذة (يتابع Django التهجيرات غير المنفّذة من خلال جدول خاص في قاعدة البيانات يحمل الاسم django_migrations) وإجرائها على قاعدة البيانات، سواء أكانت هذه التهجيرات تتضمن إنشاء جداول جديدة أو تعديل وتحديث جداول موجودة بالفعل. إذًا يمكن تلخيص عملية إجراء التعديلات على النماذج بالخطوات الثلاثة التالية: إجراء التعديلات على النموذج في ملف models.py. تنفيذ الأمر python manage.py makemigrations لإنشاء التهجيرات المرتبطة بالتعديلات التي تم إجراؤها على النموذج. تنفيذ الأمر python manage.py migrate لتطبيق هذه التعديلات على قاعدة البيانات. الواجهة البرمجية الخاصة بالتعامل مع قاعدة البيانات ذكرنا سابقًا بأن لدى Django واجهة برمجية للتعامل مع قاعدة البيانات، وأفضل طريقة للتعرف على هذه الواجهة هي التعامل المباشر معها من خلال سطر الأوامر وعن طريق صدفة Python. للولوج إلى الصدفة نفّذ الأمر التالي في سطر الأوامر: python manage.py shell أولًا يجب استيراد صنفي النموذج Question و Choice، كما سنحتاج إلى حزمة timezone من مكتبة django.utils للتعامل مع الوقت والتاريخ: from polls.models import Question, Choice from django.utils import timezone يمكن الاستعلام عن جميع الأسئلة الموجودة في جدول Question من خلال الشيفرة: Question.objects.all() وباعتبار أن قاعدة البيانات الخاصة بتطبيقنا هذا خالية تمامًا من الأسئلة، فسنحصل على النتيجة: <QuerySet []> لإنشاء السؤال الأول سنقوم بإنشاء كائن من الصنف Question مع تعريف قيم المعاملات المستخدمة في هذا الصنف وإسناد هذا الكائن إلى متغير، وكما يلي: q = Question(question_text="What's new?", pub_date=timezone.now()) يمكن الآن حفظ السؤال الجديد في قاعدة البيانات من خلال الشيفرة التالية: q.save() والآن، يمكن الوصول إلى جميع المعلومات الخاصة بهذا السؤال وبالشكل التالي: #الحصول على نص السؤال q.question_text #الحصول على تاريخ نشر السؤال q.pub_date # تغيير نص السؤال q.question_text = "What’s up?" q.save() بعد أن أضفنا سؤالًا إلى قاعدة البيانات، سنجري استعلامًا عن جميع الأسئلة في النموذج Question: Question.objects.all() #ستحصل على النتيجة التالية <QuerySet [<Question: Question object>]> نلاحظ أن النتيجة التي حصلنا عليها غريبة بعض الشيء، فالسؤال الذي أضفناه قبل قليل لم يظهر ضمن قائمة الأسئلة، ولحل هذه المشكلة سنحتاج إلى إضافة تابع __str()__ إلى كلا الصنفين، وبالشكل التالي: from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # إن كنت بحاجة إلى استخدام الإصدار الثاني من بايثون class Question(models.Model): # ... def __str__(self): return self.question_text @python_2_unicode_compatible # إن كنت بحاجة إلى استخدام الإصدار الثاني من بايثون class Choice(models.Model): # ... def __str__(self): return self.choice_text من الضروري استخدام التابع __str__() عند التعامل مع النماذج، لأن نتيجة هذا التابع ستظهر في لوحة التحكم التي يتم إنشائها آليًا من خلال هذه النماذج. وكما قمنا باستخدام أحد التوابع المعرفة مسبقًا في Django فبمقدورنا أن نستخدم توابع مخصّصة تؤدي وظائف ومهام مختلفة، ولتوضيح ذلك، قم باستيراد مكتبة datetime الخاصة بـ Python، ثم أضف الشيفرة التالية في نهاية الصنف Question: import datetime # ... class Question(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) سيقوم هذا التابع بالتحقق من أن السؤال قد تم نشره مؤخّرًا (منذ يوم) أو منذ فترة بعيدة (أكثر من يوم). والآن يمكن استدعاء تابعنا المخصص الجديد بنفس الطريقة التي استدعينا من خلالها تابع الحفظ: q.was_published_recently() افتح الآن صدفة بايثون جديدة، واستورد الأصناف Question و Choice بنفس الطريقة السابقة، ثم نفذ شيفرة الاستعلام عن جميع الأسئلة، ولاحظ الفرق. طرق الاستعلام عن البيانات في Django لا شك أن التطبيقات على أرض الواقع تتضمن قواعد بيانات تحتوي على عدد هائل من البيانات والمعلومات، وهذا يتطلب وسيلة للاستعلام عنها حسب شرط معين، ويقدم Django طرقًا متعددة لإجراء استعلامات مخصصة وبأساليب مختلفة. يقدّم Django ثلاثة توابع خاصة بالصنف QuerySet هي: filter(), exclude(), get()، وجملة الاستعلام عبارة عن معاملات مفتاحية Keyword arguments لهذه التوابع، وتأخذ الصيغة التالية: الحقل__نوع الاستعلام = القيمة. يقوم كل تابع من هذه التوابع الثلاثة بإنشاء كائن جديد للصنف QuerySet يتضمن النتائج التي تم الحصول عليها بعد إجراء الاستعلام. يقوم التابع filter() بإرجاع جميع العناصر المتوافقة مع الاستعلام، أما التابع exclude() فيرجع جميع العناصر غير المتوافقة مع الاستعلام، أما التابع get() فيرجع العنصر الذي يطابق جملة الاستعلام، وفي حالة العثور على أكثر من عنصر واحد يقوم هذا التابع بإطلاق الاستثناء MultipleObjectsReturned وإن لم يعثر على أي عنصر فسيطلق الاستثناء DoesNotExist. إليك بعض الأمثلة التي توضح طريقة عمل هذه التوابع: يمكن البحث عن السؤال الذي يبدأ بعبارة معينة بالشكل التالي: Question.objects.filter(question_text__startswith='What') ستترجم هذه الشيفرة إلى عبارة SQL التالية: SELECT … WHERE question_text LIKE ‘What%’; ويمكن البحث عن سؤال معين من خلال المعرّف الخاص به، فللبحث عن السؤال ذي المعرف رقم 1، يمكن كتابة الشيفرة: Question.objects.filter(id=1) والتي تعادل عبارة SQL التالية: SELECT … WHERE id = 1; مثال على التابع exclude(): Question.objects.exclude(pub_date__gt=datetime.date(2016, 1, 3), question_text = "What’s up?") تترجم هذه الشيفرة إلى عبارة SQL التالية: SELECT … WHERE NOT (pub_date > ‘2016-1-3’ AND question_text = “What’s up?”) يوضح الجدول التالي بعض أنواع الاستعلامات التي يقدّمها Django: نوع الاستعلام الوظيفة exact تطابق تام. iexact تطابق تام مع تجاهل حالة الأحرف. contains البحث عن كلمة مع أخذ حالة الأحرف بنظر الاعتبار. icontains البحث عن كلمة مع تجاهل حالة الأحرف. in البحث ضمن قائمة معينة. gt أكبر من gte أكبر من أو يساوي lt أصغر من lte أصغر من أو يساوي startswith يبدأ بـ istartswith يبدأ بـ مع أخذ حالة الأحرف بنظر الاعتبار. endswith ينتهي بـ iendswith ينتهي بـ مع أخذ حالة الأحرف بنظر الاعتبار. range البحث ضمن مدى معين date البحث عن تاريخ معين year البحث عن سنة معينة month البحث عن شهر معين day البحث عن يوم معين week_day البحث عن أسماء أيام الأسبوع hour البحث عن ساعة minute البحث عن دقيقة second البحث عن ثانية لنستعلم الآن عن السؤال الذي يحمل المفتاح الرئيسي primary key رقم 1 في قاعدة البيانات الخاصة بنا، وإسناد النتيجة إلى متغير: q = Question.objects.get(pk=1) يمكننا الآن الوصول إلى مجموعة الأجوبة choice_set والتي ينشئها Django تلقائيًا عند ربط الأسئلة بالأجوبة من خلال ForeignKey. q.choice_set.all() بطبيعة الحال، فإن مجموعة الأجوبة الخاصة بسؤالنا هذا فارغة، لذا سنقوم بإنشاء بعض الأجوبة وإضافتها إلى هذه المجموعة: q.choice_set.create(choice_text = 'Not much', votes = 0) q.choice_set.create(choice_text = 'The sky', votes = 0) c = q.choice_set.create(choice_text = 'Just hacking again', votes = 0) والآن يمكن التعرف على السؤال المرتبط بالجواب: c.question ويمكن معرفة عدد الأجوبة المتاحة لسؤال معين عن طريق التابع count(): q.choice_set.count() ويمكن حذف إجابة معينة عن طريق التابع delete(): c.delete() خاتمة تعرفنا في هذا الدرس على العنصر الأول من عناصر إطار العمل Django ألا وهو النماذج Models، وتعرفنا كذلك على طريقة التعامل مع قواعد البيانات من خلال هذه النماذج وكيفية تهجيرها والاستعلام عن البيانات برمجيًا. أما الدرس القادم فسيكون عن المسارات URLS وآلية عملها، وكيفية استخدام التعابير النظامية Regular Expressions في إنشائها. المصدر: توثيقات Django.
-
إن العديد من حزم بايثون تساعد مطوري جانغو Django على العمل بسرعة وفعالية أكبر، حيث أن مكتبات Django هي المفضلة لدى أغلب المطورين فهي توفر الوقت وتقلل من عملية البرمجة وبالتالي تبسط عملهم. سنتكلم في هذا المثال عن ستة حزم لبرامج Django واثنين لهيكلية Django REST، حيث تظهر هذه الحزم في غالبية المشاريع التي نعمل عليها. إضافات جانغو الموفرة للوقت: Django-extensions تعتبر Django-extensions من الحزم المليئة بالأدوات المفيدة مثل أوامر الإدارة التالية: shell_plus: تفتح Django shell مع جميع النماذج الخاصة بقاعدة البيانات والمُحمَّلة بشكل مُسبق، وبالتالي لاتحتاج إلى عمل أي استيراد من التطبيقات المختلفة والتي تحتاجها لعمل اختبار لعلاقة معقدة clean_pyc: تعمل على محي جميع المشاريع ذات اللاحقة .pyc في جميع الأماكن التي تظهر بها داخل مسار المشروع. create_tamplate_tags: تنشئ بنية مجلد خاص بالقوالب داخل التطبيق الذي تحدده. describe_form: تظهر تعريف الواجهة للنموذج ويمكن نسخه فيما بعد إلى forms.py (ولكن من المهم الانتباه إلى أن هذا الأمر ينشئ واجهة جانغو عادية وليست من نوع ModelForm). notes: يظهر هذا الأمر جميع التعليقات من نوع TODO أو FIXME وغيرها خلال المشروع. كما تحوي حزمة Django-extensions على أصناف مجردة مفيدة تستخدم للنماذج الشائعة، حيث تستطيع توريث هذه الأصناف الأساسية عند إنشاء نماذج خاصة بك: TimeStampeModel: يحوي هذه الصنف على حقول created و modified بالإضافة للتابع ()save الذي يحدث هذه الحقول تلقائيًّا. ActivatorModel: في حال كان النموذج الخاص بك يحتاج إلى حقول مثل activate_state، status و deactivate_date عندها يمكنك استخدام هذا الصنف حيث أنه يحوي أيضًا على مدير يوفر لك استعلامات ()active. و ()inactive. TitleSlugDescriptionModel و TitleDescriptionModel: يحوي الصنفان على حقول title، description كما يحوي الصنف الأول على حقل إضافي هو slug الذي يُحدَّث تلقائيًّا بالاعتماد على حقل title. حزمة Django-environ تتيح Django-environ تطبيق المنهجية 12-factor app لإدارة إعداداتك في مشروع جانغو الذي تنشئه، وتجمع هذه الحزمة مكتبات أخرى مثل envparse و honcho والآن وبعد تحميلك لحزمة Django-environ تستطيع إنشاء ملف .env في جذر مشروعك وتعرف في داخله متغيرات الإعدادات التي من الممكن أن تتغير بين البيئات أو التي يجب أن تبقى سرية مثل مفاتيح API أو حالة Debug أو عناوين قاعدة البيانات. بعد ذلك في الملف الخاص بإعدادات المشروع setting.py يمكنك عمل استيراد للبيئة ثم ضبط المتغيرات المتعلقة بـ ()environ.PATH و ()environ.Env كما ورد في المثال. مع العلم أنه يمكن الوصول إلى المتغيرات المُعرّفة في ملف .env باستخدام (’env(‘VARIABLE_NAME إنشاء أوامر الإدارة: Django-click أُنشِئت حزمة Django-click بالاعتماد على حزمة click وهي تساعدك لكتابة أوامر الإدارة جانغو، لكن لاتمتلك هذه الحزمة الكثير من التوثيقات وإنما لديها مجلد من الأوامر التجريبية test commands. لنتعرف على طريقة كتابة الأمر Hello World باستخدام هذه الحزمة: # app_name.management.commands.hello.py import djclick as click @click.command() @click.argument('name') def command(name): click.secho(f'Hello, {name}') ثم نكتب سطر التشغيل الذي يعطي أمر التنفيذ: >> ./manage.py hello Lacey Hello, Lacey التعامل مع آلة ذات حالات منتهية : Django-fsm تضيف حزمة Django-fsm الدعم لحالة الآلات ذات حالات منتهية للنموذج الموجود بالجانغو الخاص بمشروعك، ففي حال كنت تنفذ موقع ويب أخباري و تحتاج إلى مقالات تمر بحالات states مثل الكتابة، التحرير، والنشر، هنا يأتي دور حزمة Django-fsm التي تساعد في تعريف هذه الحالات وإدارة القواعد التي تحكُم الانتقال من حالة إلى أخرى. توفر Django-fsm مايدعى FSMField والذي يستخدم كصفة التي تعرف حالة النموذج وبعد ذلك تستطيع استخدام transition@ من هذه الحزمة من أجل تعريف التوابع التي تحرك النموذج من حالة إلى أخرى وللتعامل مع أي تأثيرات جانبية لذلك الانتقال. وعلى الرغم من أن حزمة Django-fsm لا تملك توثيقات التي تعرفها بشكل جيد ولكن تحوي workflows(states) in Django الذي يمكن أن يعتبر مقدمة جيدة لتعريف مفهومي آلة ذات حالات منتهية وحزمة django-fsm. استمارات التواصل: #django-contact-form إن استمارات التواصل أمر أساسي يتواجد في مواقع الويب، ولكن لا داع لتكتب ترميزها بنفسك إذ يمكن إنشاؤها بدقائق من خلال استخدام الحزمة django-contact-form والتي يأتي معه صنف اختياري spam-filtering contact form (و صنف نظامي، و non-filtering) بالإضافة إلى صنف ContactFormView الذي يحوي على توابع يمكن تخصيصها وإعادة كتابتها وذلك لإنشاء النموذج الخاص بك. تسجيل واستيثاق المستخدمين: django-allauth إن Django-allauth هو برنامج يوفر الواجهات، والروابط لتسجيل المستخدمين، ولتسجيل الدخول والخروج، وإعادة تعيين كلمات السر و استيثاق المستخدمين مع مواقع خارجية مثل GitHub و Twitter. كما أنه يدعم الاستيثاق عن طريق email-as-username وهو مُوثَّق بشكل كبير، لأنه قد يكون مربك قليلًا التعامل معه لأول مرة لذلك يمكنك اتباع تعليمات التثبيت (installation instructions)بحرص، ومن الممكن أن تفيدك أيضًا مقالة تخصيص إعداداتك (customize your setting) للتأكد من أنك قد استخدمت كل الإعدادات التي تحتاجها لتفعيل ميزة محددة. التعامل مع استيثاق المستخدمين ضمن هيكيلية REST Framework: django-rest-auth في حال كان عملك كمطور جانغو يتطلب منك كتابة تطبيقات APIs فإنك على الأرجح تستخدم هيكلية Django REST Framework (DRF)، وعلى الأغلب تعاملت مع حزمة django-rest-auth وهي حزمة تمكننا من تسجيل المستخدمين، تسجيل عمليات الدخول والخروج، إعادة تعيين كلمات المرور، استيثاق وسائل التواصل الاجتماعي (وذلك من خلال إضافة django-allauth والتي تعمل بشكل جيد مع django-rest-auth). تطبيقات الإظهار ضمن هيكلية Django REST Framework API: django-rest-swagger يوفر Django REST Swagger واجهة تعامل بالميزات للتفاعل مع Django REST Framework API، فبعد تثبيت Django REST Swagger وإضافته للبرنامج المثبت مسبقًا يمكنك إضافة Swagger View بالإضافة إلى نمط عنوان URL pattern للملف ruls.py الخاص بـواجهتك البرمجية. تتضمن واجهة المستخدم الخاصة بتطبيقك كل نقط النهاية والتوابع المتاحة مصنفة حسب التطبيق، كما تظهر أيضًا قائمة بالعمليات المتاحة لنقط النهاية هذه والتي تسمح لك بالتفاعل مع الواجهة البرمجية (عمليات الإضافة، الحذف، جلب السجلات على سبيل المثال) كما يمكن توليد توثيق لكل نقطة نهاية وبالتالي سينتج لدينا مجموعة مستندات توثيق خاصة بالمشروع والتي تفيدك كمطور وتفيد مطوري الواجهات الأمامية والمستخدمين. ترجمة –وبتصرّف– للمقال 8 Python packages that will simplify your life with Django لصاحبيه Lacey Williams Henschel و Jeff Triplett
- 1 تعليق
-
- حزم بايثون
- django
-
(و 1 أكثر)
موسوم في:
-
بعد أن تعرّفنا على أساسيات لغة بايثون حان الوقت للانتقال إلى مرحلة جديدة. في هذه السّلسلة من الدّروس سنتعرّف على أساسيات تطوير تطبيقات الويب بلغة بايثون، وذلك بالاستعانة بإطار العمل Flask، يعتبر Flask إطارا مُصغّرا Micro-Framework أي أنّه يُقدّم للمُبرمج أدوات مُساعدة بسيطة، وبعكس إطار Django فهو مُناسب للمُبتدئين الذين تعرّفوا على لغة بايثون حديثا. متطلبات هذه السلسلة لمتابعة هذه الدّروس وفهمها، ستحتاج إلى معرفة بسيطة بلغة بايثون. ستحتاج كذلك إلى معرفة بسيطة بلغة HTML الهيكلية، وكذلك القليل من لغة CSS لتنسيق الصّفحات إذ لن أشرح ما يتعلق بلغة HTML وCSS لأنّ ذلك ليس من اختصاص السّلسلة. يمكنك مراجعة الدروس التالية على أكاديمية حسوب لتعلم أساسيات هذه اللغات: سلسلة دروس تعلم لغة بايثون تعلّم لغة HTML ولغة CSS ما هو تطبيق الويب؟ تطبيق الويب، هو كل تطبيق يُمكن الوصول إليه عن طريق مُتصفّح للويب (Firefox ،Chrome ،Safari) ويقوم بتقديم صفحات مرئية حسب طلب الزّائر. يُمكن اعتبار موقع الأكاديمية هذا تطبيق ويب، إذ يتفاعل مع الزائر بتقديم المقالات بشكل متناسق، ويوفّر إمكانية المُشاركة للمُستخدمين عبر صندوق التّعليقات وغير ذلك من الخصائص. الصفحة التي تقرأ منها هذا المقال حاليا أصلها شيفرات لغة HTML وهي لغة أساسية في الويب. وتُستعمل لغات البرمجة مثل لغة Python لتقديم شيفرة HTML من الخادوم إلى المُتصفّح الذي يعرضها بدوره للمُستخدم. ما يعني أنّ الهدف النهائي من برمجة التّطبيق هو تقديم ملفات HTML من الخادوم إلى العميل (المُستخدم). خلاصة القول أنّك عندما تدخل إلى موقع الأكاديمية عن طريق رابط academy.hsoub.com، يرسل المُتصفّح طلبا للخادوم الخاص بالأكاديمية، عندما يستقبل الخادوم الطلب يقوم مُباشرة بتنفيذ الشيفرة المكتوبة بلغة برمجية، الشيفرة البرمجيّة تُجيب بملفات HTML ويعرضها لك المُتصفّح فور استقبالها. ما سنتعلّمه في هذه السّلسلة هو كيفيّة التعامل مع طلبات المُستخدم وكيفيّة تقديم ملفات HTML للمُتصفّح باستخدام لغة بايثون. ما هو إطار العمل؟ إطار العمل هو مجموعة من المكتبات والوحدات التي تحتوي على دوال مُساعدة تُمكّن المُبرمج من كتابة تطبيقات دون الاضطرار إلى التعامل مع التفاصيل الدقيقة التي تتطلب وقتا وجهدا كبيرين. يُمكن أن يكون إطار العمل خاصا بتطوير تطبيقات الويب مثل Flask أو Django، ويُمكن كذلك أن يكون مُخصّصا لمجالات أخرى كبناء تطبيقات سطح المكتب مثلا. تتوفّر لغة بايثون على العديد من أطر العمل الخاصّة بتطوير الويب، والتالي قائمة ببعض الأطر مع وصف مختصر لكلّ إطار. Django: إطار عمل ضخم، يتوفّر على عدد هائل من الدوال المُساعدة، كما يعتبر أنسب خيار لمن يرغب بتطوير تطبيقات كبيرة ومُعقّدة متعدّدة الوظائف، يتميّز بشهرته الواسعة وهو سهل التّعلم، يعتبر مناسبا كذلك لمن يرغب بإنشاء تطبيق بسرعة وهو شائع بين الشّركات النّاشئة. Flask: إطار عمل مُصغّر/صغير، يتوفّر على عدد لا بأس به من الدوال المُساعدة، شهرته تقريبا بنفس شهرة Django، مُناسب لتطوير تطبيقات صغيرة ومُتوسّطة (مُدونة، منتدى، موقع شخصي… ). Tornado: إطار عمل مُخصّص للتطبيقات التي تتطلب سرعة في مُعالجة الطّلبات وسرعة في التجاوب كتطبيقات الدّردشة مثلا. Bottle: إطار عمل صغير جدا، يوفّر أدنى المُتطلبات لتطوير تطبيق بسرعة، ويعتبر أصغر من إطار Flask. سبق وأن نشرنا درسا عنه. TurboGears: خصائصه تقترب من خصائص إطار Django، الاختلاف الرئيسي يكمن في الأدوات والمكتبات التي يعتمد عليها كالاتصال بقواعد البيانات وما إلى ذلك ويُعتبر خيارا آخر لمن يرغب بتطوير تطبيقات كبيرة. صحيح أن هناك أطر عمل أخرى لكنّ ما تقدّم ذكره يعتبر أبرزها. لماذا Flask؟ وقع الاختيار على إطار العمل Flask لسهولة تعلّمه بالنّسبة للمبتدئ، إذ سيبدو مألوفا لمن تعرّف حديثا على لغة بايثون، وبما أنّه إطار عمل مُصغّر فسيسهل عليك فهم خطوات إنشاء تطبيق كامل، خاصّة أنّك تستطيع أن تبني تطبيقا في ملفّ بايثون واحد. يتميّز إطار Flask كذلك بإتاحة إمكانيّة ربط تطبيقك بمُختلف مكتبات لغة بايثون، والتي يُمكنك تنصيبها بسهولة بأداة pip، وهي أداة لإدارة الحزم (مثل Gem بالنّسبة للغة روبي و Composer بالنّسبة للغة PHP). يُمكن كذلك الاعتماد على إضافات لجعل الإطار أقرب إلى الأطر الكبيرة مثل Django إذ يمتلك إطار العمل Flask العديد من الإضافات التي يُمكنك تنصيبها واستعمالها في مشروعك، ما يُمكن أن يُساعدك على إنشاء مشاريع كبيرة. Flask أم Django؟ يعتبر الاختيار بين إطار Flask وإطار Django من القرارات الصّعبة على المُبتدئ، لكنّ عليك فهم الفرق بين الإطارين لتختار ما يُناسبك، فكما قلنا سابقا فإطار Django يُوفّر عددا هائلا من الدوال والأدوات المُساعدة، أما إطار Flask فيُوفّر أدوات بسيطة وعددا أقلّ من الدوال المُساعدة. يُمكنك اختيار تعلّم إطار Django إذا كانت لديك خبرة مُسبقة بأحد أطر العمل في اللغات الأخرى مثل Laravel أو Ruby On Rails، كما يُنصح به إذا كان المشروع الذي ستعمل عليه كبيرا كتطبيق تواصل اجتماعي أو تطبيق خدمي. أما إذا لم تكن تملك أية خبرة مُسبقة فأنصح بتعلّم إطار Flask أولا، وبعد التمكن من التعامل معه وإتقان ذلك يُمكنك الانتقال إلى استعمال Django متى ما دعت الحاجة إلى ذلك، وستجد حينها بأنّ الوقت الذي استثمرته في تعلّم Flask قد أتى أكله، وسيسهل عليك تعلّم إطار Django وفهم كيفيّة عمله. كيف تستفيد من هذه السلسلة من الدروس؟ سلسلة الدروس هذه ستكون موزعة حسب المُخطّط التالي: إعداد بيئة التّطوير وإنشاء تطبيقك الأول تقديم ملفات HTML وملفات CSS والصور استخدام قاعدة بيانات مع تطبيق Flask كل درس سيكون شبه مُستقل عن الدّرس الذي يسبقه، وذلك لتكون الدروس مرجعا لك في حالة نسيان أي جزئية. في نهاية السّلسلة ستكون قادرا على استعمال لغة بايثون لتطوير تطبيق يعمل على المُتصفّح ويتصل بقاعدة بيانات. ختاما في الدّرس المُقبل سنقوم بإعداد بيئة التّطوير بتنصيب الأدوات المطلوبة، كما سننشئ تطبيقا بسيطا لعرض صفحة ويب على المُتصفّح.
-
يحتار المطورون في اختيار أفضل إطار لمشاريعهم وسيكون هذا تحديًا حقيقيًا للمبتدئين في الأطر الحديثة. بعد العمل على الأطر الثلاثة (Django، Laravel و Rails – والذي يُعرف باسم Ruby On -rails)، سأقارن بين هذه الأطر الرائعة على أساس شعارها، سهولة تعلمها، أدائها، قوة وضعف مكتباتها وقوالبها، دعمها، آفاقها المستقبلية، فرص العمل، التكلفة والصيانة. ملاحظة: ينتقد بعض المعجبين عند التحدث عن نقاط ضعف أطرهم، ولا أستطيع فعل أي شيء لأنه لا يمكن إخفاء الحقيقة، كل إطار لديه بعض المزايا مع بعض العيوب. المقدمة لغة البرمجة أهم فرق بين هذه الأطر هي أن Django بلغة بايثون، Laravel بلغة PHP وRails بلغة الروبي، لذا إذا كنت تنوي استخدام أي من هذه الأطر فيجب عليك تعلم لغتها أولاً، وبسبب هذا، العديد من المطورين يختارون الإطار الذي يتطابق مع اللغة التي يعرفونها. إن التحول من لغة إلى أخرى ليس صعبًا بل يحتاج إلى بعض الوقت، وإذا احترت في اختيار لغة البرمجة، فهذه مقارنة بين لغات بايثون و PHP وروبي. الشعار جميع هذه الأطر من نوع MVC وشعارها ‘لا تكرر نفسك’ أي تدعم إعادة الاستخدام وقابلية النقل، وجميعها مشاريع مجانية ومفتوحة المصدر. المواقع بعض المواقع المعروفة تستخدم Django مثل Pinterest، Instagram، Mozilla، The Washington Times، Disqus، the Public Broadcasting Service و Bitbucket. في حين أن Laravel هو إطار جديد، حيث صدر في يونيو عام 2011، لكنه أصبح مشهورا جدا، ومن بين المواقع التي تستخدمه هي Deltanet Travel، Sublimity، Neighborhood Lender، Sendity و MyRank. يعتبر Rails من الأطر الرائعة فمن المواقع التي تستخدمه Twitter، Shopify، SoundCloud، Heroku، Github، Bloomberg و Hulu. سهولة التعلم على الرغم من أن الأطر الثلاثة لديها مجتمعات كبيرة وتوثيق رسمي، إلا أن تعلم Django وLaravel أسهل بكثير من تعلم Rails، فالتوثيق الحالي ل Django يجعلها الأسهل، وإذا كنت تملك خلفية PHP فيمكنك تعلم Laravel في غضون أسبوعين أو ثلاثة أسابيع، وهذه هي الوثائق الرسمية: وثائق Django ووثائق Laravel وثائق Rails. الأداء الأمن جميع هذه الأطر آمنة جدا إذا لم يرتكب المبرمج أخطاء، فيمتلك Django برمجيات وسيطة ويمتلك Rails Active Records وأما Laravel فيمتلك برمجيات HTTP وسيطة، وتوفر كل هذه الأطر رموز csrf للنماذج. لا يوجد فرق أمني كبير بين هذه الأطر، وكل هذا يعتمد على خبرة المبرمج. تحديث:أشار بعض القراء أن المبرمجين هم بشر وسيخطئون، لذا سأقول في هذه الحالة أن Django هو الأكثر أمانا وLaravel هو الأقل أمانًا، اطلع على هذا التوثيق عن أمن Django وهذا دليل أمن Rails و هذا دليل أمن Laravel، وسأقول أيضا أنه لا يوجد إطار آمن بشكل كامل لأن المطورين هم أيضا بشر، ويمكنك زيادة الأمن لكنك لا تستطيع جعله آمن بنسبة 100%، لكن إذا كتبت التعليمات البرمجية بعناية وحذر فإن جميع الأطر متساوية من ناحية الأمن. السرعة جميع الأطر مكتوبة بشكل صحيح، لذلك سرعتها تعتمد على اللغة البرمجة المستخدمة، فDjango هو الأسرع بسبب البايثون و Laravel هي الأبطأ بسبب PHP. الوقت المطلوب لإنشاء تطبيق إذا كنت تفهم الإطار بشكل كامل فإن إنشاء تطبيق Rails هو الأسرع لأنه يوفر لك الكثير من الاختصارات وبهذا ستكتب أقل عدد من الأسطر البرمجية. ومن جهة أخرى، Laravel هو الأبطأ ولا يوفر مكتبة قوية. إذا كان المشروع معقد فإن الفرق الزمني بين تطبيقات Django وRails سيكون صغيرًا بسبب صياغة بايثون المريحة للمتابعة وأقل أرباك، أما بالنسبة لـ Laravel فيجب عليك كتابة الكثير من الأسطر البرمجية وهذا قد يسبب لك بعض الإرباك وسترتفع نسبة الأخطاء. قوة وضعف المكتبة الأشياء المشتركة في جميع الأطر: جميعها MVC (يسمى Django MTV أيضا لكن على الرغم من أن الاسم مختلف إلا أن المفهوم هو نفسه). تركز جميع الأطر على قابلية القراءة وبساطة الشيفرة البرمجية وتوزيع الملفات. جميعها تستعلم تلقائيًا من قاعدة البيانات، فلا يجب عليك كتابة استعلامات قاعدة البيانات بشكل مباشر. تبنى الجداول تلقائيا في قاعدة البيانات من النماذج (models). جميع الأطر تملك نظام توجيه سهل وآمن، وتعرض صفحات الويب بشكل حيوي. تملك جميعها أنظمة قوالب خاصة بها وكل نظام قوالب غني بالمرشحات والدوال المعرّفة مسبقًا، الفرق الوحيد في الصياغة. جميعها مرنة ومحمولة مع تقنيات حديثة أخرى. Django يمتلك Django مكتبة قوية مع المميزات التالية: يعتبر قسم الإدارة المدمجة، المزخرف (decorator)، وأصناف المناظر نقاط قوة ل Django. الاستمارات المولدة تلقائيا للنماذج مع عملية التحقيق تجعلها سهلة للغاية. يدعم الإطار خاصية التخزين المؤقت وستتمكن من استخدام أي من أساليب التخزين المؤقت المتاحة. يدعم الأصناف البرمجيات الوسطيّة والتي يمكن أن تتدخّل في مراحل مختلفة من معالجة الطلب وتُنفّذ دوال مخصصة. يسمح لك نظام مرسل (dispatcher) داخلي لمكونات التطبيق اتصال الأحداث مع بعضها البعض عبر إشارات محددة مسبقا. يملك نظام تدويل يتضمن ترجمات لمكونات Django إلى لغات مختلفة. يملك نظام تسلسل الذي يمكنك من إنتاج وقراءة تمثيل XML و/أو JSON لمثيلات نموذج Django. واجهة بايثون مدمجة في إطار اختبار الوحدة. نظام مصادقة (authentication) موسّع. واجهة إدارة حيوية. أدوات لتوليد RSS وتغذيات (feed) خلاصات Atom. إطار مواقع تسمح ل Django واحد بتشغيل مواقع متعددة، ولكل منها المحتوى والتطبيقات الخاصة به. يملك أدوات لتوليد Google Sitemap. يملك تقنيات مدمجة للتخفيف من التزوير عبر الموقع، ثغرات XSS، ثغرات حقن SQL، تكسير كلمات المرور وهجمات الويب النموذجية، ومعظمها يعمل افتراضيا. إطار لإنشاء تطبيقات GIS. Laravel على الرغم من أن مكتبات Laravel ليست قوية مثل Django وRails إلا أنها كافية لإنشاء أي نوع من المواقع. يوفر Bundles و composer عدد من حزم نظام وحدات التحزيم والاعتماديات. التوجيه (Routing) – يوّفر طريقة سهلة وبسيطة لإدارة وتوجيه الروابط إلى متحكم أو دالة تُنفَّذ عند زيارة رابط محدَّد. دعم Eloquent ORM – خدمة أخرى مقدمة لتجريد وأتمتة جزء النموذج، حيث سنطبق التقنيات المتعارف عليها على الإعدادات. التهجيرات – طريقة لإصدار سكربتات قواعد البيانات بطريقة أنيقة للغاية، فلا حاجة للحفاظ على جميع التحققات على التهجيرات، يمكن لفريق عمل المشروع سحب الهجرة المقدمة وستعيّن جميعها وستكون جاهزة للعمل. إدارة قائمة الانتظار (Queue management) – لتجريد المهام غير الضرورية ووضعهم في قائمة الانتظار وجعل وقت استجابة المستخدم أسرع بكثير. دعم Redis، ويمكن توسيعها إلى memcached. حقن الإعتماديّة – اختبار سهل وأتمتة تحميل الإعتماديّة. Artisan – لإنشاء تطبيقات سطر الأوامر في لحظة. تعلم استخدام Laravel عن طريق هذه الدروس. Rails يتضمن Rails أدوات لجعل مهام التطوير الشائعة أسهل (خارج الصندوق)، مثل scaffolding الذي يستطيع إنشاء بعض النماذج تلقائيًا والمناظر اللازمة لموقع ويب الأساسي، بالإضافة إلى WEBrick وهو خادم ويب روبي بسيط الموزع مع روبي و Rake والذي هو نظام بناء موزع كـ gem. وتوفر هذه الأدوات جنبا إلى جنب مع Rails بيئة تطوير أساسية. Active record: يلعب دورا رئيسيا في تطبيقات Rails، وهو أفضل من Eloquent ORM في Laravel ومن النماذج في Django. اختصارات: يعبر الكثير من الناس الذين يأتون من لغات برمجة أو إطارات أخرى أن هذا الإطار سحري بسبب الاختصارات الكثيرة، فأغلب الأشياء معرّفة مسبقًا ويجب عليك كتابة بعض الأسطر البرمجية لإنشاء تطبيقات معقدة. التوجيه التلقائي: بعض الدوال الشائع في جدول قاعدة البيانات مثل الإنشاء ، التعديل والعرض مُعرّفة تلقائيًا، وهذا يعني أننا لا نحتاج إلى تضييع الوقت في المهام البسيطة ويمكننا قضاء وقت أطول على الأجزاء المعقدة من المشروع. سطر الأوامر: الكثير من الأشياء يمكن إنجازها عن طريق سطر الأوامر مثل استخدام rake وهي Ruby Make، أداة روبي مستقلة تستبدل أداة يونكس 'make' وتستخدم 'Rakefile' وملفات .rake لبناء قائمة مهام. في Rails، يُستخدم Rake لمهام الإدارة الشائعة، خاصة المعقدة منها التي تبني من بعضها البعض. تحتوي وحدة ActiveModelHelper على أساليب المساعدة لإنشاء النماذج من الكائنات بسرعة التي تتبع اتفاقيات Active Model، بداية من Active Record. خدمات الاستضافة يمكنك تشغيل أي تطبيق على VPS أو على خدمة استضافة مخصصة، وهذه مجموعة من الروابط لمواقع تسمح لك باستضافة مشروعك مجانا أو على خطط الاستضافة المشتركة. Django: بعض من المواقع التي تستضيف مشاريع Django هي: WebFaction، PythonAnywhere ، Heroku ، Digital Ocean ، Bulehost ، Dreamhost ، Arvixe و Google App Engine. Laravel: يمكنك الاستضافة على Heroku ، Bulehost ، Inmotion Hosting ، Site5 ، Dreamhost ، Digital Ocean و Arvixe. Rails: مواقع لتطبيقات Rails هي: Heroku ، Bulehost ، Dreamhost ، Arvixe ، Hosting24 و Digital Ocean. معايير أخرى كل هذه الأطر جيّدة في المستقبل، ففرص العمل، التكلفة والصيانة هي تقريبا نفسها ويمتاز Rails على Django وLaravel في شروط العمل، على الرغم من سرعة نمو Laravel. خاتمة يمكنك أن تختار أي واحدة من هذه الأطر حسب لغة البرمجة والخبرة، وإذا كنت هنا لتقرر أي واحدة يجب عليك تعلمها فأنا أفضل Rails، فعلى الرغم من صعوبة تعلمها إلا أنها مريحة أثناء إنشاء التطبيقات، إذا أردت أشياء سهلة مع الكثير من المميزات فاختر Django، فصياغة بايثون ونماذجه تجعله خيار جيدا، وعلى الرغم من أن تعلم Django قد يستغرق بعض الوقت إلا أنه ليس أصعب من Rails.إذا كانت لدي خبرة في PHP أو إذا أردت التعلم بسرعة فاختر Laravel. ترجمة -وبتصرّف- للمقال Django vs Laravel vs Rails لصاحبه Harish Kumar
-
چانجو هو إطار عمل مرن يستخدم ﻹنشاء تطبيقات بلغة بايثون، وهذه التطبيقات مُجهزة تلقائيًا لتخزين البيانات في ملف قاعدة بيانات SQLite خفيف ويعمل بشكل جيد في الاستعمالات العادية والصغيرة، لكن استخدام نظام إدارة قواعد بيانات تقليدي سيطوِّر أداء التطبيق تحت ضغط زيادة المستخدمين أو زيادة حجم البيانات. وسنستعرض في هذا الدليل كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django، وسنثبّت الحزم اللازمة وننشئ اعتماديات قاعدة البيانات للتطبيق، ثم نبدأ مشروع Django جديد ونجهّزه ليستخدم هذه اﻹعدادات. المتطلبات خادم يعمل بتوزيعة ديبيان جنو/لينكس إصدار 8 “Jessie” مع مستخدم -غير الجذر- له صلاحية sudo. تثبيت الحزم من مستودعات ديبيان سنثبّت أولًا pip -مدير حزم بايثون- لتثبيت وإدارة حزم بايثون، وسنثبّت أيضًا برنامج قاعدة البيانات والمكتبات اللازمة للتفاعل معهم. يحتاج إصدار بايثون 2 و3 إلى حزم مختلفة قليلًا عن بعضها، لذا اختر الأوامر التي تتوافق مع إصدار بايثون لديك. انسخ الأوامر التالية إن كنت تستخدم بايثون 2: $ sudo apt-get update $ sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib وهذه إن كنت تستخدم بايثون 3: $ sudo apt-get update $ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib إنشاء قاعدة البيانات والمستخدم الخاص بها يستخدم Postgres نظام توثيق للاتصالات المحلية اسمه “توثيق النِّدّ Peer Authentication”. وهذا يعني أنه إذا كان اسم المستخدم في نظام التشغيل يطابق اسم Postgres صالح، فإن هذا المستخدم يمكنه الولوج دون الحاجة إلى توثيق. وقد أُنشئ مستخدم للنظام اسمه postgres ليتوافق مع مستخدم postgres المدير لنظام PostgreSQL، وسنحتاج هذا المستخدم لتنفيذ مهام إدارية، ويمكننا أيضًا أن نستخدم sudo وندخل اسم المستخدم من خلال لاحقة u-. سجل الدخول إلى جلسة Postgres تفاعلية عبر كتابة الأمر التالي: $ sudo -u postgres psql وسننشئ أولًا قاعدة بيانات لمشروع Django، ويجب أن يكون لكل مشروع قاعدة البيانات الخاصة به للدواعي الأمنية. وسنسمّي قاعدة البيانات في هذا المقال باسم myproject، لكن من اﻷفضل طبعًا أن تختار اسمًا يصلح لمشروع حقيقي. postgres=# CREATE DATABASE myproject; سيكون الخرج هكذا: CREATE DATABASE أنشئ مستخدمًا لقاعدة البيانات، وسنستعمله للاتصال بقاعدة البيانات والتفاعل معها، وﻻ تنس أن تستبدل myprojectuser باسم قاعدة البيانات الذي اخترته، وتغيّر password بكلمة سر قوية: postgres=# CREATE USER myprojectuser WITH PASSWORD 'password'; سيكون الخرج هكذا: CREATE ROLE واﻵن سنعدّل بعض معاملات الاتصال لهذا المستخدم لتسريع عمليات قاعدة البيانات بما أن القيم الصحيحة لن تضطر إلى أن تمر بعمليات استعلام وضبط في كل مرة يحدث اتصال. فسنضبط الترميز الافتراضي على UTF-8 وهو الترميز الافتراضي الذي يتوقعه Django. وسنضبط القاعدة الافترضية لعزل التعاملات “default transactio isolation scheme” على read committed، والتي تحظر القراءة من التعاملات غير المرسلة “uncommitted transactions”. وأخيرًا، سنضبط المنطقة الزمنية الافتراضية لمشاريع Django على UTC. وهذه الإعدادات يُنصح بها في التوثيق الرسمي لمشروع Django، دعنا نكتب ذلك الآن: postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8'; postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed'; postgres=# ALTER ROLE myprojectuser SET timezone TO 'UTC'; ويكون الخرج هكذا: ALTER ROLE ALTER ROLE ALTER ROLE وكل ما نحتاجه الآن هو إعطاء مستخدم قاعدة البيانات صلاحيات الوصول لقاعدة البيانات التي أنشأناها للتو: postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser; ويكون الخرج هكذا: GRANT اخرج الآن من محث SQL: postgres=# \q يجب أن تعود الطرفية بك الآن إلى جلسة shell السابقة. تثبيت Django في بيئة افتراضية يمكننا تثبيت Django الآن بما أن قاعدة بياناتنا قد صارت جاهزة، وسنثبته وكل اعتمادياته داخل بيئة بايثون افتراضية لتحقيق مرونة أكثر، وستتيح لنا حزمة virtualenv إنشاء هذه البيئات بسهولة. اكتب هذا السطر في الطرفية لتثبيت virtualenv إن كنت تستخدم Python 2: $ sudo pip install virtualenv وهذا إن كنت تستخدم Python 3: $ sudo pip3 install virtualenv أنشئ مجلدًا جديدًا باسم مشروعك (استبدل اسم مشروعك بـ myproject الذي اخترناه هنا لغرض المثال فقط)، ثم انتقل داخله: $ mkdir ~/myproject $ cd ~/myproject اكتب السطر التالي لإنشاء بيئة افتراضية لتخزين متطلبات بايثون لمشروع Django الخاص بنا: $ virtualenv venv وذلك سيثبّت نسخة محلية من بايثون وأمر pip محلي داخل مجلد اسمه venv داخل مجلد مشروعك. نحتاج الآن إلى تفعيل البيئة الافتراضية قبل تثبيت البرامج داخلها، ويمكننا فعل ذلك عبر الأمر التالي: $ source venv/bin/activate سيتغير المحثّ الآن ليشير إلى أنك تعمل الآن داخل بيئة افتراضية وسيبدو شبيهًا بهذا: (venv)user@host:~/myproject$ ويمكننا الآن تثبيت Django باستخدام pip، ثم سنثبت psycopg2 التي ستتيح لنا استخدام قاعدة البيانات التي أعددناها: (venv) $ pip install django psycopg2 يمكننا الآن أن نبدأ مشروع Django داخل مجلد المشروع (myproject في حالتنا)، وسينشئ هذا مجلدًا فرعيًا بنفس اسم مجلد المشروع ليحتوي الشفرة البرمجية، إضافة إلى مخطوطة إدارية “management script” داخل المجلد الحالي: (venv) $ django-admin.py startproject myproject . ملاحظة: تأكد من إضافة النقطة في نهاية الأمر السابق، فنحن ﻻ نحتاج مستوىً فرعيًا آخر في المجلد بما أننا أنشأنا مجلدًا أبًا للمشروع “parent directory” ليحتوي مجلد البيئة الوهمية، وهو ما كان سيحدث لو لم نضع النقطة في نهاية سطر الأوامر السابق. يجب أن تكون هيكلة مجلدك الحالي شبيهة بهذا: . └── ./myproject/ ├── manage.py ├── myproject/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── venv/ └── . . . وكما ترى فإن لدينا مجلدًا أبًا للمشروع يحتوي مخطوطة manage.py، ومجلد داخلي للمشروع، ومجلد البيئة الوهمية venv الذي أنشأناه قبل قليل. ضبط إعدادات قاعدة بيانات Django سنضبط الآن مشروعنا كي نستخدم قاعدة البيانات التي أنشأناها، افتح ملف الإعدادات الرئيسية لمشروع Django الموجود في المجلد الفرعي للمشروع: (ملاحظة: استبدل مشروعك بـmyproject) (venv) $ nano ~/myproject/myproject/settings.py قد تحتاج أيضًا إلى تعديل تعليمة ALLOWED_HOSTS قبل إعداد قاعدة البيانات، وتلك التعليمةتحدد قائمة عناوين أو أسماء نطاقات مسموح باستخدامها للاتصال مع مشروع Django، فأي طلب اتصال بترويسة HOST ليس في هذه القائمة سيتم اعتراضه. ويتطلّب Django أن تعدّل هذه التعليمة كي يمنع فئة معينة من الاختراقات الأمنية. ولتعديل هذه التعليمة، أدخل -بين قوسين مربعيْن- عناوين IP أو أسماء النطاقات المرتبطة بخادم Django الخاص بك ويجب أن يكون كل نطاق أو عنوان IP داخل علامتي تنصيص مفردتيْن، وتفصل بين كل واحد منهم فاصلة “,”. وإن رغبت في الاستجابة لطلبات من نطاق ما إضافة إلى النطاقات الفرعية له فضع نقطة قبله أثناء كتابته. إليك أمثلة تعرض لك الطريقة الصحيحة لصيغة هذه التعليمة، استبدل النطاقات وعناوين الـ IP التي تريدها بالأمثلة الموجودة هنا: . . . # أبسط حالة: اكتب العناوين وأسماء النطاقات لخادم چانجو الخاص بك # ALLOWED_HOSTS = [ 'example.com', '203.0.113.5'] # ابدأ اسم النطاق بنقطة للاستجابة له ولأي نطاق فرعي # ALLOWED_HOSTS = ['.example.com', '203.0.113.5'] ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .] واﻵن ابحث عن قسم DATABASES الذي يبدو كهذا: . . . DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } . . . هذا القسم يستخدم SQLite كقاعدة بيانات، ونريد تعديل هذه لكي يستخدم قاعدة بيانات PostgreSQL الخاصة بنا. فأول ما نفعله هو تغيير المحرك كي يستخدم محوّل postgresql_psycopg2 بدلًا من sqlite3، ثم نستخدم اسم قاعدة بياناتنا (myproject في مثالنا) في خانة NAME، ونضيف بعض بيانات تسجيل الدخول مثل اسم المستخدم وكلمة المرور، والمضيف الذي سيتصل به، وسنضيف خانة Port ونتركها فارغة كي يتم اختيار المنفذ الافتراضي: . . . DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'myproject', 'USER': 'myprojectuser', 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '', } } . . . واﻵن احفظ الملف وأغلقه. نقل قاعدة البيانات واختبار مشروعك يمكننا الآن نقل هياكل البيانات -بما أننا أنهينا ضبط إعدادات Django- إلى قاعدة بياناتنا واختبار الخادم، سنبدأ بإنشاء هيكل ابتدائي لقاعدة البيانات بما أننا ﻻ نملك أي بيانات حقيقية بعد: (venv) $ cd ~/myproject (venv) $ ./manage.py makemigrations (venv) $ ./manage.py migrate أنشئ حسابًا إداريًا: (venv) $ ./manage.py createsuperuser وسيطلب منك النظام اختيار اسم لمستخدم هذا الحساب وعنوان بريد وكلمة مرور له. ملاحظة: قبل أن تجرب خادم التطوير، تأكد أن تفتح منفذًا في جدارك الناري، وإن كنت تستخدم جدار ufw، فإن فتح المنفذ المناسب يتم عبر كتابة هذا الأمر: (venv) $ sudo ufw allow 8000 أما إن كنت تستخدم جدار iptables، فإن الأمر الذي تحتاجه يعتمد على اﻹعدادات التي تستخدمها، الأمر التالي يصلح ﻷغلب الإعدادات: (venv) $ sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT يمكنك الآن اختبار عمل قاعدة بياناتك بشكل صحيح من خلال بدء تشغيل خادم تطوير Django: (venv) $ ./manage.py runserver 0.0.0.0:8000 اذهب إلى عنوان IP الخاص بالخادم أو اسم النطاق الخاص به متبوعًا بـ 8000: للوصول إلى الصفحة الجذر الافتراضية لـDjango: http://server_domain_or_IP:8000 يجب أن ترى صفحة index الافتراضية: ضع admin/ في نهاية الرابط، يجب أن تكون قادرًا على الوصول لشاشة تسجيل الدخول إلى واجهة التحكم: أدخل اسم المستخدم وكلمة المرور اللتان أنشأتهما قبل قليل باستخدام createsuperuser، فتدخل إلى لوحة التحكم: وبدخولنا للوحة التحكم نكون قد تأكدنا أن قاعدة البيانات قد خزّنت معلومات حساب المستخدم الخاص بنا ويمكننا الدخول إليه دون مشاكل. يمكنك الآن إيقاف الخادم حين تنتهي من تحققك بالضغط على ctrl-c داخل شاشة الطرفية. وإن أردت وسيلة أخرى لاختبار قاعدة البيانات يمكنك الاستعلام داخل قاعدة بيانات Postgres نفسها باستخدام psql، فمثلًا يمكنك الاتصال بقاعدة بيانات مشروعك (myproject) عن طريق المستخدم myprojectuser وإظهار كل الجداول المتاحة بكتابة الأمر التالي: (venv) $ psql -W myproject myprojectuser -h 127.0.0.1 -f <(echo '\dt') لتفصيل اﻷمر السابق، فإنه يجب أن نستخدم ﻻحقة h- من أجل الاتصال بالمضيف المحلي localhost عبر الشبكة لتحديد أننا نريد توثيق كلمة المرور بدلًا من توثيق النّدّ. أما W- فستجعل psql يسألك عن كلمة المرور المناسبة، وf- لتمرير الأمر الوصفي “meta-command” في psql لتنفيذه، وdt\ لعرض كل الجداول في قاعدة البيانات. List of relations Schema | Name | Type | Owner --------+----------------------------+-------+--------------- public | auth_group | table | myprojectuser public | auth_group_permissions | table | myprojectuser public | auth_permission | table | myprojectuser public | auth_user | table | myprojectuser public | auth_user_groups | table | myprojectuser public | auth_user_user_permissions | table | myprojectuser public | django_admin_log | table | myprojectuser public | django_content_type | table | myprojectuser public | django_migrations | table | myprojectuser public | django_session | table | myprojectuser (10 rows) وكما ترى فإن Django قد أنشأ بعض الجداول داخل قاعدة البيانات الخاصة بنا، وهذا يؤكد لنا أن إعداداتنا كانت صحيحة. الخلاصة قد عرضنا في هذا الدليل كيفية تثبيت وإعداد PostgreSQL كقاعدة بيانات في النهاية الخلفية لمشروع Django، إذ تستفيد أغلب المشاريع من استخدام نظم إدارة متطورة لقواعد البيانات، رغم أن SQLite تتعامل بشكل جيد أثناء تطوير المشروع وأثناء الاستخدام الخفيف له. ترجمة -بتصرف- لمقال How To Use Postgresql with your Django Application on Debian 8 لصاحبه Justin Ellingwood.
-
- postgresql
- sqlite
-
(و 2 أكثر)
موسوم في:
-
Django هو إطار عمل مرن يستخدم ﻹنشاء تطبيقات بلغة بايثون، وهذه التطبيقات مُجهزة تلقائيًا لتخزين البيانات في ملف قاعدة بيانات SQLite خفيف ويعمل بشكل جيد في الاستعمالات العادية والصغيرة، لكن استخدام نظام إدارة قواعد بيانات تقليدي سيطوِّر أداء التطبيق تحت ضغط زيادة المستخدمين أو زيادة حجم البيانات. وسنستعرض في هذا الدرس كيفية تثبيت وتهيئة PostgreSQL لاستخدامها مع تطبيقات Django، وسنثبّت الحزم اللازمة وننشئ اعتماديات قاعدة البيانات للتطبيق، ثم نبدأ مشروع Django جديد ونجهّزه ليستخدم هذه اﻹعدادات. المتطلبات خادم يعمل بتوزيعة أوبنتو 16.04 مع مستخدم -غير الجذر- له صلاحية sudo. تثبيت الحزم من مستودعات أوبنتو سنثبّت أولًا pip -مدير حزم بايثون- لتثبيت وإدارة حزم بايثون، وسنثبّت أيضًا برنامج قاعدة البيانات والمكتبات اللازمة للتفاعل معهم. يحتاج إصدار بايثون 2 و3 إلى حزم مختلفة قليلًا عن بعضها، لذا اختر الأوامر التي تتوافق مع إصدار بايثون لديك. انسخ الأوامر التالية إن كنت تستخدم بايثون 2: $ sudo apt-get update $ sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib وهذه إن كنت تستخدم بايثون 3: $ sudo apt-get update $ sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib يمكننا الآن إنشاء قاعدة البيانات بما أننا أنهينا تثبيت هذه الحِزّم. إنشاء قاعدة البيانات والمستخدم الخاص بها يستخدم Postgres نظام توثيق للاتصالات المحلية اسمه "توثيق النِّدّ Peer Authentication”. وهذا يعني أنه إذا كان اسم المستخدم في نظام التشغيل يطابق اسم Postgres صالح، فإن هذا المستخدم يمكنه الولوج دون الحاجة إلى توثيق. وقد أُنشئ مستخدم للنظام اسمه postgres ليتوافق مع مستخدم postgres المدير لنظام PostgreSQL، وسنحتاج هذا المستخدم لتنفيذ مهام إدارية، ويمكننا أيضًا أن نستخدم sudo وندخل اسم المستخدم من خلال لاحقة u-. سجل الدخول إلى جلسة Postgres تفاعلية عبر كتابة الأمر التالي: $ sudo -u postgres psql وسننشئ أولًا قاعدة بيانات لمشروع Django، ويجب أن يكون لكل مشروع قاعدة البيانات الخاصة به للدواعي الأمنية. وسنسمّي قاعدة البيانات في هذا المقال باسم myproject، لكن من اﻷفضل طبعًا أن تختار اسمًا يصلح لمشروع حقيقي. ملاحظة: تذكر أن تنهي كل الأوامر في محث SQL بفاصلة منقوطة ; postgres=# CREATE DATABASE myproject; أنشئ مستخدمًا لقاعدة البيانات، وسنستعمله للاتصال بقاعدة البيانات والتفاعل معها، وﻻ تنسَ أن تستبدل myprojectuser باسم قاعدة البيانات الذي اخترته، وتغيّر password بكلمة سر قوية: postgres=# CREATE USER myprojectuser WITH PASSWORD 'password'; واﻵن سنعدّل بعض معاملات الاتصال لهذا المستخدم لتسريع عمليات قاعدة البيانات بما أن القيم الصحيحة لن تضطر إلى أن تمر بعمليات استعلام وضبط في كل مرة يحدث اتصال. فسنضبط الترميز الافتراضي على UTF-8 وهو الترميز الافتراضي الذي يتوقعه Django. وسنضبط النظام الافتراضي لعزل التعاملات "default transactio isolation scheme” على read committed، وذلك لحظر القراءة من التعاملات غير المرسلة "uncommitted transactions”. وأخيرًا، سنضبط المنطقة الزمنية الافتراضية لمشاريع Django على UTC. وهذه الإعدادات يُنصح بها في التوثيق الرسمي لمشروع Django، دعنا نكتب ذلك الآن: postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8'; postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed'; postgres=# ALTER ROLE myprojectuser SET timezone TO 'UTC'; وكل ما نحتاجه الآن هو إعطاء مستخدم قاعدة البيانات صلاحيات الوصول لقاعدة البيانات التي أنشأناها للتو: postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser; اخرج الآن من محث SQL: postgres=# \q تثبيت Django في بيئة افتراضية يمكننا تثبيت Django الآن بما أن قاعدة بياناتنا قد صارت جاهزة، وسنثبته وكل اعتمادياته داخل بيئة بايثون افتراضية لتحقيق مرونة أكثر، وستتيح لنا حزمة virtualenv إنشاء هذه البيئات بسهولة. اكتب هذا السطر في الطرفية لتثبيت virtualenv إن كنت تستخدم Python 2: $ sudo pip install virtualenv وهذا إن كنت تستخدم Python 3: $ sudo pip3 install virtualenv أنشئ مجلدًا جديدًا باسم مشروعك (استبدل اسم مشروعك بـ myproject الذي اخترناه هنا لغرض المثال فقط)، ثم انتقل داخله: $ mkdir ~/myproject $ cd ~/myproject اكتب السطر التالي لإنشاء بيئة افتراضية لتخزين متطلبات بايثون لمشروع Django الخاص بنا: $ virtualenv myprojectenv وذلك سيثبّت نسخة محلية من بايثون وأمر pip محلي داخل مجلد اسمه myprojectenv داخل مجلد مشروعك. نحتاج الآن إلى تفعيل البيئة الافتراضية قبل تثبيت البرامج داخلها، ويمكننا فعل ذلك عبر الأمر التالي: $ source myprojectenv/bin/activate سيتغير المحثّ الآن ليشير إلى أنك تعمل الآن داخل بيئة افتراضية وسيبدو شبيهًا بهذا: (myprojectenv)user@host:~/myproject$ ويمكننا الآن تثبيت Django باستخدام pip، ثم سنثبت psycopg2 التي ستتيح لنا استخدام قاعدة البيانات التي أعددناها: (ﻻحظ أنه يجب استخدام أمر pip وليس pip3 داخل البيئة الافتراضية بغض النظر عن نسخة بايثون التي لديك) (venv) $ pip install django psycopg2 يمكننا الآن أن نبدأ مشروع Django داخل مجلد المشروع (myproject في حالتنا)، وسينشئ هذا مجلدًا فرعيًا بنفس اسم مجلد المشروع ليحتوي الشفرة البرمجية، إضافة إلى مخطوطة إدارية "management script” داخل المجلد الحالي، ﻻ تنس إضافة النقطة التي في آخر الأمر التالي كي ﻻ يُنشأ مستوى فرعي جديد في المجلد: (venv) $ django-admin.py startproject myproject . سنضبط الآن مشروعنا ليستخدم قاعدة البيانات التي أنشأناها، افتح ملف الإعدادات الرئيسية لمشروع Django الموجود في المجلد الفرعي للمشروع: (ملاحظة: استبدل مشروعك بـmyproject) (myprojectenv) $ nano ~/myproject/myproject/settings.py ستجد قسم DATABASE في نهاية الملف، وسيبدو مشابهًا لهذا: . . . DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } . . . هذا القسم يستخدم SQLite كقاعدة بيانات، ونريد تعديل هذه لكي يستخدم قاعدة بيانات PostgreSQL الخاصة بنا. فأول ما نفعله هو تغيير المحرك كي يستخدم محوّل postgresql_psycopg2 بدلًا من sqlite3، ثم نستخدم اسم قاعدة بياناتنا (myproject في مثالنا) في خانة NAME، ونضيف بعض بيانات تسجيل الدخول مثل اسم المستخدم وكلمة المرور، والمضيف الذي سيتصل به، وسنضيف خانة Port ونتركها فارغة كي يتم اختيار المنفذ الافتراضي: . . . DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'myproject', 'USER': 'myprojectuser', 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '', } } . . . وبما أننا في الملف، فقد تحتاج إلى تعديل تعليمة ALLOWED_HOSTS التي تحدد قائمة عناوين أو أسماء نطاقات مسموح باستخدامها للاتصال مع مشروع Django، فأي طلب اتصال بترويسة HOST ليس في هذه القائمة سيتم اعتراضه. ويتطلّب Django أن تعدّل هذه التعليمة كي يمنع فئة معينة من الاختراقات الأمنية. ولتعديل هذه التعليمة، أدخل -بين قوسين مربعيْن- عناوين IP أو أسماء النطاقات المرتبطة بخادم Django الخاص بك ويجب أن يكون كل نطاق أو عنوان IP داخل علامتي تنصيص مفردتيْن، وتفصل بين كل واحد منهم فاصلة ",”. وإن رغبت في الاستجابة لطلبات من نطاق ما إضافة إلى النطاقات الفرعية له فضع نقطة قبله أثناء كتابته. إليك أمثلة تعرض لك الطريقة الصحيحة لصيغة هذه التعليمة، استبدل النطاقات وعناوين الـ IP التي تريدها بالأمثلة الموجودة هنا: . . . # أبسط حالة: اكتب العناوين وأسماء النطاقات لخادم چانجو الخاص بك # ALLOWED_HOSTS = [ 'example.com', '203.0.113.5'] # ابدأ اسم النطاق بنقطة للاستجابة له ولأي نطاق فرعي # ALLOWED_HOSTS = ['.example.com', '203.0.113.5'] ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .] واﻵن احفظ الملف وأغلقه. نقل قاعدة البيانات واختبار مشروعك يمكننا الآن نقل هياكل البيانات -بما أننا أنهينا ضبط إعدادات Django- إلى قاعدة بياناتنا واختبار الخادم. سنبدأ بإنشاء هيكل ابتدائي لقاعدة البيانات بما أننا ﻻ نملك أي بيانات حقيقية بعد: (myprojectenv) $ cd ~/myproject (myprojectenv) $ python manage.py makemigrations (myprojectenv) $ python manage.py migrate أنشئ حسابًا إداريًا: (myprojectenv) $ python manage.py createsuperuser وسيطلب منك النظام اختيار اسم لمستخدم هذا الحساب وعنوان بريد وكلمة مرور له. انتبه هنا إلى أنه يجب فتح المنفذ الذي سنستخدمه في الجدار الناري كي نتمكن من الدخول إلى خادم تطوير Django، إن كنت تستخدم UFW فإن فتح المنفذ المناسب يتم بكتابة هذا الأمر: (myprojectenv) $ sudo ufw allow 8000 وبمجرد أن تفتح المنفذ يمكنك اختبار عمل قاعدة البيانات بتشغيل خادم Django: http://server_domain_or_IP:8000 يجب أن ترى صفحة index الافتراضية: ضعadmin/ في نهاية الرابط، يجب أن يدخلك هذا لشاشة تسجيل الدخول إلى واجهة التحكم: أدخل اسم المستخدم وكلمة المرور اللتان أنشأتهما قبل قليل باستخدام createsuperuser، فتدخل إلى لوحة التحكم: وبدخولنا للوحة التحكم نكون قد تأكدنا أن قاعدة البيانات قد خزّنت معلومات حساب المستخدم الخاص بنا ويمكننا الدخول إليه دون مشاكل. يمكنك الآن إيقاف الخادم حين تنتهي من تحققك بالضغط على ctrl-c داخل شاشة الطرفية. الخلاصة قد عرضنا في هذا الدليل كيفية تثبيت وإعداد PostgreSQL كقاعدة بيانات في النهاية الخلفية لمشروع Django، إذ تستفيد أغلب المشاريع من استخدام نظم إدارة متطورة لقواعد البيانات، رغم أن SQLite تتعامل بشكل جيد أثناء تطوير المشروع وأثناء الاستخدام الخفيف له. ترجمة -بتصرف- لمقال How To Use PostgreSQL with your Django Application on Ubuntu 16.04 لصاحبه Justin Ellingwood.
-
Django هو إطار عمل مجّاني ومفتوح المصدر، مكتوب بلغة Python، وتتبع المشاريع فيه بنية Model-View-Template (عادة ما تختصر إلى MVT). يؤكّد Django على قابلية إعادة الاستخدام Reusability للمكونات وكذلك على التطوير السريع، بالإضافة إلى مبدأ عدم التكرار. تستخدم لغة Python في جميع مفاصل إطار العمل هذا، كالإعدادات ونماذج قواعد البيانات وغيرها. ومن أشهر المواقع التي تستخدم Django هي: Pinterest ،Instagram ،Mozilla ،The Washington Times ،Disqus ،National Geographic وغيرها الكثير. طوّر Django سنة 2003 على يدي المبرمجين Adrian Holovaty و Simon Willson اللذين يعملان في صحيفة Lawrence Journal World، وذلك عندما انتقلا إلى لغة Python لبناء التطبيقات. ثم أطلق Django سنة 2005 تحت رخصة BSD، وقد سمّي بهذا الاسم تيمنًا بعازف الغيتار Django Reinhardt. بنية MVT تنقسم بنية المشاريع في Django إلى ثلاثة أقسام مرتبطة ببعضها البعض، ولكنّها مختلفة عن أطر العمل الأخرى التي تتبع بنية (MVC - Model, View, Controller) مثل Laravel في PHP وغيرها، حيث تتكون المشاريع في Django من النموذج Model والعرض View والقالب Template. يتولى قسم النموذج معالجة البيانات والتعامل معها واسترجاعها، ويدعم Django العديد من قواعد البيانات، مثل: SQlite ،MySQL، و PostgreSQL. أما العرض فعبارة عن مجموعة من دوال Python التي تستجيب لعنوان URL معين، ووظيفة العرض هي تحديد البيانات والمعلومات التي يجب عرضها. أما القالب فهو عبارة عن ملف بصيغة HTML يتم من خلاله تحديد الطريقة التي ستظهر بها المعلومات التي يعرضها قسم العرض. أين المتحكم Controller إذًا؟ المتحكم هنا هو إطار العمل نفسه، أي الآلية التي يتم من خلالها إرسال الطلب إلى العرض المناسب بالاعتماد على عنوان URL محدّد. تثبيت Django إطار العمل Django هو إحدى الحزم الخاصة بلغة البرمجة بايثون، وتوفّر هذه اللغة مدير حزم خاصّ يدعى pip يتم من خلاله تثبيت وتحديث وإزالة الحزم بسهولة ويسر؛ لذا ستكون الخطوة الأولى في تثبيت Django هي التأكد من وجود مدير الحزم pip وتثبيته إن لم يكن متوفّرًا. تنصيب pip لتنصيب إطار العمل Django ستحتاج إلى مدير الحزم الخاصّ بـ Python وهو pip، ولحسن الحظّ فإن pip متوفّر في نسخة Python 2.7.9 وما بعدها، وفي نسخة Python 3.4 وما بعدها. في حال عدم توفّر pip في نسخة Python المنصّبة لديك يمكنك تنصيبه باتباع الخطوات التالية: حمّل الملفّ get-pip.py. توجه في سطر الأوامر إلى المكان الذي حملت فيه الملف السابق، ثم اكتب التعليمة التالية: python get-pip.py استخدام سطر الأوامر لنجرب الآن استخدام مدير الحزم في بايثون لتنصيب Django، توجّه الآن إلى سطر الأوامر ثم اكتب الأمر: pip install django==1.9 هل ظهرت لك رسالة خطأ؟ ما المشكلة، ألم نقم بتنصيب pip قبل قليل؟ هذا صحيح، ولكننا لم نخبر سطر الأوامر بأن يوجّه أي تعليمة تبدأ بكلمة pip إلى مدير حزم بايثون، وللقيام بذلك اتبع الخطوات التالية: في أوبنتو: يجب تنصيب حزمة python3-pip إن كنت تستخدم الإصدار الثالث من بايثون أو python-pip للإصدار الثاني من بايثون، لتتمكن من استخدام pip في سطر الأوامر في أبونتو، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install python3-pip أدخل كلمة المرور الخاصة بك، وستبدأ عملية التثبيت، وبعد الانتهاء يمكنك تنصيب أي حزمة خاصة بلغة بايثون عن طريق سطر الأوامر مباشرة. في نظام Windows: أما في نظام Windows فيجب إضافة السطر التالي: C:\Python34\scripts; إلى مسار النظام System path، وللقيام بذلك اتبع الخطوات التالية: انقر بزر الفأرة الأيمن على أيقونة Computer واختر Properties من القائمة المنسدلة: انقر على أيقونة Advance system settings، وفي مربع الحوار المنبثق اضغط على أيقونة Environment Variables. انقر نقراً مزدوجًا على متغير النظام Path في الجزء السفلي من مربع الحوار المنبثق. أضف السطر السابق إلى نهاية السلسلة النصّية، بعد الفاصلة المنقوطة (;) (إن لم تكن هناك فاصلة منقوطة في نهاية السطر فقم بإضافتها). اضغط Ok ثم أغلق بقية النوافذ بالضغط على Ok. يمكنك الآن استخدام pip من سطر الأوامر مباشرة. البيئة الافتراضية Virtual Environment قبل البدء بتنصيب Django سنعمل على تنصيب أداة مفيدة جدًّا من شأنها المساعدة على ترتيب البيئة البرمجية على حاسوبك. يمكن تجاوز هذه الخطوة، ولكن ينصح بها بشدّة. تعمل البيئة الافتراضية على عزل مشاريع Python أو Django الخاصّة بك عن بعضها البعض، وهذا يعني أن إجراء التعديلات على موقع إلكتروني معيّن لن تؤثّر على المشاريع الأخرى التي تعمل عليها. ستحتوي البيئة الافتراضية على الملفات التنفيذية الخاصة بـ Python بالإضافة إلى نسخة من مكتبة pip يمكنك استخدامها في تنصيب حزم Python المختلفة. سننشئ مجلدًا سيحتوي على البيئة الافتراضية التي سوف ننشئها بعد قليل. mkdir mysite cd mysite يتطلب إنشاء البيئة الافتراضية تنصيب حزمة virtualenv وسنستعين بـ pip للقيام بذلك: pip install virtualenv لاستخدام virtualenv من سطر الأوامر مباشرة في أوبنتو يجب تنصيب الحزمة virtualenv، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install virtualenv بعد اكتمال عملية التنصيب يمكنك إنشاء البيئة الافتراضية بالشكل التالي: virtualenv myvenv ستنشئ هذه الشيفرة بيئة افتراضية وهي عبارة عن مجموعة من المجلدات. لتفعيل البيئة الافتراضية الجديدة في نظام Windows استخدم الشيفرة التالية: myvenv\Scripts\activate أما في نظامي Linux و OS X فاستخدم: source myvenv/bin/activate ملاحظة: قد لا تحصل على النتيجة المرجوّة من الشيفرة السابقة، لذا يمكنك استخدام هذه الشيفرة: . myvenv/bin/activate سيتغيّر سطر الأوامر وذلك بإضافة كلمة (myvenv) إلى بداية السطر، وهذا يعني أن الأمور تسير على ما يرام. ولإغلاق البيئة الافتراضية يمكنك استخدام التعليمة التالية: deactivate تنصيب Django بعد اكتمال الخطوتين السابقتين يمكننا الآن تنصيب Django وذلك بتنفيذ الأمر التالي (انتبه إلى وجود علامتي مساواة لا علامة واحدة): pip install django==1.9 بعد اكتمال عملية التنصيب، وللتأكد من أن الأمور تجري على ما يرام، اكتب الأمر التالي في سطر الأوامر: python3 -c "import django; print(django.get_version())" إن حصلت على رقم النسخة (1.9 في حالتنا هذه) التي قمت بتنصيبها، فقد أصبحت جاهزًا لإنشاء مشروعك الأول على Django. إنشاء المشروع الأول مشروعنا الأول سيكون عبارة عن تطبيق استطلاع بسيط، يتألف من جزئين: موقع عام يتيح مشاهدة الاستطلاعات والتصويت عليها. لوحة تحكم تتيح لنا إضافة وحذف وتعديل الاستطلاعات. هذا المشروع سيكون مبنيًا على الإصدار 1.9 من Django والإصدار 3.4 من Python. في حال كنت تستخدم الإصدار 2.7 من Python فيتوجب عليك حينها إضافة بعض التعديلات على الشيفرة التي تكتبها، وسنشير إلى ذلك في محلّه. انتقل إلى سطر الأوامر وتوجه من خلاله إلى المجلد الذي ترغب استخدامه لإنشاء المشروع، وبإمكانك استخدام أي مجلد تحت أي تسمية وفي أي موقع في القرص الصلب، فلا مشكلة لدى Django في ذلك. لإنشاء المشروع نفّذ الأمر التّالي في سطر الأوامر (انتبه إلى النقطة في نهاية السطر): django-admin startproject mysite . سيعمل هذا الأمر على إنشاء مجلد باسم mysite داخل مجلد المشروع. انتبه كذلك إلى كتابة النقطة في نهاية السطر، فهي توجّه الشيفرة إلى تنصيب Django في المجلد الحالي. البنية الأولية للمشروع يحتوي مجلد mysite الذي أنشأته التعليمة السابقة، على مجموعة الملفات التالية: manage.py /mysite __init__.py settings.py urls.py wsgi.py manage.py، يُوصف هذا الملف بالسكين السويسري، وهو الأداة التي سنستعين بها للقيام بالكثير من الأشياء في إدارة الموقع، وفي تهجير قواعد البيانات وتشغيل الخادوم الخاص بـ Django، وغير ذلك الكثير. المجلد mysite هو حزمة بايثون الخاصة بمشروعنا، وسنستخدم هذا الاسم عندما نرغب في استيراد أي شيء داخله. (مثال mysite.urls). mysite/__init__.py ملف فارغ، ووجوده يعني أن هذا المجلّد هو حزمة من حزم بايثون. mysite/settings.py ملف الإعدادات الخاصة بمشروعنا. mysite/urls.py يحتوي على عناوين URL الخاصة بموقعنا، وهو أشبه ما يكون بجدول المحتويات الخاص بالموقع. mysite/wsgi.py نقطة الولوج إلى الخواديم المتوافقة مع WSGI. تشغيل الخادوم توجه في سطر الأوامر إلى المجلد الذي يحوي الملف manage.py ثم اكتب الأمر التالي: python manage.py runserver وستظهر العبارات التالية في سطر الأوامر: Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them. February 01, 2016 - 15:50:53 Django version 1.9, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ملاحظة: لا تستخدم هذا الخادوم في المشاريع الإنتاجية على الإطلاق، فالهدف من هذا الخادوم هو استخدامه لأغراض التطوير فقط. أدخل العنوان التالي في متصفح الإنترنت: http://127.0.0.1:8000 ستظهر الصفحة التالية لتشير إلى نجاحنا في إنشاء أول مشروع في Django.
- 3 تعليقات
-
- 4
-
- django 101
- بايثون
- (و 5 أكثر)
-
بعد أن تعرفنا في الدرس الأول على طريقة تثبيت Django وإنشاء مشروعنا الأول فيه، سنشرع في هذا الدرس في إنشاء تطبيقنا الأول والذي سيكون عبارة عن موقع بسيط للاقتراعات يتكون من قسمين: القسم الأول: واجهة يمكن للمستخدم أن يطلع من خلالها على الأسئلة المطروحة واختيار الإجابة التي يرغب فيها. أما القسم الثاني: لوحة تحكم يمكن من خلالها إضافة الأسئلة وتعديلها وحذفها وإضافة الأجوبة وغير ذلك من الأمور. المشاريع Projects والتطبيقات Applications قبل أن ندخل في تفاصيل إنشاء تطبيق الاقتراعات، لا بأس في الحديث بشكل موجز عن مفهومي "المشروع" Project و"التّطبيق" Application في Django. يمثّل المشروع تطبيق الويب الذي يتم إنشاؤه بواسطة Django، ويتم تعريفه من خلال ملف الإعدادات Settings، فكما رأينا في الدرس السابق فبعد تنفيذ الأمر: django-admin startproject mysite تم إنشاء حزمة بايثون تحتوي على ملفات settings.py و urls.py و wsgi.py، وعادة ما تتوسع هذه الحزمة بإضافة المزيد من الملفات مثل ملفات CSS والقوالب وما إلى ذلك من الأمور التي لا تكون مرتبطة بتطبيق معيّن. وعادة ما يكون مجلّد المشروع هذا (المجلد الذي يحتوي على الملف manage.py) حاويًا للتطبيقات التي يتم إنشاؤها بشكل مستقل، وهذه التطبيقات ما هي إلا حزم بايثون تعمل على تقديم بعض الخصائص وتؤدي بعض المهام، ويمكن استخدام هذه التطبيقات في مشاريع متعددة، وهذا ما يسمى بمبدأ قابلية إعادة الاستخدام re-usability. إنشاء تطبيق الاقتراعات ملاحظة: ابتدءًا من هذا الدرس فإن عبارة "مجلد المشروع" تعني المجلد الذي يحتوي على ملف manage.py. توجّه في سطر الأوامر إلى مجلد المشروع ثم اكتب الأمر التالي: python manage.py startapp polls يمكن الحصول على نفس النتيجة من خلال الأمر التالي: django-admin startapp polls بعد تنفيذ الأمر ستجد أنّ إطار العمل قد أنشأ مجلدًا جديدًا يحمل الاسم polls، ويتضمن عددًا من الملفات نستعرضها بشكل مختصر: init__.py__: هذا الملف مشابه للملف الموجود في مجلد المشروع، وهو ملف فارغ يعني وجوده أن هذا المجلد هو حزمة من حزم بايثون. admin.py: يمكن من خلال هذا الملف إدارة وتخصيص لوحة التحكم والتي تأتي جاهزة مع التطبيق. apps.py: يمكن من خلال هذا الملف إعداد التطبيق configuration لاستخدامه في مشاريع أخرى. models.py: سيتضمن هذا الملف النماذج التي يتعامل التطبيق معها، والتي تكون مسؤولة عن إنشاء جداول قواعد البيانات. tests.py: يمكن من خلال هذا الملف إجراء الاختبارات Tests على التطبيق. views.py: تضاف في هذا الملف العروض المسؤولة عن تحديد البيانات والمعلومات التي سيتم عرضها على المتصفح، وهي كذلك صلة الوصل بين المسارات والقوالب. مجلد migrations: سيستقبل هذا المجلد الملفات الناشئة عن عملية تهجير قاعدة البيانات. إعدادات المشروع يحتوي مجلد المشروع على ملف الإعدادات settings.py، وهو عبارة عن ملف بايثون يحتوي جميع الإعدادات الخاصة بالمشروع، وسنستعرض بعض محتويات هذا الملف بشكل موجز. BASE_DIR: متغير نصّي يقدّم مسار المجلد الأساسي للمشروع، ويمكن الاستفادة من هذا المتغير في تحديد مسارات المجلدات التي تحتوي على القوالب أو الملفات الساكنة وغيرها، وسنتعرف على طريقة استخدامه عند الحديث عن القوالب. SECRET_KEY: عبارة عن سلسلة نصية من حروف ورموز عشوائية يمكن الاستفادة منها في حماية التطبيق. DEBUG: متغير من نوع bool، ويمكن من خلاله التحكم في وضع التنقيح Debugging، حيث تظهر معلومات مفيدة عند حدوث الأخطاء، ولكن ينصح بتغيير قيمته إلى False عند نقل المشروع إلى بيئة الإنتاج. INSTALLED_APPS: عبارة عن قائمة تتضمن التطبيقات التي سيضمها المشروع الحالي، ويمكنك أن تلاحظ وجود عدد من التطبيقات المثبتة بشكل مسبق، مثل إدارة لوحة التحكم admin، والاستيثاق auth، والجلسات sessions وغيرها. TEMPLATES: عبارة عن قائمة تتضمن إعدادات القوالب المستخدمة في المشروع، وما يهمنا فيها هو العنصر DIRS والذي يتم من خلاله تعيين المسارات التي تحتوي على ملفات القالب. DATABASES: قائمة أخرى مسؤولة عن تحديد المعلومات اللازمة للتعامل مع قواعد البيانات، وسنتطرق إليها عند الحديث عن النماذج Models والاتصال بقواعد البيانات. LANGUAGE_CODE: يمكن من خلال هذا المتغير تحديد لغة واجهة لوحة التحكم، والإعداد الافتراضي هنا هو اللغة الإنكليزية، ولكن Django يدعم العديد من اللغات ومن ضمنها العربية، وإن كنت ترغب في استخدام اللغة العربية في عرض عناصر لوحة التحكم، فيمكنك تغيير قيمة هذا المتغير بالشكل التالي: LANGUAGE_CODE = 'ar' TIME_ZONE: يمكن من خلال هذا المتغيير تعيين المنطقة الزمنية التي سيستخدمها Django في دوال الوقت والتاريخ. ويمكن استبدال هذه القيمة حسب الرغبة. STATIC_URL: في هذا المتغير يتم تحديد مسار المجلد الذي يحتوي على الملفات الساكنة وهي ملفات CSS و Javascript والخطوط والصور وغيرها. كتابة العرض الأول العرض View عبارة عن دالة مكتوبة بلغة Python (أو صنف كما سنرى في الدروس اللاحقة) يمكن تلخيص عملها ببساطة في أنها تأخذ الطلبات Requests التي يرسلها العميل وتقوم بإرجاع الإجابة response والتي يمكن أن تكون على هيئة شيفرة بصيغة HTML، أو إعادة توجيه لصفحة أخرى، أو صفحة خطأ 404، أو ملف XML، أو صورة أو أي شي آخر. لنبدأ الآن بكتابة العرض الأول في مشروعنا، وللقيام بذلك افتح ملف polls/view.s.py في محرر النصوص المفضّل لديك، ثم امسح محتوياته واكتب الشيفرة التالية: from django.http import HttpResponse def index(request): html = "مرحبًا بك في تطبيق الاقتراعات، هذه هي الصفحة الرئيسية." return HttpResponse(html) في السطر الأول من هذه الشيفرة قمنا باستيراد الصنف HttpResponse من وحدة django.http، وهو المسؤول عن التعامل مع الاستجابة التي ترد على الطلب الذي أرسلناه إلى الخادوم من خلال الدالة index، وذلك عن طريق تمرير المعامل request عند تعريف الدالة. ستقوم هذه الدالة بإعادة العنصر HttpResponse والذي يحتوي على الإجابة، وهي في مثالنا هذا عبارة عن سلسلة نصية بسيطة. ملاحظة: في حال عدم ظهور الأحرف العربية بشكل صحيح، أضف السطر التالي إلى بداية ملف views.py: # -*- coding:utf8 -*- لنتمكن من مشاهدة النتيجة على المتصفح، يجب أن نربط هذا العرض بمسار معين؛ وللقيام بذلك توجه إلى الملف mysite/urls.py وعدّل محتوياته لتصبح بالشكل التالي: from django.conf.urls import url from django.contrib import admin from polls import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^polls/', views.index), ] يتضمن هذا الملف جميع المسارات التي سنستخدمها في المشروع، وهو بمثابة جدول لمحتويات الموقع. في البداية قمنا باستيراد محتويات ملف views.py الموجود في مجلد polls من خلال الشيفرة التالية: from polls import views من خلال هذه الشيفرة يمكنك أن تلاحظ أن Django يتعامل مع المجلد polls باعتباره حزمة من حزم بايثون، وذلك لاحتواءه على ملف init__.py__ كما ذكرنا سابقًا. بهذا الطريقة يمكننا الوصول إلى دالة index التي أنشأناها قبل قليل في ملف views.py الموجود في مجلد polls (أو حزمة polls لنكون أكثر دقة) وذلك تمهيدًا لربطها بالمسار الذي نرغب فيه. أضفنا كذلك الشيفرة التالية إلى قائمة urlpatterns: url(r'/polls', views.index), وهي عبارة عن دالة وظيفتها ربط المسار الذي نحدده في المعامل الأول بالعرض الذي نحدده في المعامل الثاني. لاحظ أن المسار عبارة عن سلسلة نصية مسبوقة بحرف r صغير وذلك لإخبار بايثون بأن يتعامل مع هذه السلسلة النصية على أنّها سلسلة خام raw، بمعنى أنه سيتم تجاوز جميع العلامات الخاصة المستخدمة في هذه السلسلة، وهذا ضروري جدًّا، لأن Django يستخدم التعبيرات النظامية Regular Expressions في تحديد المسارات وتمرير المتغيرات، وهذه التعبيرات تستخدم الكثير من الرموز التي يجب تجاوزها لتعمل الشيفرة بالشكل الصحيح. سنتعرف على المسارات وآلية عملها وكيفية استخدام التعبيرات النظامية، في الدروس اللاحقة. يمكنك الآن التوجه إلى مجلد المشروع وتشغيل الخادوم الخاص بـ Django عن طريق سطر الأوامر من خلال الأمر التالي: python manage.py runserver انتقل في المتصفح إلى العنوان التالي: http://127.0.0.1:8000/polls لتشاهد عبارة الترحيب في واجهة الموقع. يمكننا استخدام شيفرة HTML ضمن السلسلة النصية التي ترجعها دالة العرض، وللقيام بذلك افتح ملف polls/view.py وعدّله ليصبح بالشكل التالي: from django.http import HttpResponse def index(request): html = """ <html dir="rtl"> <head> <title>تطبيق الاقتراعات</title> </head> <body> <h1>تطبيق الاقتراعات</h1> <p>مرحبًا بك في تطبيق الاقتراعات، هذه هي الصفحة الرئيسية.</p> </body> </html> """ return HttpResponse(html) من المؤكد أن التطبيقات التي نراها على صفحات الإنترنت لا تتمتع بهذه البساطة الشديدة، وهذا يعني أن استخدام شيفرة HTML ضمن دالة العرض أمر غير عملي على الإطلاق، وهنا تظهر الحاجة إلى فصل هذه الشيفرات عن العروض وهذه هي وظيفة القوالب Templates والتي سنتعرف إليها في الدروس اللاحقة. خاتمة تعرفنا في هذا الدرس على مفهومي المشروع والتطبيق في Django، وقمنا بكتابة العرض الأول وتعرفنا بشكل مختصر على المسارات Urls. سنتعرف في الدرس القادم على كيفية التعامل مع قواعد البيانات من خلال النماذج Models، وكذلك سنتعرف على كيفية تهجير قواعد البيانات، وكذلك الاستعلام عن البيانات برمجيًا، وذلك لتهيئة قاعدة البيانات التي سنستخدمها في تطبيق الاقتراعات.