TGViewer
بنیاد پایتون کاران فارسی بنیاد پایتون کاران فارسی @psfarsi · 1.89K subscribers
Post #1464 625
بنیاد پایتون کاران فارسی فرض کنید ما این Schema رو داریم: class PostBase(BaseModel): title: str content: str category_id: int | None = None class PostCreate(PostBase): pass class PostResponse(PostBase): id: int slug: str author_id: int created_at:…
خب پس از همکاری و بحث و گفتگوی فوق العاده ای که درباره این سوال شد بریم سراغ جوابش
همونطور که آقا سروش اشاره کرد، اینجا یک اشتباه سهوی به وجود اومده.

این قسمت:
category_id: int | None = None


نمیگه:

اگر category_id مقدار 0 داشت، اون را به None تبدیل کن.


بلکه میگه:

category_id

میتونه یک

int
یا

None
باشه و اگر فیلد اصلا ارسال نشد، مقدار پیش‌فرض

None
خواهد بود.


بنابراین:

اگه category_id اصلا ارسال نشه، مقدار پیش‌فرض که None هست به category_id اختصاص داده میشه

و اگه :
{
"category_id": null
}


ارسال بشه بازم None میشه.

اما اگه بنویسیم :
{
"category_id": 0
}


و ارسالش کنیم، category_id = 0 میشه. تا اینجا همه چی ساده و مشخص بود. اما پس مشکل اصلی کجاست؟

مشکل اصلی در Router صورت میگیره!

اینجا ما گفتیم:
if data.category_id:


که یعنی اگه ما 0 ارسال کنیم مثل این میمونه که ما این شرط رو چک کردیم:
if 0:


و در پایتون مقدار 0 برابر با Falsy value هست.
پس وقتی:
data.category_id == 0

باشه، این شرط:
if data.category_id:

اجرا نمیشه.
در نتیجه، اصلاً این Query هم اجرا نمیشه:
select(Category).where(Category.id == data.category_id)


و Router مستقیم میره سراغ ساخت Post:
post = Post(
...
category_id=0,
)

بعد:
await db.commit()


و SQLAlchemy درخواست INSERT را به دیتابیس (در اینجا PostgreSQL) میفرسته.
PostgreSQL هم هنگام INSERT بررسی میکنه:
آیا در جدول

categories
رکوردی با

id = 0
وجود دارد؟

چون مقدار category_id=0 به رکوردی در جدول categories اشاره نمی‌کنه، Foreign Key Constraint نقض میشه و IntegrityError میگیریم.
راه حل چیه؟
در این مثال، category_id اختیاریه و میتونه None باشه. پس ما میتونیم None بودن یا نبودنش رو چک کنیم و به صراحتا بگیم :

if data.category_id is not None:
result = await db.execute(
select(Category).where(Category.id == data.category_id)
)

category = result.scalar_one_or_none()

if category is None:
raise CategoryNotFound(data.category_id)


حالا اگر:
"category_id": 0

باشه، شرط اجرا میشه و وجود Category با ID صفر بررسی میشه.
اگر وجود نداشته باشه، قبل از رسیدن به Database خطای مناسب رو raise میکنیم.
که اینجا میرسیم به یکی از اصول Zen of Python :

Explicit is better than implicit

⚠️ نکته : اگر از نظر Business Logic پروژه تون، مقدار category_id باید عددی بزرگتر از صفر باشه، بهتره که این محدودیت رو در Schema تعریف کنیم:

from pydantic import BaseModel, Field

class PostBase(BaseModel):
title: str
content: str
category_id: int | None = Field(default=None, gt=0)


حالا:
{
"category_id": 0
}


اصلاً وارد منطق Router نمیشه و Pydantic خطای Validation Error بر میگردونه.

اما:
{
"category_id": null
}


و :

{
"category_id": 5
}

مشکلی نداره.
  • 👏 2
More from @psfarsi
  1. Oct 6, 2026🚀 هاست حرفه‌ای مخصوص ربات‌های تلگرامی 🇳🇱 سرور هلند (Leaseweb) ⚡️ تأخیر پایین و اتصال سر…
  2. Sep 16, 2026#خارج_از_بحث چرا چیزهایی که یاد می‌گیریم را به اشتراک بگذاریم؟ یکی از عادت‌هایی که می‌توان…
  3. Sep 10, 2026فرض کنید ما این Schema رو داریم: class PostBase(BaseModel): title: str content: str catego…
  4. Aug 13, 2026در جنگو، از blank=True استفاده کنیم یا null=True ؟ یکی از اشتباهات رایج در طراحی مدل‌های D…
  5. Oct 26, 2025سرعت 5G همراه اول حق مینوازد 🔥 〰〰〰〰〰 🌐 Website: LearnSecurity.ir 🎓 Channel: @LearnSecur…
  6. Mar 20, 2025// Initialization of a new chapter... #define SUCCESS 100% #define STABILITY 100% #define…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →