Django

راهنمای کامل جنگو برای مبتدیان – قسمت 3

به بخش سوم آموزش جنگو خوش آمدید! در مقاله قبل یعنی راهنمای کامل جنگو برای مبتدیان قسمت 2 توضیحاتی درباره پروژه و چیزی که قرار بنویسیم و روابط دیتابیسی گفتیم.

در این مقاله، کمی وارد فاز عملی میشیم و کد زنی ها رو آغاز میکنیم.

Models (مدل ها)

مدل‌ها اساساً نمایشی از طرح‌بندی پایگاه داده برنامه شما هستند.کاری که ما در این بخش انجام میدیم اینکه طرح بندی پایگاه داده ای رو که در قسمت قبل توضیح دادیم کد نویسی کنیم: Board، Topic و Post.

مدل کاربر قبلاً در داخل یک برنامه داخلی به نام auth تعریف شده که در پیکربندی INSTALLED_APPS ما در زیر فضای نام django.contrib.auth قرار گرفته.

ما تمام کارهای مربوط به فایل boards/models.py رو انجام خواهیم داد(به تصاویر مربوط به مقاله قبل مراجعه کنید).

مدل جنگویی ما:

from django.db import models
from django.contrib.auth.models import User


class Board(models.Model):
    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=100)


class Topic(models.Model):
    subject = models.CharField(max_length=255)
    last_updated = models.DateTimeField(auto_now_add=True)
    board = models.ForeignKey(Board, related_name='topics')
    starter = models.ForeignKey(User, related_name='topics')


class Post(models.Model):
    message = models.TextField(max_length=4000)
    topic = models.ForeignKey(Topic, related_name='posts')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(null=True)
    created_by = models.ForeignKey(User, related_name='posts')
    updated_by = models.ForeignKey(User, null=True, related_name='+')

همه مدل ها زیر کلاس django.db.models.Model هستند.کلاس ها به جداول پایگاه داده تبدیل میشن. هر فیلد با نمونه هایی از زیر کلاس های django.db.models.Field (هسته داخلی جنگو) نشان داده میشن و به ستون های پایگاه داده ترجمه میشن.

فیلدهای CharField، DateTimeField، و غیره، همه زیر کلاس‌های django.db.models.Field هستن و در هسته جنگو گنجانده شدن و آماده استفاده هستن.

در اینجا ما فقط از فیلدهای CharField، TextField، DateTimeField و ForeignKey برای تعریف مدل ها استفاده می کنیم. اما جنگو طیف گسترده ای از گزینه ها رو برای نمایش انواع مختلف داده مانند IntegerField، BooleanField، DecimalField و بسیاری دیگر ارائه میکنه که در صورت نیاز به آنها اشاره خواهیم کرد.

بعضی از فیلدها یک سری آرگومان ها رو از ما میخوان، مثل CharField. ما همیشه باید max_length رو تنظیم کنیم. این اطلاعات برای ایجاد ستون پایگاه داده استفاده میشن. جنگو باید بدونه که ستون پایگاه داده باید چقدر بزرگ باشد. پارامتر max_length نیز توسط Django Forms API برای اعتبارسنجی ورودی کاربر استفاده خواهد شد. بعدا توضیحات بیشتری درباره هر کدام از این مباحث میدم.

در تعریف مدل Board،در قسمت name، پارامتر unique=True قرار میدم، این پارامتر، منحصر به فرد بودن فیلد رو در سطح پایگاه داده اعمال می کنه یعنی این فیلد نمیتونه مقادیر تکراری بگیره.

در مدل Post، فیلد create_at یک پارامتر اختیاری داره که auto_now_add روی True تنظیم شده. این به جنگو دستور می ده تا تاریخ و زمان فعلی رو هنگام ایجاد یک شی Post تنظیم کنه.یعنی موقعی که من یک پست رو مینویسم به صورت اتوماتیک زمان نوشتن پست رو برای این فیلد اختصاص می ده.

یکی از راه های ایجاد رابطه بین مدل ها استفاده از فیلد ForeignKey هست که یک پیوند بین مدل ها ایجاد می کنه به فیلد ForeignKey باید مدلی که رو که قراره با اون رابطه داشته باشه رو بدیم.

به عنوان مثال، در مدل Topic، فیلد board یک مدل ForeignKey به مدل Board هست که به جنگو میگه که یک نمونه Topic تنها به یک نمونه Board وصل هست. پارامتر related_name برای ایجاد یک رابطه معکوس استفاده میشه که در اون نمونه‌های Board به فهرستی از نمونه‌های Topic مربوط بهش دسترسی داره.یعنی وقتی من میخواهم از داخل board به topic دسترسی داشته باشم از این نام استفاده می کنم.

جنگو به طور خودکار این رابطه معکوس رو ایجاد می کنه و related_name اختیاری هست. اما اگر نامی براش قرار ندیم، جنگو آن رو با نام: (class_name)_set تولید می کنه. برای مثال، در مدل Board، نمونه‌های Topic تحت ویژگی topic_set در دسترس هستن. در عوض، ما به سادگی نام اونها رو به موضوعات تغییر دادیم تا راحت تر یامون بمونه.

داخل مدل Post، فیلد updated_by مقدار ‘+’ = related_name رو قرار دادیم که به جنگو دستور میده که ما به این رابطه معکوس نیاز نداریم، بنابراین نادیدش بگیر.

عکس زیر مقایسه بین نمودار کلاس و کد منبع برای تولید مدل ها با جنگو قابل مشاهدس. خطوط سبز نشان دهنده نحوه برخورد ما با روابط معکوس هستش.

راهنمای کامل جنگو برای مبتدیان – قسمت 3_تعریف مدل های نمودار کلاس

Migrating در Models

مرحله بعدی اینکه به جنگو بگیم پایگاه داده رو ایجاد کنه که بتونیم ازش استفاده کنیم.Command Line Tools رو باز میکنیم، محیط مجازی رو فعال میکنیم ، به پوشه ای که فایل manager.py اونجا هست میریم و دستورات زیر رو اجرا کنید:

python manage.py makemigrations

نوشته ای مثل نوشته پایین رو دریافت میکنید:

Migrations for 'boards':
  boards/migrations/0001_initial.py
    - Create model Board
    - Create model Post
    - Create model Topic
    - Add field topic to post
    - Add field updated_by to post

حالا، جنگو فایلی به اسم 0001_initial.py تو دایرکتوری boards/migrations ایجاد کرده که نشون دهنده وضعیت فعلی مدل های برنامه ما است. در مرحله بعدی، جنگو از این فایل برای ایجاد جداول و ستون ها استفاده می کنه.

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

python manage.py sqlmigrate boards 0001

اگر با SQL آشنایی ندارید، نگران نباشید. ما توی این مجموعه آموزشی مستقیماً با SQL کار نمیکنیم. تمام کارها فقط با استفاده از Django ORM انجام میشه که یک لایه انتزاعی هستش که با پایگاه داده ارتباط برقرار می کنه.

گام بعدی اعمال migration هستش که ایجاد کردیم:

python manage.py migrate

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

Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying sessions.0001_initial... OK

از اونجایی که این اولین باری هستش که پایگاه داده رو میسازیم، دستور migrate فایل های migration مربوط به برنامه های از پیش آماده جنگو رو که توی INSTALLED_APPS فهرست شدن رو هم اعمال میکنه. خط Applying boards.0001_initial… OK، مهاجرتی (migration) که در مرحله قبل ایجاد کردیم.الان پایگاه داده ما آماده استفاده است.

راهنمای کامل جنگو برای مبتدیان – قسمت 3

توجه

توجه به این نکته مهم که SQLite یک پایگاه داده با کیفیت برای استفاده در حالت پابلیش نیست. SQLite توسط بسیاری از شرکت ها توی هزاران محصول استفاده میشه، مثل همه دستگاه های Android و iOS، همه مرورگرهای وب اصلی، ویندوز 10، macOS و غیره.فقط بدونید که برای همه کار ها مناسب نیست. وب سایت های با حجم بالا، برنامه های کاربردی فشرده، مجموعه داده های بزرگ، همزمانی بالا، شرایطی هستن که در نهایت با استفاده از SQLite منجر به ایجاد مشکل میشن.
من توی مراحل توسعه پروژه از SQLite استفاده میکنم چون راحت هست و نیازی به نصب چیز دیگری نداره. وقتی که پروژه تموم میشه و بآماده پابلیش میشه، به PostgreSQL یا هر دیتا بیس مناسب تری سوئیچ می کنم. برای وب سایت های ساده این کار خوب است. اما برای وب سایت های پیچیده، توصیه میشه از همون پایگاه داده برای توسعه و تولید استفاده کنیم.
اگر دوست دارید درباره دیتابیس ها بیشتر بدونید به مقالات ما درباره پایگاه داده مراجعه کنید.

آزمایش با Models API

یکی از مزایای بزرگ توسعه با پایتون، پوسته تعاملیش هست. من همیشه ازش استفاده می کنم. یک راه سریع برای امتحان کردن و آزمایش کتابخانه ها و APIها هست.می تونید با استفاده از ابزار manager.py، یک پوسته پایتون رو برای پروژه فعال کنید:

python manage.py shell
Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

ما می تونیم هر مدلی رو تو پروژه وارد کنیم وآن رو تست کنیم.

با کلاس Board شروع میکنیم:

from boards.models import Board

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

board = Board(name='Django', description='This is a board about Django.')

برای اینکه این شی جدید رو که نوشتیم تو پایگاه داده ذخیره کنیم باید از متد save استفاده کنیم:

board.save()

روش save هم برای ایجاد و هم برای به روز رسانی اشیاء استفاده میشه. الان یک شی جدید به اسم جنگو ایجاد کردیم بعد از ذخیره اون برای اولین بار، جنگو به طور خودکار شناسه (ID) رو براش تنظیم می کنه:

board.id
1

ما می تونیم به بقیه فیلدها هم دسترسی داشته باشیم:

board.name
'Django'
board.description
'This is a board about Django.'

برای به‌روزرسانی یک مقدار هم می‌تونیم همین کار رو بکنیم:

board.description = 'Django discussion board.'
board.save()

هر مدل جنگو یک مدیر مدل (Model Manager) داره که می تونیم از طریق ویژگی objects پایتون بهش دسترسی داشته باشیم. و عمدتاً برای اجرای کوئری در پایگاه داده استفاده میشه. برای مثال، می‌تونیم از آن برای ایجاد مستقیم یک شی Board جدید استفاده کنیم:

board = Board.objects.create(name='Python', description='General discussion about Python.')
board.id
2
board.name
'Python'

پس، الان ما دو board داریم. ما می تونیم از objects برای لیست کردن تمام board های موجود در پایگاه داده هم استفاده کنیم:

Board.objects.all()
<QuerySet [<Board: Board object>, <Board: Board object>]>

نتیجه یک QuerySet خواهد بود. بعدا بیشتر دربارش صحبت میکنیم. اساساً، این فهرستی از اشیاء توی پایگاه داده است. می بینیم که دوتا شی داریم، اما فقط می تونیم شی Board رو بخونیم. دلیلش هم اینکه ما متد __str__ رو توی مدل Board تعریف نکردیم.

متد __str__ یک نمایش رشته ای از یک شی هست. می تونیم از اسم board ها برای نشان دادنش استفاده کنیم. پس اول از کنسول تعاملی خارج میشیم:

exit()

بعد فایل models.py توی برنامه boards رو ویرایش میکنیم:

class Board(models.Model):
    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=100)

    def __str__(self):
        return self.name

حالا دوباره کوئری رو امتحان می کنیم. دوباره کنسول تعاملی رو باز میکنیم:

python manage.py shell
from boards.models import Board

Board.objects.all()
<QuerySet [<Board: Django>, <Board: Python>]>

بهتر شد.

ما می تونیم با این QuerySet مثل یک لیست رفتار کنیم. فرض کنید می‌خواستیم روی اون تکرار کنیم و توضیحات هر board رو چاپ کنیم:

boards_list = Board.objects.all()
for board in boards_list:
    print(board.description)

نتیجه اینطوری میشه:

Django discussion board.
General discussion about Python.

به طور مشابه، ما می تونیم از Model Manager برای کوئری از پایگاه داده و برگردوندن یک شی استفاده کنیم. برای این کار از روش get استفاده می کنیم:

django_board = Board.objects.get(id=1)

django_board.name
'Django'

اما ما باید مراقب این نوع عملیات باشیم. اگر بخوایم یک شی رو بدست بیاریم که وجود نداره، مثلاً یک board با id=3، با ارور موجه میشیم:

board = Board.objects.get(id=3)

boards.models.DoesNotExist: Board matching query does not exist.

می‌تونیم از متد get برای هر فیلد مدلی استفاده کنیم، اما ترجیحاً از فیلدی استفاده کنیم که بتونه یک شی رو به‌طور منحصربه‌فرد شناسایی کنه. مگرنه، کوئری ممکن که بیش تر از یک شی رو برگردونه که باعث ایجاد ارور میشه.

توجه کنید که کوئری به حروف بزرگ و کوچک حساس هستش، “django” با حروف کوچک صحیح نیست:

Board.objects.get(name='django')
boards.models.DoesNotExist: Board matching query does not exist.

خلاصه ای از عملیات مدل

این هم خلاصه ای از کل بحث فقط Board به کلاس اشاره میکنه و board به یک نمونه (یا شی) از کلاس مدل Board اشاره داره:

نمونه کدعملکرد
board = Board()بدون ذخیره کردن یک شی بسازید
board.save()ذخیره یک شی (ایجاد یا به روز رسانی)
Board.objects.create(name='...', description='...')ایجاد و ذخیره یک شی در پایگاه داده
Board.objects.all()لیست تمام اشیاء
Board.objects.get(id=1)یک شی واحد را دریافت کنید که با یک فیلد مشخص می شود

توی قسمت بعدی شروع به نوشتن view و نمایش board های خودمون توی صفحات HTML می کنیم.

امیرحسین باقری

امیرحسین باقری هستم عاشق برنامه نویسی مخصوصا با python و همینطور طراح قالب و متخصص فرانت اند؛ از دانشی که تو این مدت بدست آوردم میشه به HTML, CSS, Bootstrap, Flexbox, SASS, Python, Django, DRF و هوش مصنوعی اشاره کرد.

دیدگاهتان را بنویسید

دکمه بازگشت به بالا