ویرگول
ورودثبت نام
رضا رضایی
رضا رضاییبرنامه‌نویس جونیور بک‌اند با تمرکز بر پایتون و فریم‌ورک جنگو. علاقه‌مند به ساخت برنامه‌های تحت وب مقیاس‌پذیر و قابل اعتماد. مشتاق مشارکت در پروژه‌های واقعی و پیشرفت در توسعه بک‌اند.
رضا رضایی
رضا رضایی
خواندن ۶ دقیقه·۶ روز پیش

فصل اول - اپیزود ۸ - ترجمه کتاب Django 5 By Example

ترجمه کتاب Django 5 By Example اثر آنتونیو مله - فصل ۱ - اپیزود ۸ - پیاده سازی رابطه یک به چند در مدل کاربر و پست
ترجمه کتاب Django 5 By Example اثر آنتونیو مله - فصل ۱ - اپیزود ۸ - پیاده سازی رابطه یک به چند در مدل کاربر و پست

پیاده سازی رابطه یک به چند در مدل کاربر و پست

پست‌ها همیشه توسط یک نویسنده نوشته می‌شوند. ما رابطه‌ای بین کاربران و پست‌ها ایجاد خواهیم کرد که نشان دهد کدام کاربر، کدام پست‌ها را نوشته است.
جنگو همراه با یک فریم‌ورک احراز هویت (Authentication Framework) ارائه می‌شود که حساب‌های کاربری را مدیریت می‌کند. فریم‌ورک احراز هویت جنگو در پکیج django.contrib.auth قرار دارد و شامل یک مدل کاربر (User model) است. برای تعریف رابطه بین کاربران و پست‌ها، ما از تنظیمات AUTH_USER_MODEL استفاده خواهیم کرد که به صورت پیش‌فرض به auth.User اشاره دارد. این تنظیم به شما اجازه می‌دهد تا مدل کاربر متفاوتی را برای پروژه خود مشخص کنید.

فایل models.py در اپلیکیشن بلاگ را به گونه‌ای ویرایش کنید که به شکل زیر دربیاید:

ما تنظیمات (settings) پروژه را وارد (Import) کرده‌ایم و یک فیلد author (نویسنده) به مدل Post اضافه کرده‌ایم. این فیلد یک رابطه «یک‌-به-چند» (many-to-one) با مدل کاربر پیش‌فرض تعریف می‌کند؛ به این معنی که هر پست توسط یک کاربر نوشته می‌شود و هر کاربر می‌تواند تعداد نامحدودی پست بنویسد. برای این فیلد، جنگو با استفاده از کلید اصلی (Primary Key) مدلِ مرتبط، یک کلید خارجی (Foreign Key) در پایگاه داده ایجاد خواهد کرد.

پارامتر on_delete رفتاری را مشخص می‌کند که هنگام حذف شیءِ مورد ارجاع (Referenced Object)، باید اتخاذ شود. این موضوع مختص جنگو نیست، بلکه یک استاندارد SQL است. با استفاده از CASCADE مشخص می‌کنید که وقتی کاربرِ مرتبط حذف شد، پایگاه داده باید تمام پست‌های بلاگ مرتبط با او را نیز حذف کند. می‌توانید تمام گزینه‌های ممکن را در لینک زیر مشاهده کنید:

https://docs.djangoproject.com/en/5.0/ref/models/fields/#django.db.models.ForeignKey.on_delete

ما از related_name برای مشخص کردن نامِ «رابطه معکوس» (Reverse Relationship)، یعنی از سمت User به Post استفاده می‌کنیم. این کار به ما اجازه می‌دهد تا به راحتی از طریق نحو (Notation) user.blog_posts به اشیاء مرتبط از طریق یک آبجکت کاربر دسترسی پیدا کنیم. در ادامه بیشتر درباره این موضوع خواهیم آموخت.

جنگو با انواع مختلفی از فیلدها ارائه می‌شود که می‌توانید از آن‌ها برای تعریف مدل‌های خود استفاده کنید. می‌توانید تمام انواع فیلدها را در این لینک پیدا کنید:

https://docs.djangoproject.com/en/5.0/ref/models/fields/

اکنون مدل Post کامل شده است و می‌توانیم آن را با پایگاه داده همگام‌سازی (Synchronize) کنیم.

نکته مترجم: به یاد داشته باشید که استفاده از settings.AUTH_USER_MODEL به جای ارجاع مستقیم به User یک Best Practice فوق‌العاده در جنگو است. این عادت باعث می‌شود اگر در آینده تصمیم گرفتید مدل کاربر سفارشی خودتان را (مثلاً با اضافه کردن فیلد شماره موبایل یا پروفایل تجاری) پیاده سازی کنید، تمامی پروژه مختل نشود و از هارد-کدینگ جلوگیری میکند و این یک شیوه کدنویسی تمیز(Clean Code) است.


ایجاد مایگرشن و اعمال مایگرشن به پایگاه داده

اکنون که یک مدل داده (Data Model) برای پست‌های بلاگ داریم، باید جدول پایگاه داده متناظر با آن را ایجاد کنیم. جنگو همراه با یک سیستم «مهاجرت» (Migration System) ارائه می‌دهد که تغییرات اعمال شده در مدل‌ها را ردیابی کرده و امکان انتشار (Propagate) آن‌ها را در پایگاه داده فراهم می‌کند.

دستور migrate مهاجرت‌ها را برای تمام اپلیکیشن‌هایی که در لیست INSTALLED_APPS قرار دارند، اعمال می‌کند. این دستور، پایگاه داده را با مدل‌های فعلی و مهاجرت‌های موجود همگام‌سازی (Synchronize) می‌کند.

ابتدا، باید یک مهاجرت اولیه برای مدل Post خود ایجاد کنیم. دستور زیر را در ترمینال (Shell Prompt) از مسیر اصلی (Root) پروژه خود اجرا کنید:

python manage.py makemigrations blog

خروجی شما باید چیزی شبیه به زیر باشد:

Migrations for 'blog': blog/migrations/0001_initial.py - Create model Post - Create index blog_post_publish_bb7600_idx on field(s) (-publish of model post)

جنگو به تازگی فایل 0001_initial.py را در دایرکتوری migrations اپلیکیشن blog ایجاد کرده است. این مهاجرت شامل دستورات SQL برای ایجاد جدول پایگاه داده برای مدل Post و تعریف ایندکس (Index) دیتابیس برای فیلد publish است.

می‌توانید به محتویات این فایل نگاهی بیندازید تا ببینید مهاجرت چگونه تعریف شده است. یک فایل مهاجرت، وابستگی‌ها (Dependencies) به سایر مهاجرت‌ها و عملیاتی که باید در پایگاه داده برای همگام‌سازی با تغییرات مدل انجام شوند را مشخص می‌کند.

بیایید نگاهی به کد SQL بیندازیم که جنگو برای ایجاد جدول مدل شما در پایگاه داده اجرا خواهد کرد. دستور sqlmigrate نام مهاجرت‌ها را می‌گیرد و کد SQL آن‌ها را بدون اجرا کردن، باز می‌گرداند.

برای مشاهده خروجی SQL اولین مهاجرت خود، دستور زیر را در ترمینال اجرا کنید:

python manage.py sqlmigrate blog 0001

خروجی باید به شکل زیر باشد:

BEGIN; -- -- Create model Post -- CREATE TABLE "blog_post" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE; -- -- Create blog_post_publish_bb7600_idx on field(s) (-publish of model post) -- CREATE INDEX "blog_post_publish_bb7600_idx" ON "blog_post" ("publish" DESC); CREATE INDEX "blog_post_slug_b95473f2" ON "blog_post" ("slug"); CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id"); COMMIT;

خروجی دقیق بسته به پایگاه داده‌ای که استفاده می‌کنید، متفاوت خواهد بود. خروجی بالا برای SQLite تولید شده است. همانطور که در خروجی مشاهده می‌کنید، جنگو نام جداول را با ترکیب نام اپلیکیشن و نام مدل به صورت حروف کوچک (blog_post) ایجاد می‌کند؛ اما شما همچنین می‌توانید با استفاده از ویژگی db_table در کلاس Meta مدل خود، یک نام سفارشی برای جدول دیتابیس تعیین کنید.

جنگو یک ستون id با قابلیت خودکار افزایشی (Auto-incremental) ایجاد می‌کند که به عنوان کلید اصلی (Primary Key) برای هر مدل استفاده می‌شود، اما شما می‌توانید با تعیین primary_key=True روی یکی از فیلدهای مدل خود، این مورد را تغییر دهید (Override کنید). ستون پیش‌فرض id شامل یک عدد صحیح است که به صورت خودکار افزایش می‌یابد. این ستون با فیلد id که به طور خودکار به مدل شما اضافه می‌شود، مطابقت دارد.

سه ایندکس دیتابیس زیر ایجاد شده‌اند:

  1. یک ایندکس با ترتیب نزولی (Descending) روی ستون publish: این همان ایندکسی است که ما صراحتاً با استفاده از گزینه indexes در کلاس Meta مدل تعریف کردیم.

  2. یک ایندکس روی ستون slug: زیرا فیلدهای از نوع SlugField به صورت پیش‌فرض شامل یک ایندکس هستند.

  3. یک ایندکس روی ستون author_id: زیرا فیلدهای از نوع ForeignKey به صورت پیش‌فرض شامل یک ایندکس هستند.

بیایید مدل Post را با جدول متناظر آن در دیتابیس یعنی blog_post مقایسه کنیم:

مدل پست و جدول آن در پایگاه داده
مدل پست و جدول آن در پایگاه داده

بیایید پایگاه داده را با مدل جدید همگام کنیم.

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

python manage.py migrate

خروجی‌ای دریافت خواهید کرد که در پایان آن، این خط دیده می‌شود:

Applying blog.0001_initial... OK

ما اکنون مهاجرت‌های مربوط به برنامه‌هایی را که در INSTALLED_APPS فهرست شده‌اند، اعمال کردیم؛ از جمله برنامه blog. پس از اعمال مهاجرت‌ها، پایگاه داده وضعیت فعلی مدل‌ها را منعکس می‌کند.

اگر فایل models.py را ویرایش کنید تا فیلدهای مدل‌های موجود را اضافه، حذف یا تغییر دهید، یا اگر مدل‌های جدیدی اضافه کنید، باید با استفاده از دستور makemigrations یک مهاجرت جدید بسازید. هر مهاجرت به جنگو اجازه می‌دهد تغییرات مدل‌ها را ردیابی کند. سپس باید آن مهاجرت را با دستور migrate اعمال کنید تا پایگاه داده با مدل‌های شما همگام بماند.


پست قبلی: (فصل اول - اپیزود ۷ - اضافه کردن ترتیب‌بندی، تنظیم اندیس در پایگاه داده و فعال سازی اپلیکیشن)

پست بعدی: (فصل اول - اپیزود ۹ - ایجاد مدیر و پنل مدیریت)

ترجمه کتاب
۴
۰
رضا رضایی
رضا رضایی
برنامه‌نویس جونیور بک‌اند با تمرکز بر پایتون و فریم‌ورک جنگو. علاقه‌مند به ساخت برنامه‌های تحت وب مقیاس‌پذیر و قابل اعتماد. مشتاق مشارکت در پروژه‌های واقعی و پیشرفت در توسعه بک‌اند.
شاید از این پست‌ها خوشتان بیاید