Pythopia
547 subscribers
50 photos
8 videos
14 links
آموزش تخصصی برنامه‌نویسی و هوش مصنوعی
از مقدماتی تا پیشرفته | پروژه‌محور
همراه با پشتیبانی، تمرین عملی و مسیر شغلی

ارتباط با ادمین و ثبت‌نام در دوره: @pythopia

چنل یوتیوب:
https://youtube.com/@pythopiatutoring
Download Telegram
🔒🐍 چرا پایتون const ندارد؟

در پایتون، «متغیر» در واقع یک اسم است که به یک شیء وصل می‌شود. وقتی می‌نویسیم x = 2 یعنی «اسم x به شیء ۲ وصل شو».
اگر بعدا از آن بنویسیم x = 3، فقط اتصال اسم عوض می‌شود (rebinding).
ولی اگر بنویسیم lst.append(4)، خود شیء تغییر می‌کند (mutation).

حالا اگر پایتون const داشت، فقط جلوی تعویض اسم را می‌گرفت، نه تغییر محتوای شیء. یعنی هنوز می‌شد شیءهای قابل‌تغییر (مثل list یا dict) را تغییر داد، پس فایدهٔ زیادی نداشت.

در زبان های دیگر:
در بیشتر زبان‌ها مثل JavaScript، Java و C#، وقتی متغیری را با const یا readonly تعریف می‌کنیم، در واقع فقط نام آن متغیر قفل می‌شود؛ یعنی دیگر نمی‌توان آن را به شیء یا مقدار دیگری نسبت داد، اما خود شیء (اگر قابل‌تغییر باشد) همچنان می‌تواند دستکاری شود. در C و ++C این مفهوم کمی پیچیده‌تر است؛ چون const می‌تواند هم به اشاره‌گر (نام) و هم به داده اشاره کند و رفتار آن بستگی دارد به اینکه «کدام بخش» را ثابت کرده باشیم.



در پست بعدی راه های جایگزین مشخص کردن const بودن در پایتون رو بررسی میکنیم.
@pythopiachannel
9🔥3💯2
Pythopia
🔒🐍 چرا پایتون const ندارد؟ در پایتون، «متغیر» در واقع یک اسم است که به یک شیء وصل می‌شود. وقتی می‌نویسیم x = 2 یعنی «اسم x به شیء ۲ وصل شو». اگر بعدا از آن بنویسیم x = 3، فقط اتصال اسم عوض می‌شود (rebinding). ولی اگر بنویسیم lst.append(4)، خود شیء تغییر…
🔒🐍 راه‌های جایگزین برای «ثابت» (const) در پایتون

در پست قبلی دیدیم که پایتون به‌خاطر مدل
«اسم → شیء» و وجود mutation، نیازی به const به سبک زبان‌های دیگر نداره. اما چطور می‌تونیم در عمل «قصد ثابت بودن» رو نشون بدیم یا جلوی تغییر ناخواسته رو بگیریم؟

اینجا چند روش عملی و استاندارد رو بررسی می‌کنیم:


۱. استفاده از `NamedTuple` یا `dataclasses(frozen=True)`
برای ساختارهای داده‌ای غیرقابل‌تغییر (immutable):

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
x: int
y: int

p = Point(2, 3)
p.x = 5 # خطا! FrozenInstanceError


مزیت: کاملاً immutable، حتی فیلدها هم تغییر نمی‌کنن.


۲. ماژول `typing.Final` (برای تایپ‌چکرها)
نشون می‌ده که نباید مقدار عوض بشه (در زمان اجرا چک نمی‌شه، ولی mypy خطا می‌ده):

from typing import Final

API_KEY: Final = "abc123"
API_KEY = "new" # mypy: Cannot assign to final name


فقط در توسعه کمک می‌کنه، در runtime جلوی تغییر رو نمی‌گیره.


۳. قرارداد نام‌گذاری: حروف بزرگ
رایج‌ترین روش در جامعه پایتون:

MAX_RETRIES = 3
PI = 3.14159


همه می‌دونن که نباید تغییرش بدن.
ابزارهایی مثل pylint می‌تونن هشدار بدن اگر تغییر کنه.


۴. ماژول `types` + `SimpleNamespace` (اختیاری)
برای گروه‌بندی ثابت‌ها:
from types import SimpleNamespace

Config = SimpleNamespace(
DEBUG=False,
VERSION="1.0",
MAX_USERS=100
)


خوانا و مرتب تره، ولی همچنان قابل تغییره.


۵. استفاده از `Enum` برای مقادیر ثابت
وقتی چند مقدار ثابت و مرتبط داریم:

from enum import Enum

class Status(Enum):
PENDING = 1
SUCCESS = 2
FAILED = 3


مقادیر کاملاً ثابت و غیرقابل تغییر، با پشتیبانی تایپ.


۶. جلوگیری از mutation در لیست/دیکشنری با `tuple` یا `frozenset`
CONST_LIST = (1, 2, 3)        # tuple → immutable
CONST_SET = frozenset({1, 2}) # frozenset → immutable


نمی‌تونی .append() یا .add() کنی.


۷. ماژول سفارشی `const` (اختیاری، پیشرفته)
می‌تونی خودت بسازی:

class Const:
def __setattr__(self, name, value):
if hasattr(self, name):
raise AttributeError(f"Can't change const.{name}")
super().__setattr__(name, value)

const = Const()
const.PI = 3.14
# const.PI = 3 # خطا!


اگه تجربه ای از شبیه سازی const در پروژه هات داری کامنت کن ✍🏽

@pythopiachannel
7🔥3
🔥🐍 شما بگید، ما بهتون یاد می‌دیم!

محتوای پست های بعدی قراره از درخواست های شما باشه😌

هر موضوعی تو پایتون یا مفاهیم برنامه نویسی که دوست داری عمیق و کاربردی یاد بگیری، همین زیر کامنت کن:

یه ترفند خاص؟
یه ماژول ناشناخته؟
یه پروژه واقعی؟
حل یه باگ سخت؟
مفاهیم پیشرفته مثل metaclass، descriptor یا asyncio؟

با مثال کاربردی و فرمت دلخواه شما

اولین کامنت‌ها اولویت دارن! 🚀

@pythopiachannel
13
این هفته به جای کافه رفتن، پایتون یاد بگیر!

“کارگاه آموزشی پایتون”

📍سرفصل ها:
ساختارهای داده
دستورهای شرطی
حلقه
تابع
ساخت ماژول اختصاصی
کار با فایل

🎖️همراه با ارائه مدرک معتبر از دانشگاه الزهرا

پشتیبانی فوری در تلگرام( گروه اختصاصی + چت خصوصی)

📚دسترسی دائمی به جزوه‌ها و ویدئوی
جلسات

📆زمان برگزاری:
۱۳ و ۱۴ آذر ۱۴۰۴
ساعت ۱۰ الی۱۲

💰شهریه:
عموم دانشجویان: ۳۰۰ هزارتومان
دانشجویان دانشگاه های الزهرا و زنجان:۲۷۸ هزارتومان

شرکت برای عموم آزاد است.

👥ظرفیت: ۲۵ نفر

برای رزرو به آیدی زیر پیام دهید:
@pythopia

❅معاونت فرهنگی و اجتماعی دانشگاه الزهرا (س)❅
https://eitaa.com/farhangialzahraplans
7🔥3
چرا باید تست نوشتن بلد باشیم؟

تو برنامه‌نویسی، اینکه صرفا “کدت کار کنه” فقط نصف ماجراست. نصف مهم‌ترش اینه که همیشه و در هر شرایطی درست کار کنه؛ فارغ از اینکه چه متغیر هایی عوض بشن. دقیقاً همین‌جاست که تست‌نویسی نقش اصلی رو بازی می‌کنه.

چندتا دلیل خیلی ساده ولی مهم:

🔹زودتر می‌فهمی کجای کارت می‌لنگه.

🔹وقتی یه چیزی رو تغییر می‌دی، خیالت راحته که بقیه خراب نمیشه .

🔹تست‌ها مثل دفترچه‌ی راهنمای زنده‌ان؛ می‌گن هر بخش از کد دقیقاً چه انتظاری رو باید برآورده کنه.

تو کار تیمی هم عملاً جون همه رو نجات می‌دن؛ چون هر فرد مطمئنه با یه تغییر کوچیک پروژه رو خراب نمی‌کنه.

خلاصه اینکه: تست‌نویسی هم برای خودت خوبه، هم برای اعصابت، هم برای بقیه آدمای بی‌گناهی که قراره رو کد تو کار کنن 😃

توی پست بعدی با unittest در پایتون آشنا می‌شیم.

@pythopiachannel
11
تست‌نویسی مقدماتی با unittest

پایتون خودش یه ابزار تست‌نویسی به اسم unittest داره، و خوبی‌ش اینه که برای شروع لازم نیست چیز خاصی بلد باشی.

یه مثال ساده:
import unittest

def add(a, b):
"""
این تابع دو مقدار رو با هم جمع می‌کنه، اما:
- اگر هر کدوم از ورودی‌ها str باشه → خطا بده (TypeError)
- اگر هر کدوم از ورودی‌ها None باشه → خطا بده
- فقط اعداد int یا float رو قبول کنه
"""
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("ورودی‌ها باید عدد باشن!")
if a is None or b is None:
raise ValueError("ورودی نمی‌تونه None باشه!")

return a + b


# ------------ تست‌ها --------------
class TestAddFunction(unittest.TestCase):

# تست‌های موفق (Happy Path)
def test_add_positive_numbers(self):
self.assertEqual(add(2, 3),
5)

def test_add_float_numbers(self):
self.assertEqual(add(2.5, 3.7), 6.2)

def test_add_zero(self):
self.assertEqual(add(10, 0), 10)

# تست‌های خطادار (باید ارور بدن)
def test_add_string_raises_type_error(self):
with self.assertRaises(TypeError):
add("2", 3)

def test_add_none_raises_value_error(self):
with self.assertRaises(ValueError):
add(5, None)



if __name__ == '__main__':
unittest.main(verbosity=2)

کاری که اینجا کردیم:

• یه تابع جمع اعداد نوشتیم که تایپ رو چک میکنه
• یه کلاس تست ساختیم
•در ابتدا چند تا تست که پاس میشن و بعد چند تا تست با ارور های متفاوت گذاشتیم که مطمئن بشیم خروجی تابع درسته.
•با assertEqual چک کردیم که نتیجه دقیقاً همونیه که می‌خوایم

همین! خیلی از پروژه‌های بزرگ دنیا هم از همین ساختار ساده شروع شدن.

🤓چند تا نکته‌ی مهم که از همون اول باید جدی بگیری:

︎هر تست فقط یه چیز رو چک کنه.

︎اسم تست‌هاتو واضح انتخاب کن؛ که بعداً خودت هم بفهمی چی نوشتی.

︎تست‌هات وابسته به محیط و شانس و ساعت سیستم نباشن.

اگر سوالی داشتی تو کامنتا بپرس.

🔥منتظر کوئیز ویژه این بخش باشید.

@pythopiachannel
13
جعبه ابزار «بی‌نهایت» پایتون کدوم کتابخونه‌س؟

اگه از حلقه‌های for تو در تو خسته شدید و کداتون کُند شده، وقتشه با نجات دهنده‌تون آشنا بشید: ماژول itertools

🔧این ماژول شبیه یه آچار فرانسه برای کار با لیست‌ها، تکرارها و ترکیب‌های داده‌ایه. دیگه نیازی نیست ساعت‌ها کد بزنی تا چند تا حالت مختلف رو بچینی.

ماژول itertools برای حل مشکلات زیر طراحی شده است:

🎯سرعت و عملکرد: توابع داخلی این ماژول با کد C نوشته شده‌اند، به همین دلیل خیلی سریع‌تر و بهینه‌تر از حلقه‌های for تو در تو هستند که خودتون می‌نویسید.

مصرف بهینه حافظه (Lazy): این توابع به جای اینکه تمام نتایج ممکن را یک‌باره در حافظه RAM ذخیره کنند، نتایج رو به‌صورت تک به تک و در لحظه نیاز تولید می‌کنند. این یعنی حتی با داده‌های "بی‌نهایت" یا بسیار بزرگ هم می‌توانید بدون مشکل حافظه کار کنید.

🧰کد تمیز و هوشمند: یک خط کد با itertools جایگزین ده‌ها خط کد پیچیده می‌شود و خوانایی پروژه را به شدت بالا می‌بره.

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

بعد از معرفی itertools، وقتشه یکی از پرکاربرد ترین ابزارهاشو ببینیم:
تابع cycle، هر چیزی بدی بهش، بی‌نهایت تکرارش می‌کنه.
و این تکرار می‌تونه برنامه‌ت رو هوشمند تر کنه

🎮 مثال :

فرض کن داری یک بازی ساده می‌سازی و می‌خوای دشمن‌ها یکی‌درمیون از سه مسیر مختلف وارد صفحه بشن:
from itertools import cycle

paths = cycle(["left", "center", "right"])

for _ in range(9):
print("Enemy spawned from:", next(paths))


خروجی:
left
center
right
left
center
right
left
center
right


با cycle منطق چرخشی رو بدون نیاز به شرط‌های تکراری یا مدیریت دستی اندیس‌ها پیاده می‌کنیم.
نه تنها یه الگوی بی‌نقص و قابل اتکا بهمون میده، بلکه یه چرخه‌ی پایدار می‌سازه که توی هر بار فراخوانی، عنصر بعدی رو دقیق و منظم تحویل می‌ده و کدت رو تمیز، خوانا و حرفه‌ای نگه می‌داره.

در پست بعدی، می‌ریم سراغ یکی دیگه از ابزارهای فوق‌العاده itertools.⌛️
4👏3
سلام وقت همگی بخیر 🌱 دوستانی که در کارگاه پایتون ۱۳ و ۱۴ آذر شرکت کرده‌اند، لینک کلاس برایشان ارسال شد. اگر کسی ثبت‌نام کرده اما لینک را دریافت نکرده، لطفاً به پشتیبانی پیام بدهد.
ممنون از همراهی شما 🙏
7
🔔QUIZ TIME
🔥1
چطوری یه حلقه‌ی بی‌نهایت داشته باشیم که اعداد رو یکی‌یکی بشماره بدون اینکه دستی یه متغیر i بسازیم و هر بار i += 1 کنیم؟

از itertools.count() استفاده کن😃

تابع count یه شمارشگر بی‌نهایت و lazy می‌ده که هر بار next بگیری، عدد بعدی رو تحویل می‌ده.

🎮 مثال واقعی:
فرض کن داری یه بازی می‌سازی و می‌خوای به هر موج از دشمن‌ها یه شماره بدی و همزمان سختی بازی و تعداد دشمن ها رو بر اساس شماره‌ی موج افزایش بدی:
from itertools import count

wave_number = count(start=1, step=1) # از 1 شروع کن، هر بار 1 اضافه کن

for _ in range(10): # فقط برای نمایش 10 موج اول
current_wave = next(wave_number)
enemy_speed = 2 + current_wave * 0.5
enemy_count = 5 + current_wave * 2
print(f"موج {current_wave}: سرعت = {enemy_speed}, تعداد دشمن = {enemy_count}")

خروجی:
موج 1: سرعت = 2.5, تعداد دشمن 7
موج 2: سرعت = 3.0, تعداد دشمن = 9
موج 3: سرعت = 3.5, تعداد دشمن = 11
موج 4: سرعت = 4.0, تعداد دشمن = 13


🥈نکته‌های نقره‌ای:

1️⃣می‌تونی start و step دلخواه بدی
[مثلاً count(10, -1) برای شمارش معکوس]

2️⃣مثل همه generator ها کاملاً lazy عه یعنی تا وقتی next نزنی هیچ عددی تولید نمی‌کنه و حافظه نمی‌خوره، همچنین می‌تونی با zip ترکیبش کنی تا یه حلقه‌ی محدود بسازی:

for i, enemy in zip(count(1), list_of_enemies):
print(f"دشمن {i}: {enemy}")


با count دیگه لازم نیست یه متغیر شمارشگر دستی بسازی و نگران فراموش کردن i += 1 باشی.
8
وقتی دیتا زیاده، چطوری جلوی کند شدن اجرای کد در پایتون رو بگیریم؟

وقتی پای دیتای بزرگ وسط میاد یا می‌خوای حلقه‌های بزرگ رو اجرا کنی، سرعت پایتون میاد پایین. این ضعف ذاتیش به عنوان یک زبون مفسری (Interpreted) است.

اگر دنبال یک راه مدرن و کوتاهید، قطعا Numba بهترین گزینه است؛ Numba یک کامپایلر JIT (Just-In-Time) برای پایتونه که برنامه نویس های دیتا عاشقشن.

وظیفه‌اش اینه: کدهای عددی و توابع NumPy پایتون شما رو می‌گیره و با استفاده از موتور LLVM، مستقیماً به کد ماشین فوق سریع تبدیل می‌کنه که انگار با C++ نوشتید!

برای استفاده‌ش نیاز به یادگیری زبان جدید نداری، لازم نیست کل الگوریتمت رو عوض کنی یا از توزیع های پایین تر استفاده کنی و فقط کافیه بالای تابعت یک خط decorator اضافه کنی!




from numba import njit #وارد کردن کامپایلر

@njit #اعمال دکوریتور
def calc_heavy_duty():
s = 0
# فرض کنید اینجا ۱۰ میلیون عملیات دارید
for i in range(10_000_000):
s += i
return s

همین کار ساده باعث می‌شه که کدهای سنگین شما معمولاً ۲۰ تا ۱۰۰ برابر سریع‌تر اجرا بشن!

نظراتتون رو توی کامنت ها برامون بنویسید
🔥62👏1
چه فرمت پست آموزشی براتون جذاب تر و مفید تره؟
Anonymous Poll
54%
متن همراه نمونه کد
13%
ویس همراه نمونه کد
33%
ویدیو
6
Pythopia
متاکلاس در پایتون دقیقاً چیه؟
متاکلاس در پایتون

توی پایتون یه جمله معروف هست که می‌گه: Everything is an object (همه چیز یه آبجکته)
ولی خب اگه کلاسی مثل dict یه آبجکت باشه، پس خودش باید از روی یه «قالب» ساخته شده باشه دیگه، که اون قالب، اسمش متاکلاسه.


👶🏼به بیان ساده تر:
کلاس: قالبی برای ساختن «آبجکت» (مثل قالبِ شیرینی‌پزی).

متاکلاس: قالبی برای ساختنِ خودِ «کلاس» (مثل کارخونه‌ای که اون قالب‌های شیرینی‌پزی رو تولید می‌کنه!).


📍 متاکلاس پیش‌فرض پایتون چیه؟ همه کلاس‌هایی که ما می‌نویسیم، به‌صورت پیش‌فرض توسط type ساخته می‌شن.
بله، همون type که باهاش نوع متغیرها رو چک می‌کنی، خودش لیدرِ متاکلاس‌های پایتونه!

🚀 چرا باید از متاکلاس استفاده کنیم؟
متاکلاس‌ها بهت اجازه می‌دن موقع «تولد» یک کلاس، توی ساختارش دست ببری. مثلاً:

1⃣اجبار به رعایت استانداردهای خاص: مثلاً اگه کلاسی متد save نداشت، کلاً اجازه ساخته شدن بهش نده.

2⃣تغییر خودکار فیلدها: مثلاً تمام ویژگی‌های کلاس رو خودکار به حروف بزرگ تبدیل کن.

3⃣ثبت‌نام خودکار (Registration): کلاس رو به محض ساخته شدن، توی یه لیستِ مرکزی ثبت کن.

توی پست بعدی یه متاکلاس می‌سازیم🏗
5🔥1👏1
Pythopia
متاکلاس در پایتون توی پایتون یه جمله معروف هست که می‌گه: Everything is an object (همه چیز یه آبجکته) ولی خب اگه کلاسی مثل dict یه آبجکت باشه، پس خودش باید از روی یه «قالب» ساخته شده باشه دیگه، که اون قالب، اسمش متاکلاسه. 👶🏼به بیان ساده تر: کلاس: قالبی…
💡 یک مثال از متاکلاس در دنیای واقعی

تا حالا فکر کردی چطور وقتی توی جنگو می‌نویسی

name = models.CharField(...)


این فیلد ساده تبدیل به یک ستون در SQL می‌شه؟ اینجا در پشت صحنه، متاکلاسی به اسم ModelBase هست. اون کدِ تو رو قبل از اینکه اجرا بشه، به یک ساختارداده تبدیل می‌کنه که به SQL ترجمه بشه.

توی این پست می‌خوایم یک «ناظرِ کیفیت» بسازیم! فرض کن سرپرست یک تیم برنامه‌نویسی هستی و می‌خوای همه‌ی اعضای تیم رو مجبور کنی که استانداردها رو رعایت کنن. مثلاً هیچ کلاسی نباید بدون «توضیحات» (Docstring) رها بشه. به جای اینکه دستی چک کنی، یک متاکلاس می‌سازی که نقش ناظر رو بازی کنه:

class DocumentationRequiredMeta(type):
def init(cls, name, bases, attrs):
# چک می‌کنیم که آیا کلاس نوشته شده توضیح (Docstring) دارد یا خیر
if not cls.doc or len(cls.doc.strip()) < 10:
raise TypeError(
f" خطا در کلاس '{name}': نوشتن مستندات (Docstring) اجباری است!"
)
super().init(name, bases, attrs)

# --- حالا تست کنیم ---

class Order(metaclass=DocumentationRequiredMeta):
"""این کلاس برای مدیریت سفارشات آجیل یلدا طراحی شده است."""
pass
# بخاطر داشتن docstring تایید شد

class Task(metaclass=DocumentationRequiredMeta):
pass
# متوقف شد! پایتون اجازه نمی‌ده این کلاس به وجود بیاد.


این یعنی Automation در سطح معماری. تو دیگه نگران این نیستی که کسی استانداردها رو یادش بره؛ چون متاکلاس مثل یک فیلترِ هوشمند، اجازه نمی‌ده کدهای غیراستاندارد حتی متولد بشن!

⚠️ یک واقعیت مهم: حقیقتاً اغلب برنامه‌نویس‌ها توی کل دوران کاری‌شون شاید حتی یک بار هم نیاز به نوشتن متاکلاس پیدا نکنن. این ابزار مخصوص اون درصدِ خاصیه که نمی‌خوان فقط مصرف‌کننده باشن، بلکه می‌خوان فریم‌ورک بسازن، کتابخانه‌های سطح بالا طراحی کنن و زیرساخت‌های پیچیده رو مدیریت کنن.

🏗️ متاکلاس‌ها یعنی رفتن به لایه‌ای که تو دیگه صرفاً مصرف کننده نیستی، بلکه طراحِ قوانینِ بازی هستی، جایی که تو تعیین می‌کنی بقیه چطوری باید کد بزنن.
8
متد clean چطور نمی‌ذاره دیتابیسِت به فنا بره؟

تا حالا توجه کردی که دیتابیس‌ها ذاتا «کم‌عقل» اند؟ 🧠🤷🏻‍♀

دیتابیس شاید بفهمه قیمت نباید «متن» باشه، اما عقلش نمی‌رسه که «قیمت فروش نباید از قیمت خرید کمتر باشه!» اینجاست که لایه‌های اعتبارسنجی (مثل همین عکس) میان وسط:

🎨 ۱. لایه فرانت‌اند (Frontend): همون لایه که کاربر می‌بینه. هدفش فقط اینه که کاربر اذیت نشه (UX). مثلاً اگه فیلدی رو خالی گذاشت، همون‌جا قرمز بشه و نذاره دیتای الکی ارسال کنه.

📄 ۲. لایه فرم (Form/Serializer): اینجا چک می‌کنیم که دیتا «فرمتش» درسته یا نه؟ مثلاً ایمیل واقعاً فرمت ایمیل داره؟ یا تاریخ واقعاً تاریخه؟

🧠 ۳. لایه Model Clean (مغز متفکر): اصل جنس اینجاست! متد clean آخرین سنگر دفاعی شماست. اینجا جاییه که «منطق بیزینس» رو چک می‌کنیم. مثلاً: «آیا این کد تخفیف به این محصول خاص می‌خوره؟» در برنامه‌نویسی به این‌ها می‌گیم Invariants؛ یعنی قوانینی که اگه رعایت نشن، اون دیتا کلاً اعتبار نداره و نباید ذخیره بشه.

🔒 ۴. لایه دیتابیس: آخرین لایه محافظت فیزیکی. چک کردن چیزایی مثل تکراری نبودن (Unique) یا روابط بین جدول‌ها.

ادامه در پست بعد
8
Pythopia
متد clean چطور نمی‌ذاره دیتابیسِت به فنا بره؟ تا حالا توجه کردی که دیتابیس‌ها ذاتا «کم‌عقل» اند؟ 🧠🤷🏻‍♀ دیتابیس شاید بفهمه قیمت نباید «متن» باشه، اما عقلش نمی‌رسه که «قیمت فروش نباید از قیمت خرید کمتر باشه!» اینجاست که لایه‌های اعتبارسنجی (مثل همین عکس)…
🛒 سناریو: محافظِ سرمایه

فرض کن تو مسئول بخش فروش و تخفیف‌های یه فروشگاه آنلاین بزرگی و باید این مسئله که کد تخفیف به درستی و برای محصول مرتبط وارد شه رو کنترل کنی‌.

ممکنه ادمین موقع ساخت کد تخفیف، به هر دلیلی مقدارش رو خیلی زیاد وارد کنه مثلا جای 5 بزنه 50.
از طرفی مشتری ها هم به راحتی می‌تونن سواستفاده کنن.

تو نباید بذاری این اطلاعات خراب برسه به دیتابیس! باید یه فیلتر بذاری که قبل از ذخیره‌سازی نهایی، همه‌چی رو چک کنه.

اینجاست که متد clean نیاز می‌شه، این متد دقیقاً لایه محافظه تا جلوی خطاهای مالی و منطقی رو بگیره.

تصور کن یهو یه سفارش بزرگ میاد، اما حواست نیست و یهو یه کد تخفیف بزرگ می‌زنی که از قیمت اصلی هم بیشتره! 💸
دیتابیس ما که عقل نداره ببینه داری محصول رو "با ضرر" میدی، ولی متد clean مثل یه نگهبان وایمیسته و اجازه نمیده این اتفاق بیافته.

📍 بیا روش پیاده سازیشو ببینیم:

from django.core.exceptions import ValidationError
from django.db import models

class Order(models.Model):
# نام محصول
product_name = models.CharField(max_length=100)
# قیمت اصلی محصول
price = models.DecimalField(max_digits=10, decimal_places=2)
# تخفیفی که روش زدیم
discount = models.DecimalField(max_digits=10, decimal_places=2)

# متد clean: جایی که قانون‌های خودمون رو چک می‌کنیم

def clean(self):
super().clean()
errors = {}

# 🚫 قانون ۱: تخفیفی نده که از اصل پول بیشتر باشه
if self.discount > self.price:
errors['discount'] = "تخفیف از قیمت بیشتره، خطر ورشکستگی :)"

# 🚫 قانون ۲: سقف تخفیف
MAX_DISCOUNT_PERCENT = 0.25

if self.discount > (self.price * MAX_DISCOUNT_PERCENT):
errors['discount'] = چه خبره؟! تخفیف تا ۲۵% مجازه."

if errors:
# اگه گند زدیم، سریع دست نگه دار!
raise ValidationError(errors)


🔒چرا این قانون واجبه؟
۱. نجات از فاجعه: اگه یه ادمین گیج، یا یه مشتری کنجکاو بخواد عدد الکی وارد کنه، سیستم همین‌جا مچش رو می‌گیره.
2. سیاست‌های شرکت: اینجا می‌تونی بگی: "پیتزا رو ۳۰٪ تخفیف بده، ولی ساندویچ رو نهایتاً ۱۵٪."
3. دفتر حساب و کتاب: اگه دیتات درست نباشه، آخر ماه می‌فهمی الکی کلی جنس رو ضرر دادی.

💡 متد clean عین فیلتر تصفیه می‌مونه؛ نمی‌ذاره آشغال (دیتای غلط) بره داخل دیتابیس‌.

شما تو پروژه هاتون بدترین اشتباهی که یه کاربر یا خودتون سر وارد کردن دیتا داشتید چی بوده؟ برامون تعریف کنین 👇
7👏1