اذهب إلى المحتوى

تعلمت في المقال السابق كيفية إنشاء قاعدة بيانات MySQL وإنشاء تطبيق جانغو Django وربطه بها وتشغيله. في هذا المقال سننشئ نماذج models في جانغو التي تُعرّف الحقول والسلوكيات الخاصة ببيانات تطبيقك (تطبيق المُدونة الذي بدأنا به في المقال السابق)، إذ تربط هذه النماذج البيانات من تطبيقك إلى قاعدة البيانات، ويستخدمها جانغو لإنشاء جداول قاعدة البيانات من خلال واجهة برمجة التطبيقات ORM (اختصار للعبارة Object Relational Mapping أي "ربط الكائنات العِلاقيَّة") وهو عبارة عن طريقة لربط الكائنات الخاصة بتطبيق ما بجداول في نظام إدارة قواعد بيانات علائقية. ويمكن تعريف النماذج بشكل مبسط على أنها وصف للبيانات الموجودة في قاعدة البيانات، وبمعنى آخر تمثّل النماذج في جانغو بنية قاعدة البيانات، أي ما ستحصل عليه من إجراء الأمر CREATE TABLE، لكن بلغة بايثون بدلًا من SQL.

المتطلبات الأساسية

هذا المقال جزء من سلسلة مقالات قصيرة حول كيفية إنشاء تطبيق ويب ليكون بمثابة مدونة وإليك فهرس كامل السلسلة:

فإذا لم تكن قد قرأت المقالات السابقة وطبقتها، فيجب أن تعلم أننا نفترض ما يلي:

  • لديك نسخة جانغو 3 أو أحدث.
  • وصلت تطبيقك بقاعدة بيانات (نحن نستخدم MySQL).
  • أنك تعمل على نظام تشغيل مبني على يونيكس Unix. يُفضل أن يكون خادمًا سحابيًّا أبونتو Ubuntu، لأنه النظام الذي تم إجراء الاختبار عليه. إذا كنت تريد العمل على بيئة مشابهة، فيجب عليك إعداد جانغو عليها (يمكنك العودة إلى المقال الأول في السلسلة).

هذا المقال يتعامل مع نماذج جانغو، وبالتالي قد تتمكن من اتباع هذا الدرس، حتى لو كان لديك إعداد مختلف.

الخطوة الأولى - إنشاء تطبيق جانغو

لكي تعمل وفق النهج العام المُتبع في جانغو، يجب عليك إنشاء تطبيق جانغو ضمن المشروع، ويحتوي على جميع الملفات اللازمة لإنشاء موقع المدونة.

عندما تريد معاودة العمل على مشروعك في جانغو، عليك أولًا تنشيط بيئة بايثون الخاصة بك والتي أنشأتها لأجل هذا الغرض، ثم الانتقال إلى المجلد الجذر للتطبيق. يمكنك إنجاز ذلك كما يلي:

$ cd ~/my_blog_app
$ . env/bin/activate
$ cd blog

بعد الانتقال إلى المشروع، نفّذ الأمر التالي:

(env) sammy@ubuntu:$ python manage.py startapp blogsite

يؤدي ذلك إلى إنشاء تطبيقك، بجانب مجلد مشروع المدونة، وستصبح بنية المجلد لديك في هذه المرحلة كما يلي:

my_blog_app/
└── blog
    ├── blog
       ├── __init__.py
       ├── __pycache__
          ├── __init__.cpython-38.pyc
          ├── settings.cpython-38.pyc
          ├── urls.cpython-38.pyc
          └── wsgi.cpython-38.pyc
       ├── asgi.py
       ├── settings.py
       ├── urls.py
       └── wsgi.py
    ├── blogsite
       ├── __init__.py
       ├── admin.py
       ├── apps.py
       ├── migrations
          └── __init__.py
       ├── models.py
       ├── tests.py
       └── views.py
    └── manage.py

سنركز في هذا المقال على الملف models.py الموجود في المجلد blogsite.

الخطوة الثانية - إنشاء نموذج المنشورات Posts Model

يجب علينا أولًا أن نفتح ملف model.py وأن نحرره بحيث يحتوي على الشيفرة الخاصة بإنشاء نموذج النشر، وهو نموذج يتضمن حقول قاعدة البيانات التالية:

  • title: عنوان المنشور على المدونة.
  • slug: يتم فيها تخزين عناوين URL الصالحة وإنشاءها لصفحات الويب.
  • content: المحتوى النصي لمنشور المدونة.
  • Creat_on: تاريخ إنشاء المنشور.
  • author: الشخص الذي كتب المنشور.

انتقل الآن إلى المجلد الذي يحتوي الملف model.py:

(env) sammy@ubuntu:$ cd ~/my_blog_app/blog/blogsite

استخدم الأمر cat لإظهار محتويات الملف في الطرفية terminal:

(env) sammy@ubuntu:$ cat models.py

يجب أن يحتوي الملف على الشيفرة التالية، حيث ستجد فيه تعليمة استيراد النماذج import models، جنبًا إلى جنب مع تعليق يصف ما سيتم وضعه في ملف model.py:

from django.db import models
# Create your models here.

أضف الشيفرة التالية إلى ملف model.py باستخدام أحد محررات النصوص (هنا سيتم استخدام المحرر nano):

(env) sammy@ubuntu:$ nano models.py

نضع الآن داخل هذا الملف تعليمات استيراد الوحدات التالية:

from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse

حيث نستورد الوحدة slugify لتوليد العناوين الفرعية slugs من السلاسل strings، ونستخدم الوحدة User للاستيثاق authentication، ونستخدم reverse لتوفير مرونة أكبر في إنشاء عناوين URL.

أضف بعد ذلك تابع لصنف class method إلى صنف النموذج model class والتي سنسميها Post، مع إضافة الحقول التالية أيضًا إلى قاعدة البيانات:

...
class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True, max_length=255)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    author = models.TextField()

سنضيف بعد ذلك دالة لإنشاء عنوان URL، ودالة لحفظ المنشور، وهذا أمر مهم جدًا لأنه يُنشئ رابطًا فريدًا لكل منشور في المدونة.

...
    def get_absolute_url(self):
        return reverse('blog_post_detail', args=[self.slug])

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)

نحتاج الآن إلى إخبار النموذج بكيفية ترتيب المنشورات وعرضها على صفحة الويب، إذ يضاف النهج اللازم لإنجاز ذلك إلى الصنف الداخلي Meta الذي يحتوي أيضًا على نموذج مهم آخر لا يرتبط بتعريف حقل قاعدة البيانات.

...
    class Meta:
        ordering = ['created_on']

        def __unicode__(self):
            return self.title

تبقى إضافة نموذج التعليق Comment إلى هذا الملف، وهذا يعني أنك بحاجة إلى إضافة صنف جديد يسمى Comment، يحتوي على الحقول التالية:

  • الاسم: اسم الشخص الذي يقوم بنشر التعليق.
  • البريد الإلكتروني: عنوان بريده الإلكتروني.
  • النص: نص التعليق.
  • المنشور: المنشور الذي تم التعليق عليه.
...
class Comment(models.Model):
    name = models.CharField(max_length=42)
    email = models.EmailField(max_length=75)
    website = models.URLField(max_length=200, null=True, blank=True)
    content = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now_add=True)

انتهيت الآن ولكن تأكد من أن ملفك يحتوي على يُطابق الملف التالي:

from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse


class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True, max_length=255)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    author = models.TextField()

    def get_absolute_url(self):
        return reverse('blog_post_detail', args=[self.slug])

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)

    class Meta:
        ordering = ['created_on']

        def __unicode__(self):
            return self.title


class Comment(models.Model):
    name = models.CharField(max_length=42)
    email = models.EmailField(max_length=75)
    website = models.URLField(max_length=200, null=True, blank=True)
    content = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now_add=True)

بعد ذلك احفظ الملف واغلقه (إذا كنت تستخدم المحرر nano اضغط CTRL+X ثم Y ثم ENTER).

بعد الانتهاء من إعداد ملف models.py، يمكنك الانتقال إلى ملف settings.py لتحديثه.

الخطوة الثالثة - تحديث الإعدادات

بعد الانتهاء من إضافة النماذج إلى التطبيق، يجب أن تُخبر المشروع أن التطبيق blogsite الذي أضفناه منذ قليل موجود. لإنجاز ذلك، عليك بإضافته إلى قسم INSTALLED_APPS في ملف الإعدادات settings.py.

انتقل إلى المجلد الذي يحتوي ملف الإعدادات:

(env) sammy@ubuntu:$ cd ~/my_blog_app/blog/blog

افتح الآن ملف settings.py باستخدام محرر النصوص:

$ nano settings.py

أضف الآن التطبيق blogsite إلى القائمة INSTALLED_APPS:

# Application definition
INSTALLED_APPS = [
    'blogsite',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

الخطوة الرابعة - عمليات التهجير

بعد إضافة النموذج Comment والنموذج Post، يجب عليك تطبيق هذه التغييرات، لكي يتعرف مخطط قاعدة بيانات MySQL عليها وينشئ الجداول اللازمة.

الآن لو انتقلنا إلى المجلد ‎~/my_blog_app/blog/blogsite/migrations ونفذنا الأمر ls، ستلاحظ وجود ملف واحد هو ‎__init__.py، لكن ذلك سيتغير بعد التهجير.

توجّه إلى مجلد المشروع عن طريق سطر الأوامر ونفّذ الأمر التالي للانتقال إلى المجلد blog:

(env) sammy@ubuntu:$ cd ~/my_blog_app/blog

ثم نفذ الأمر makemigrations على الملف manage.py:

(env) sammy@ubuntu:$ python manage.py makemigrations

وظيفة الأمر makemigrations هي إخبار جانغو بأنّك قد أجريت بعض التعديلات على النماذج وأنّك ترغب في حفظ هذه التعديلات على هيئة ملف تهجير يُحفظ على القرص الصلب كملف بايثون في مجلد migrations، تحت اسم ‎0001_initial.py و pycache وهي من ضمن ملفات تُنشَأ تلقائيًّا في كل مرة تنفذ هذا الأمر:

Migrations for 'blogsite':
  blogsite/migrations/0001_initial.py
    - Create model Post
    - Create model Comment

تذكر عندما انتقلنا إلى ‎~/my_blog_app/blog/blogsite/migrations كان يحتوي فقط على ملف ‎__init__.py. الآن لو رجعت إلى هذا المجلد، ستلاحظ وجود ملفين هما ‎0001_initial.py و pycache، ويمكنك تنفيذ الأمر التالي لرؤية محتويات هذا الملف:

less 0001_initial.py

انتقل الآن إلى المجلد ‎~/my_blog_app/blog:

$cd ~/my_blog_app/blog

بما أنه تم إنشاء ملف تهجير، يجب تطبيق التغييرات التي تحددها هذه الملفات على قاعدة البيانات باستخدام أمر التهجير migrate لكن بدايةً تحقق من عمليات التهجير الموجودة حاليًّا باستخدام الأمر showmigrations.

(env) sammy@ubuntu:$ python manage.py showmigrations

سيكون الخرج:

admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
blogsite
 [ ] 0001_initial
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

ستلاحظ أنه تم التحقق من جميع عمليات التهجير باستثناء التهجير الخاص بالملف ‎0001_initial.py الذي أنشأناه منذ قليل.

تحقق الآن من تعليمات SQL التي يتم تنفيذها عند إجراء عمليات التهجير من خلال الأمر التالي (يأخذ هذا الأمر اسم التهجير والتهجير كوسطاء):

(env) sammy@ubuntu:$ python manage.py sqlmigrate blogsite 0001_initial

ستلاحظ الخرج التالي الذي يوضح تعليمات SQL التي تم تنفيذها في الخلفية.

--
-- Create model Post
--
CREATE TABLE `blogsite_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL UNIQUE, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `author` longtext NOT NULL);
--
-- Create model Comment
--
CREATE TABLE `blogsite_comment` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(42) NOT NULL, `email` varchar(75) NOT NULL, `website` varchar(200) NULL, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `post_id` integer NOT NULL);
ALTER TABLE `blogsite_comment` ADD CONSTRAINT `blogsite_comment_post_id_de248bfe_fk_blogsite_post_id` FOREIGN KEY (`post_id`) REFERENCES `blogsite_post` (`id`);

نفّذ الآن أمر التهجير لكي يتم تطبيق التغييرات على قاعدة البيانات:

(env) sammy@ubuntu:$ python manage.py migrate

ستحصل على الخرج التالي:

Operations to perform:
  Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
  Applying blogsite.0001_initial... OK

بذلك تكون قد انتهيت من إنجاز عمليات التهجير.

هناك ثلاث ملاحظات يجب الانتباه لها عند إجراء عمليات التهجير:

  • إذا لم تكتمل عملية التهجير بنجاح، يتعين عليك إلغاء التغييرات التي أجريتها يدويًّا قبل معاودة المحاولة (إجراء محاولة تهجير أخرى)، لأن دعم هذا النوع من عمليات التعديل على المخطط ضعيفة.
  • معظم عمليات التعديل على مخطط قاعدة البيانات تؤدي إلى إعادة كتابة الجداول بالكامل، وبالتالي قد يؤدي إلى بطء في التنفيذ.
  • في MySQL هناك حدود معينة لطول أسماء الأعمدة والجداول والفهارس.

من أجل كل قاعدة بيانات تفكر في استخدامها مع جانغو، حبذا لو تقارن بين مزايا وعيوب كل قاعدة بيانات.

الخطوة الخامسة - تحقق من مخطط قاعدة البيانات

يجب بعد الانتهاء من عمليات التهجير أن نتأكد من نجاح توليد الجداول في قاعدة البيانات، والتي أنشأناها من خلال نماذج جانغو. لإنجاز ذلك سجل الدخول إلى قاعدة بيانات MySQL، سنستخدم حساب المستخدم djangouser الذي أنشأناه سابقًا.

(env) sammy@ubuntu:$ mysql blog_data -u djangouser

حدد الآن قاعدة البيانات blog_data. إذا كنت لا تتذكرها، فيمكنك استخدام الأمر SHOW DATABASES;‎ لإظهار جميع قواعد البيانات الموجودة.

mysql> USE blog_data;

ثم اكتب الأمر التالي لعرض الجداول:

mysql> SHOW TABLES;

يجب أن تحصل على الخرج التالي:

+----------------------------+
| Tables_in_blog_data        |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| blogsite_comment           |
| blogsite_post              |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+
12 rows in set (0.01 sec)

الجدولين blogsite_comment و blogsite_post هما الجداول التي تمثل النماذج التي أنشأنها. للتحقق من أنها تحتوي على الحقول التي عرفناها:

mysql> DESCRIBE blogsite_comment;

الخرج:

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| name       | varchar(42)  | NO   |     | NULL    |                |
| email      | varchar(75)  | NO   |     | NULL    |                |
| website    | varchar(200) | YES  |     | NULL    |                |
| content    | longtext     | NO   |     | NULL    |                |
| created_on | datetime(6)  | NO   |     | NULL    |                |
| post_id    | int          | NO   | MUL | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

والأمر نفسه بالنسبة للجدول blogsite_post:

mysql> DESCRIBE blogsite_post;

الخرج:

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| title      | varchar(255) | NO   |     | NULL    |                |
| slug       | varchar(255) | NO   | UNI | NULL    |                |
| content    | longtext     | NO   |     | NULL    |                |
| created_on | datetime(6)  | NO   |     | NULL    |                |
| author     | longtext     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

يمكنك الآن إغلاق MySQL باستخدام CTRL+D، بعد ذلك يمكنك مغادرة بيئة بايثون الخاصة بك من خلال تنفيذ أمر إلغاء التنشيط، وبالتالي الانتقال إلى الموقع الافتراضي في الطرفية:

(env) sammy@ubuntu:$ deactivate

خاتمة

تعلمت في هذا المقال إضافة نماذج للوظائف الأساسية في مشروعك وتعلمت كتابة الشيفرة البرمجية اللازمة لتعريف النماذج وكيفية إجراء عمليات التهجير إلى جدول قاعدة بيانات MySQL.

ترجمة -وبتصرف- للمقال How To Create Django Models لصاحبه Jeremy Morris.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...