مدل، قرارداد شما با پایگاه داده است
هر کلاس مدل یک جدول و هر فیلد یک ستون است. انتخاب نوع فیلد و گزینههایش فقط سلیقه نیست: روی درستی داده، سرعت کوئری و اعتبارسنجی فرمها و ادمین اثر مستقیم دارد. مدل طرح فرش یک کارخانهی کاشانی را ببینید:
# apps/catalog/models.py
from django.db import models
from django.db.models.functions import Now
class Carpet(models.Model):
class Density(models.IntegerChoices):
D700 = 700, "۷۰۰ شانه"
D1000 = 1000, "۱۰۰۰ شانه"
D1200 = 1200, "۱۲۰۰ شانه"
class Status(models.TextChoices):
DRAFT = "draft", "پیشنویس"
ACTIVE = "active", "فعال"
ARCHIVED = "archived", "بایگانی"
code = models.CharField("کد طرح", max_length=20, unique=True)
name = models.CharField("نام طرح", max_length=100, db_index=True)
density = models.PositiveSmallIntegerField("تراکم", choices=Density)
status = models.CharField("وضعیت", max_length=10, choices=Status, default=Status.DRAFT)
price = models.PositiveBigIntegerField("قیمت هر متر (ریال)")
stock = models.PositiveIntegerField("موجودی", default=0)
weight_kg = models.DecimalField("وزن", max_digits=6, decimal_places=2, null=True, blank=True)
description = models.TextField("توضیحات", blank=True)
created_at = models.DateTimeField(db_default=Now())
updated_at = models.DateTimeField(auto_now=True)
از Django 5.0 میتوانید خود کلاس TextChoices را مستقیم به choices بدهید و دیگر لازم نیست .choices بنویسید. db_default هم (باز از 5.0) مقدار پیشفرض را در خود پایگاه داده تعریف میکند؛ حتی INSERTهای خارج از جنگو هم آن را میگیرند.
null در برابر blank
| گزینه | سطح | معنی |
|---|---|---|
null=True | پایگاه داده | ستون میتواند NULL باشد |
blank=True | اعتبارسنجی (فرم/ادمین) | فیلد در فرم میتواند خالی بماند |
قاعدهی عملی: برای فیلدهای متنی (CharField، TextField) فقط blank=True بگذارید و «خالی» را با رشتهی خالی نشان دهید. برای عدد، تاریخ و ForeignKey اختیاری، هر دو را با هم بگذارید؛ چون عدد «خالی» معنایی جز NULL ندارد.
پول را چطور ذخیره کنیم؟
هرگز با FloatField. ریال را بهصورت عدد صحیح (PositiveBigIntegerField) نگه دارید و تبدیل به تومان را فقط در نمایش انجام دهید. اگر اعشار واقعی دارید (نرخ ارز، وزن) از DecimalField استفاده کنید.
نکتههایی که کمتر کسی میداند
- CharField با
null=Trueدو نوع «خالی» میسازد (NULL و رشتهی خالی) و کوئریها را پیچیده میکند؛ تنها استثنا وقتی است کهunique=Trueدارید و چند رکورد خالی مجاز است. unique=Trueخودش ایندکس میسازد؛ اضافه کردنdb_index=Trueکنارش فقط یک ایندکس تکراری بیفایده است.- برای هر فیلد choices، متد
get_status_display()خودکار ساخته میشود و برچسب فارسی را برمیگرداند؛ در قالب بدون پرانتز:{{ carpet.get_status_display }}. auto_nowفقط درsave()بهروز میشود؛QuerySet.update()آن را دست نمیزند و باید خودتانupdated_at=timezone.now()را بفرستید.choicesفقط در اعتبارسنجی اعمال میشود، نه در پایگاه داده؛ برای ضمانت واقعی یک CheckConstraint اضافه کنید (درس ۸).