Ninja Learn | نینجا لرن
1.26K subscribers
95 photos
36 videos
11 files
306 links
یادگیری برنامه نویسی به سبک نینجا 🥷
اینجا چیزایی یاد میگیری که فقط نینجاهای وب‌ بلدن 🤫

📄 Send me post: https://t.iss.one/NoronChat_bot?start=sec-fdggghgebe

👥 ɢʀᴏᴜᴘ: https://t.iss.one/+td1EcO_YfSphNTlk
Download Telegram
چرا نباید لاجیک پروژه رو تو سریالایزرهای DRF پیاده‌سازی کنیم؟ 🚫

یه موضوع مهم هست که چرا نباید لاجیک پروژه‌مون رو تو سریالایزرها پیاده‌سازی کنیم؟ خیلی از افرادی که میشناسم متاسفانه اینکارو میکنن (پیاده سازی لاجیک توی سریالایزر ها) اگه شماهم حزو این دسته افراد هستید این پست براتون مناسبه

اول از همه سریالایزر تو DRF چیه؟

سریالایزرها تو DRF مسئول تبدیل داده‌ها بین فرمت‌های مختلف (مثل JSON و مدل‌های Django) هستن. کارشون اینه که داده‌ها رو بگیرن، اعتبارسنجی (validation) کنن و به شکل مناسب تحویل بدن. مثلاً یه مدل User رو به JSON تبدیل می‌کنن یا برعکس. تا اینجا همه‌چیز اوکیه، ولی مشکل از جایی شروع می‌شه که بخوایم لاجیک اصلی پروژه رو تو همین سریالایزرها پیاده سازی کنیم.

🚫 چرا این کار بده؟
بعضی‌ها عادت دارن تو متدهای سریالایزر (مثل to_representation یا validate) لاجیک‌های پیچیده بنویسن، مثلاً محاسبات، فیلتر کردن داده‌ها یا حتی آپدیت دیتابیس. اما این کارا چندتا مشکل بزرگ به وجود میاره

1⃣ نقض اصل Single Responsibility:
سریالایزرها برای تبدیل و اعتبارسنجی داده‌ها طراحی شدن، نه برای مدیریت لاجیک پروژه.
وقتی لاجیک رو اونجا می‌نویسین، کدتون از یه سریالایزر ساده تبدیل میشه به سریالایزر خیلی گنده که بعداً نگهداریش سخت می‌شه.

2⃣ کاهش Readability و Testability:
اگه لاجیک تو سریالایزر باشه، پیدا کردنش تو پروژه سخت‌تره و تست کردنش هم پیچیده می‌شه. مثلاً برای تست یه محاسبه، باید کل سریالایزر رو تست کنین، نه فقط اون لاجیک خاص.

3⃣ مشکلات Scalability:
تو پروژه‌های بزرگ، وقتی لاجیک‌ها تو سریالایزرها پخش بشن، دیگه نمی‌تونین به راحتی تغییرشون بدین یا جابه‌جاشون کنین. یه تغییر کوچیک تو لاجیک ممکنه کل API رو به هم بریزه.

4⃣ وابستگی بیش از حد:
سریالایزرها به مدل‌ها و داده‌ها وابسته‌ ان. اگه لاجیک پروژه رو اونجا بذارین، هر تغییری تو مدل‌ها یا ساختار داده‌ها می‌تونه لاجیک‌تون رو خراب کنه.

5⃣ سخت شدن دیباگ:
وقتی یه باگ پیش میاد، نمی‌دونین مشکل از تبدیل داده‌ست یا از لاجیک پروژه، چون همه‌چیز قاطی شده.

سخن اخر 🗣
پیاده‌سازی لاجیک پروژه تو سریالایزرهای DRF مثل اینه که بخوای با چاقو سوپ بخوری؛ می‌شه، ولی چرا؟! سریالایزرها برای تبدیل و اعتبارسنجی داده‌ها طراحی شدن، نه برای نگه داشتن لاجیک پیچیده. با انتقال لاجیک به مدل‌ها یا سرویس‌ها، کدتون تمیزتر، قابل‌نگهداری‌تر و حرفه‌ای‌تر می‌شه. دفعه بعد که خواستین تو سریالایزر لاجیک بنویسین، یه لحظه وایسید و بگین: اینجا جای این کارا نیست 😊

#️⃣ #backend #drf #django #api


🥷 CHANNEL | GROUP
👍203
همه میدونن چرا این پست انقدر ریکشن خنده داره 🤣


🥷 CHANNEL | GROUP
🤣76
Forwarded from Denver
🛠 چند alias کاربردی برای هر کاربر لینوکس
حتما با alias ها آشنایی دارین، همون لقب دادن به دستوراتمون.
کاربردش چیه؟ میتونیم کلی دستور طولانی یا حتی دستورایی که تایپ کردنشون هر دفعه مثل یه کابوس میمونه رو توی دستور مورد نظر خودمون خلاصه کنیم.
ساده تر بگیم، درواقع با اینکار داریم به شل(zsh, bash, fish) میگیم که دستور مورد نظر a معادل دستور طولانی b هست.


با این aliasها توی فایل ~/.bashrc یا ~/.zshrc می‌تونی کلی زمان تو ترمینال صرفه‌جویی کنی 💻⚡️

# ====== System Management ======
alias update="sudo apt update && sudo apt upgrade -y" # Fast system update
alias clean="sudo apt autoremove && sudo apt autoclean" # Clean cache and unnecessary packages
alias reboot="sudo reboot" # Reboot the system
alias ping="ping -c 5" # Ping with 5 packets

# ====== Navigation Shortcuts ======
alias home='cd ~' # Go to home directory
alias cd..='cd ..' # One directory up
alias ..='cd ..' # One directory up (short)
alias ...='cd ../..' # Two directories up
alias ....='cd ../../..' # Three directories up
alias .....='cd ../../../..' # Four directories up

# ====== File Search ======
alias f="find . -name" # Find file by name in current directory and subdirectories

# ====== Listing (ls) Aliases ======
alias la='ls -Alh' # List all files including hidden
alias ls='ls --color=always' # Enable colored output
alias lx='ls -lXBh' # Sort by extension
alias lk='ls -lSrh' # Sort by size
alias lc='ls -lcrh' # Sort by change time
alias lu='ls -lurh' # Sort by access time
alias lr='ls -lRh' # Recursive listing
alias lt='ls -ltrh' # Sort by date
alias lw='ls -xAh' # Wide listing format
alias ll='ls -Flsh' # Long listing format with type indicators
alias labc='ls -lap' # Alphabetical listing with hidden files
alias lf="ls -l | egrep -v '^d'" # List only files
alias ldir="ls -l | egrep '^d'" # List only directories

🔗برای راحتی کار میتونید فایل آماده ی alias هارو از لینک زیر دانلود کنید:
فایل آماده ی alias ها

📌 نکته: بعد از اضافه کردن aliasها، فراموش نکن که ترمینالت رو یه بار ببندی و باز کنی یا دستور زیر رو وارد کنی:
source ~/.bashrc  # or ~/.zshrc


#️⃣ #linux #terminal #tools


🐧 CHANNEL | GROUP
13
آیا پایتون همیشه کنده؟ 🐢

چیزی که همیشه از زبون همه ی برنامه نویسا می‌شنویم (مخصوصا جامعه محترم C#) اینه که پایتون خیلی کنده (نسبت به زبان های دیگه هرچند این مقایسه اشتباهه بعضی جاها)
خب اره، درسته پایتون کنده (البته در حالت pure)
توی این پست میخوام بگم که چرا کنده و چجوری میشه سریعش کرد؟

چرا پایتون کنده ؟ 🤓

همونجور که میدونید پایتون به صورت پیش‌فرض با CPython اجرا می‌شه، که یه مفسر (interpreter) برای پایتونه و با زبان C نوشته شده. CPython کد پایتون رو به بایت‌کد (bytecode) تبدیل می‌کنه و بعد اون رو تو یه ماشین مجازی (VM) اجرا می‌کنه. این فرایند باعث می‌شه پایتون نسبت به زبان‌های کامپایل‌شده مثل C یا Rust کندتر باشه، چون
تفسیر خط‌به‌خط انجام میده و به جای کامپایل مستقیم به کد ماشین، پایتون تو زمان اجرا تفسیر می‌شه.
GIL (Global Interpreter Lock) تو CPython، یه قفل سراسری هست که جلوی اجرای چند نخ (thread) همزمان رو می‌گیره و برای کارهای multithreading مشکل‌ساز می‌شه.
داینامیک تایپ بودن پایتون تایپ‌ها رو تو زمان اجرا چک می‌کنه، که یه کم سرعت رو پایین میاره.

ولی خبر خوب اینه که پایتون راه ها و ابزارهایی داره که می‌تونن این کندی رو برطرف کنن و پرفورمنس رو حسابی بالا ببرن

راه ها و ابزارهایی برای افزایش سرعت 📚

1️⃣ PyPy 🌟
‏Pypy یه مفسر جایگزین برای پایتونه که از JIT (Just-In-Time Compilation) استفاده می‌کنه.
و کارکردش اینجوریه که کد پایتون رو به جای تفسیر ساده، تو زمان اجرا به کد ماشین کامپایل می‌کنه. این یعنی برای حلقه‌ها و عملیات تکراری خیلی سریع‌تره.
مزیتشم اینه تو بعضی موارد تا ۷ برابر سریع‌تر از CPython عمل می‌کنه
و باید توجه داشت باشید برای کدهایی که با C extensionها (مثل NumPy) کار می‌کنن، کامل سازگار نیست.

2️⃣ Cython
‏Cython یه ابزار که کد پایتون رو به C تبدیل می‌کنه و بعد کامپایلش می‌کنه.
اینجوری کار میکنه که می‌تونی تایپ‌های استاتیک (مثل int یا float) به متغیرها‏ اضافه کنی تا سرعتش بیشتر بشه. بعد Cython این کد رو به C تبدیل می‌کنه و یه فایل باینری سریع تحویلت می‌ده.
و تا چندین برابر سریع‌تر از CPython می‌شه، به‌خصوص برای محاسبات سنگین.

3️⃣ Numba 🔥
‏Numba یه کامپایلر JIT برای پایتونه که با دکوریتور @jit کار می‌کنه.
کارکردش اینجوریه که کد پایتون رو تو زمان اجرا به کد ماشین تبدیل می‌کنه، بدون نیاز به تغییر زیاد تو کدنویسی.
برای حلقه‌ها و محاسبات عددی (مثل کار با آرایه‌ها) تا ۱۰۰ برابر سریع‌تر می‌شه

4️⃣ CPython با C Extensions 🛠️
می‌تونی بخش‌های کند پروژت یا جاهایی که به سرعت بالا نیاز داری رو با C بنویسی و به CPython وصل کنی.
اینجوریه که کد C رو به صورت ماژول می‌سازی و تو پایتون لودش می‌کنی.
و سرعت C رو با سادگی پایتون ترکیب می‌کنی. کتابخونه‌هایی مثل NumPy و Pandas از این روش استفاده می‌کنن.

و در اخر پایتون همیشه کند نیست 🙃

حقیقت اینه که پایتون به تنهایی برای خیلی از کارها به اندازه کافی سریعه، به‌خصوص تو پروژه‌هایی که I/O (مثل شبکه یا دیتابیس) گلوگاه اصلیه، نه CPU. ولی وقتی پای محاسبات سنگین وسط میاد، ابزارهایی مثل PyPy، Cython و Numba می‌تونن پرفورمنس رو چند برابر کنن. مثلاً:
یه حلقه ساده با Numba می‌تونه از ۵ ثانیه به ۰.۰۵ ثانیه برسه
‏PyPy تو برنامه‌های واقعی تا ۷ برابر سرعت رو بالا برده. 🐆

#️⃣ #python


🥷 CHANNEL | GROUP
👌93👍2🔥2
شنبه دو حالت داره
یا به فنا میریم یا به فنا میریم
👍18🔥3🤣2
چگونه یه رزومه حرفه‌ای بنویسیم؟ 📝

یکی از مشکلاتی که توی اکثر بچه هایی که باهاشون سروکار دار میبینم، عدم داشتن مهارت رزومه نویسیه.
و بدون اینکه بدونن همین رزومه در ظاهر ساده آینده شغلیشون و شانس استخدامشون رو تأیین میکنه رزومه مینویسن.
این پست برای افرادیه که بنظرشون منابع مناسبی برای رزومه نویسی مطالعه نداشتن و ابزار مناسبیم براش پیدا نکردن. (اگه داشتید بازم این پست مناسبتونه)

🧠 مقدمه
رزومه فقط یه کاغذ A4 نیست؛ یه ابزاره که باید تو چند ثانیه کارفرما رو متقاعد کنه شما همون آدمی هستین که دنبالش می‌گردن. مهم نیست تازه‌کار باشین یا حرفه‌ای، یه رزومه خوب باید واضح، مرتب و هدفمند باشه و بتونه کامل پتانسیل شمارو برای اون نشون بده. حالا بیاین چندتا منبع درجه‌یک برای؟یادگیری اصول رزومه‌نویسی و ساخت رزومه ببینیم.

📚 منابع معتبر برای یادگیری رزومه‌نویسی

1⃣The Muse - How to Write a Resume
یه راهنمای جامع با نکات عملی برای نوشتن رزومه، از انتخاب قالب تا پر کردن بخش‌های مختلف.
لینک

2⃣Harvard Career Services- Resume Guide
یه PDF از دانشگاه هاروارد با اصول رزومه‌نویسی برای موقعیت‌های آکادمیک و غیرآکادمیک.
لینک

3⃣LinkedIn Learning - Writing a Resume
یه دوره ویدیویی که قدم‌به‌قدم رزومه‌نویسی رو آموزش می‌ده.
لینک

🛠 ابزار برای ساخت رزومه

1⃣Canva Resume Templates
مجموعه‌ای از قالب‌های رزومه حرفه‌ای و زیبا با امکان ویرایش آنلاین.
لینک

2⃣ ‌‏Zety Resume Builder
یه ابزار آنلاین که با راهنمایی قدم‌به‌قدم رزومه می‌سازه.
لینک

3⃣Novorésumé
یه پلتفرم برای ساخت رزومه با قالب‌های مدرن و بهینه برای ATS (سیستم‌های ردیابی متقاضی).
رزومه‌تون رو برای عبور از فیلترهای اتوماتیک کارفرماها آماده می‌کنه.
لینک

جمع‌بندی

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

#️⃣ #tip #resume #cv


🥷 CHANNEL | GROUP
👍11❤‍🔥22
خب خب آپدیت جدید جنگو اینجاست، ببینیم چه تغییراتی داشته🔥🛠
چند روز پیش (۲ آوریل) آپدیت جدید جنگو با ورژن ۵.۲ منتشر شد. این نسخه LTS هست و تا آوریل ۲۰۲۸ پشتیبانی میشه. توی این نسخه تغییرات بیشتر مربوط به زیرساخت هایی مثل دیتابیس و shell جنگو بودن. بریم بررسیشون کنیم.

1️⃣ ایمپورت خودکار مدل ها توی shell
از این نسخه به بعد وقتی وارد shell جنگو میشین مدل هاتون به صورت خودکار ایمپورت میشن. این ویژگی بهتون کمک میکنه که زمان کمتری برای ایمپورت کردن بزارین و باعث صرفه جویی در زمان میشه.

2️⃣ پشتیبانی از کلید اصلی مرکب(Composite Primary Key)

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

3️⃣ ساده تر شدن شخصی سازی BoundField
توی این نسخه میتونید کلاس BoundField رو به راحتی توی سطح پروژه یا فرم شخصی سازی کنید. با ایجاد یک کلاس که از BoundField ارث بری میکنه و اعمال تغییرات مورد نظر میتونید اون رو به فیلد های فرم هاتون اختصاص بدین.
‏BoundField همون چیزیه که وقتی توی قالب می‌نویسید form.name، پشت صحنه وظیفه داره اون فیلد رو به HTML تبدیل کنه، مقدارش رو بذاره، ارورهاش رو نشون بده و...
یجورایی رابط بین فرم و فیلد واقعی‌ توی قالبه.


4️⃣ فیلتر های Facet توی پنل ادمین
توی پنل ادمین جنگو، با فعالسازی ویژگی ModelAdmin.show_facets، میتونید تعداد آیتم های توی هر فیلتر رو ببینید. این قابلیت باعث میشه اطلاعات پنل ادمین رو راحت تر مدیریت کنید.

5️⃣ فیلد های تولید شده(Generated Fields)

با معرفی GeneratedFields، میتونید فیلد هایی تعریف کنید که مقدارشون بر اساس مقدار سایر فیلد های مدل محاسبه و ثبت میشه. این ویژگی بهتون این امکان رو میده که ستون های محاسبه شده توی دیتابیس قرار بدین.

6️⃣ مقادیر پیش فرض در سطح دیتابیس

با استفاده از پارامتر db_default توی فیلد های مدل، مقادیر پیش فرض مستقیما توسط دیتابیس اعمال میشن. این ویژگی باعث بهبود عملکرد و سازگاری بیشتر با دیتابیس های مختلف میشه.

⏺️ با استفاده از لینک زیر میتونید اطلاعات بیشتری درمورد این آپدیت کسب کنید⚡️

Django 5.2 release notes

#django #backend #python


🥷🏻 CHANNEL | GROUP
16👍3
خب خب خب، کامند inspectdb توی جنگو⚙️
احتمالا به این فکر کردین که چطوری میشه از جدول های یه دیتابیس آماده توی جنگو استفاده کرد. راه حلش این ابزاره.

‏inspectdb چیه
؟
با استفاده از inspectdb، جنگو میتونه ساختار جدول های دیتابیس رو بررسی کنه و یه فایل مدل جنگو(مثل model.py) تولید کنه و توی خروجی نمایش بده. این یعنی دیگه نیاز نیست برای دیتبایس قدیمیتون دستی مدل بنویسید، جنگو اینکارو هم خودش انجام میده.
python manage.py inspectdb > models.py

شما حتی میتونید فقط یه جدول رو بررسی و تبدیل کنید:
python manage.py inspectdb my_table > models.py


این ابزار میتونه توی این مواقع کمکتون کنه:
1️⃣ وقتی روی یه دیتابیس قدیمی یا پروژه ی legacy کار میکنید.
2️⃣ موقع مهاجرت از یه سیستم دیگه به جنگو.
3️⃣ وقتی میخوان بدون نوشتن کلی کد دستی با یه دیتابیس خارجی کار کنید.

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


⏺️ برای اطلاعات بیشتر میتونید به داکیومنت جنگو مراجعه کنید:
inspectdb در جنگو

#⃣ #django #python #db


🥷🏻 CHANNEL | GROUP
👍15
سیستم مدیریت وابستگی در FastAPI
یکی از بهترین ویژگی های FastAPI، سیستم مدیریت وابستگی(Dependnecy Injection) اون هست، این سیستم باعث میشه کد ما تمیز تر، تست پذیر تر و قابل توسعه تر بشه.
بهتره برای درک بهتر این پست درمورد Dependency Injectionرو مطالعه کنید تا با پایه و اساس این مبحث آشنا بشین.

‏Depends چیه؟
این کلاس توی FastAPI، برای مدیریت وابستگی ها استفاده میشه. به زبان ساده Depends یه راهه که بتونیم بک تابع یا آبجکت رو به صورت خودکار به فانکشن های دیگه تزریق کنیم بدون اینکه دستی اونارو صدا بزنیم یا بخونیم.
با یه مثال ساده شروع میکنیم:
from fastapi import FastAPI, Depends

app = FastAPI()

def get_db():
db = "Database Connection"
try:
yield db
finally:
print("Closing DB connection")

@app.get("/items/")
def read_items(db = Depends(get_db)):
return {"db_connection": db}

اینجا read_items خودش مستقیم سشن دیتابیس رو نمیسازه، فقط میگه: من به یه سشن دیتابیس نیاز دارم.
‏FastAPI به صورت خودکار get_db رو صدا میزنه و نتیجه رو به db میده.

چرا این سیستم خوبه؟
وابستگی ها مدیریت شده و قابل کنترل میشن
کد تست پذیر تر میشه
ساختار پروژه ماژولار میشه
لاجیک لایه های مختلف جدا میشه و تغییرات ساده تر میشن

اگه ازش استفاده نکنیم چی؟
خب با استفاده نکردن از این ویژگی یه کمک بزرگ رو از دست میدین. به طور مثال اگه وابستگی ها تو در تو باشن شما میتونید فقط با همین ویژگی کلی به تمیزی کدتون کمک کنید.
from fastapi import Header, HTTPException, APIRouter, Depends


router = APIRouter()

def get_token(token: str = Header(...)):
return token

def get_current_user(token: str = Depends(get_token)):
user = {"username": "abolfazl", "role": "admin"}
return user

def require_admin(user: dict = Depends(get_current_user)):
if user["role"] != "admin":
raise HTTPException(status_code=403, detail="Not authorized")
return user

def list_users_service():
return [{"username": "a"}, {"username": "b"}]

@router.get("/users")
def list_users(admin_user: dict = Depends(require_admin)):
users = list_users_service()
return users

توی مثال بالا میتونید چندین لایه از وابستگی رو ببینید که به خوبی با Depends مدیریت شدن. حالا اگه این سیستم وجود نداشت چی؟
def list_users():
token = get_token()
user = get_current_user(token)
admin_user = require_admin(user)
...

اگه اون سیستم وجود نداشت باید قبل از هرکاری دونه دونه سرویس ها و لایه های پایین تر رو صدا میزدین و نتیجه اونهارو به همدیگه پاس میدادین. درواقع Depends میاد هر وابستگی ای که تعیین کرده باشین رو قبل از ورود به بدنه ی فانکشن اجرا میکنه و نتیجه ی وابستگی رو به آرگومان فانکشن پاس میده. در نتیجه شما در اولین خط بدنه ی فانکشن همه ی نتایجی که میخواین رو از طریق آرگومان ها در اختیار دارین.

پشت صحنه چه اتفاقی میوفته؟

‏FastAPI از بالا شروع کرد به نگاه کردن:
دید require_admin به get_current_user نیاز داره، بعد دید get_current_user هم به get_token نیاز داره، پس اول get_token اجرا شد، بعد get_current_user بعد هم require_admin. هربار خروجی یه فانکشن، ورودی فانکشن بعدی شد. درنهایت اگه مشکلی نباشه میرسیم به endpoint.

از کجا فهمید چی رو به کجا بفرسته؟

خب باید بگم که FastAPI به شدت به تایپ هینت ها وابسته است و خیلی ازشون استفاده میکنه. همین Depends هم با استفاده از تایپ هینت ها جای مقادیر رو درک میکنه. یه فانکشن توی پایین ترین لایه یه آرگومان با تایپ Header داره؟ خب Depends اون آرگومان رو توی درخواست دریافت میکنه به اون فانکشن میرسونه.

کجا ازش استفاده کنیم؟
هر وابستگی ای که نیاز داره یه پارامتری رو مستقیما از درخواست بگیره و روش پردازش انجام بده، و به نحوی قبل از فانکشن endpoint اجرا بشه و نتیجه ی آماده داشته باشه(درست همونطور که گفتم، قبل از بدنه ی اصلی فانکشن) باید با Depends استفاده بشه. مثلا گرفتن توکن از هدر یا چک کردن دسترسی ها، اتصال به دیتابیس

اما اگه فانکشنی که میخواید استفاده کنید ارتباط مستقیم با بدنه و اطلاعات ورودی از درخواست نداره و فقط برای انجام کاری یا پردازش داخلی باشه نیازی به Depends نداره. مثل ثبت نام کاربر که ممکنه دیتای خام و پردازش نشده ای از درخواست نیاز نداشته باشه و صرفا اطلاعات رو توی دیتابیس ذخیره میکنه

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

#️⃣ #fastapi #python #backend


🥷🏻 CHANNEL | GROUP
👍14
🟡 خب خب خب، PEP8: قوانین طلایی برای کدنویسی پایتون
وقتی به برنامه‌نویسی پایتون علاقه‌مند می‌شید، یکی از اولین چیزهایی که باید یاد بگیرید PEP8 هست. این یه استاندارد رسمی برای کدنویسی به زبان پایتونه که توسط Python Software Foundation منتشر شده و هدفش اینه که کدهای پایتون هماهنگ، خوانا و استاندارد باشن. با این استاندارد کد های همه برنامه های پایتون توی مسائل پایه ای استایل کد مثل هم میشه و خوندن و درک کد های مختلف هم ساده تر میشه. توی این پست می‌خوایم توضیح بدیم که PEP8 چیه، چرا مهمه و چندتا از مهم‌ترین قواعدش رو بررسی کنیم.

PEP8 چی هست؟
‏PEP8 یه استاندارد شامل یه سری دستورالعمل ها و قوانین برای نوشتن کد منظم و تمیز پایتونه. این استاندارد برای کمک به برنامه نویس ها تنظیم شده تا کدی بنویسن که هم برای خودشون هم برای دیگران قابل فهم باشه. دستورااعمل های این استاندارد شامل اصولی درمورد قواعد نام گذاری، استایل کد، تو رفتگی ها و ... میشه.

چرا باید از PEP8 استفاده کنیم؟
خوانایی بیشتر: کد هایی که طبق استاندارد های خاصی نوشته میشن، برای دیگران راحت تر قابل فهم هستن.
نگهداری ساده تر: کد استادارد به راحتی قابل تغییر و گسترشه.
هماهنگی بین تیم ها: وقتی همه از یک استاندارد پیروی کنن، حتی اگه جند نفر هم روی یک پروژه کار کنن کار کردن با کد ها خیلی راحت تر میشه

اصول کلیدی PEP8
1️⃣ قواعد نام گذاری(Naming Conventions)
نام گذاری درست متغیر ها، توابع، کلاس ها و ماژول ها باعث میشه کد شما خوانا و قابل فهم باشه.

نام متغیر ها و توابع: از snake_case استفاده کنید.
my_variable = 10
def my_function():
pass

نام کلاس ها: باید از CapCase استفاده کنید
class UserProfile:
pass

نام ماژول ها: میشه از lowercase استفاده کنید و برای جدا کردن کلمات از خط تیره (-) نکنید
import mymodule
import user_routers


2️⃣ چیدمان کد(Code Layout)
چیدمان منظم کد برای راحتی خوندن و نگهداری کد ها ضروریه
طول خط ها:‌ طول خط ها توی پایتون نباید بیشتر از ۷۹ کاراکتر باشه. این باعث میشه که کد های توی ابزارهای مختلف(مثل کامند git diff) و ترمینال راحت تر دیده بشن.
فاصله های خالی: بعد از کاما و آرگومان ها یک فاصله بگذارین:
print("This code is too long and does not follow the standard. It cannot be read. properly in some tools like 'git diff'. This line should be broken into. multiple lines to follow the standard. The maximum length for a line is 79 characters.")

def my_function(x, y):
return x + y


3️⃣ تو رفتگی(Indentation)
تو رفتگی ها برای نمایش ساختار کد و مشخص کردن بلوک های کد استفاده میشن.
از ۴ فضای خالی برای هر سطح تو رفتگی استفاده کنید.
class MyMath:
def my_function(self, x):
if x > 0:
print("Positive")
else:
print("Negative")


5️⃣ فضای خالی در عبارات و دستورات (Whitespaces in Expressions and Statements)

فضای خالی در عبارات و دستورات به خوانایی کد کمک می‌کنه:
قبل و بعد از اپراتورهای ریاضی فاصله بگذارید:
x = 5 + 3

در داخل پرانتزها فاصله نگذارید:
my_function(1, 2, 3)

فاصله هارو فقط قبل از هر کاما بذارید:
a, b, c = 1, 2, 3


چجوری همیشه این قواعد رو رعایت کنیم؟
خب یه راه آسونش میتونه استفاده از ابزار هایی مثل pylint و flake8 باشه. اما یه راه راحت تر، اگه از IDE هایی مثل Pycharm استفاده میکنید خودشون وقتی که کد غیر استاندارد بنویسید بهتون میگن و بییشتر مواقع خودشون کد رو درست میکنن. اگه از VSCode یا هر ادیتور دیگه ای استفاده میکنید میتونید افزونه ی مربوط به این استاندارد رو روش نصب و استفاده کنید.

جمع بندی✍️
‏PEP8 به شما کمک میکنه که کد پایتون تمیز، خوانا و استاندارد بنویسید. رعایت قواعدی مثل نام گذاری درست، استفاده مناسب از فاصله ها و تو رفتگی ها باعث میشه کد شما به راحتی قابل نگهداری و درک باشه.

#️⃣ #programming #python


🥷🏻 CHANNEL | GROUP
👍182
خب خب خب،‌ معرفی Pylint🏛️
اگه با پایتون کار میکنین و میخواین کدتون تمیز باشه، حتما باید با ابزارهایی مثل pylint اشنایی داشته باشین. این ابزار ها میان یک سری قوانین و قواعد ثابت رو براتون تعریف میکنن و بررسی میکنن که توی کدتون این قواعد رعایت شده یا نه.

‏Pylint چیه؟🤔
‏pylint به ابزار linter برای زبان پایتونه که کد رو بررسی میکنه، اشتباهات رایج رو گزارش میده، با استاندارد های PEP8 ارزیابیش میکنه و در نهایت یه امتیاز (از ۰ تا ۱۰) به کدی که نوشتین میده. این ابزار باعث میشه کد هاتون استاندارد و قابل توسعه باشن و میتونه توی رعایت کردن اصول PEP8 بهتون کمک کنه.

معجزه توی هماهنگی تیمی
وقتی توی یه تیم فعالیت میکنین و مشغول به کار هستین، قطعا همه یه استایل خاصی برای کدنویسیشون دارن. اینجاست که pylint و فایل کانفیگش میتونن هماهنگی رو به تیمتون بیارن و باعث یک پارچگی کد میشن و در نتیجه باعث میشه خوندن کد ساده تر باشه.

نصب و استفاده🚀
میتونید با دستور زیر این ابزار رو نصب کنید.
pip install pylint

اجرا روی یه فایل
pylint main.py

یا روی یه پروژه ی کامل
pylint myproject/

خب حتما بعد اجرا متوجه شدین که دیگه خیلی داره سخت میگیره یا اینکه میخواین تنظیمات و استایل خودتون رو بهش بدین، میتونین با استفاده از فلگ های دستور pylint این کار رو انجام بدین. به طور مثال خاموش کردن بعضی اخطار ها:
pylint myfile.py --disable=missing-docstring,invalid-name,too-many-arguments --max-line-length=100


کانفیگ Pylint🛠️
خب تایپ و استفاده از دستور قبلی با یه سری شخصی سازی های دیگه خیلی سخت میشه و تا مرز غیرقابل استفاده بودن میرسه، اینجاست که میتونین از فایل کانفیگ استفاده کنین. استفاده از فایل کانفیگ خیلی مرتب تر و تیم پسند تره.
فایل کانفیگ رو با این دستور ایجاد کنین:
pylint --generate-rcfile > .pylintrc

و بعد میتونید طبق استایل کدنویسی خودتون یا استایل مدنظر تیمتون کانفیگ هارو تغییر بدین:
[MESSAGES CONTROL] # disable selected warnings
disable=
missing-docstring,
# no docstring warning
invalid-name,
# allow any names
too-few-public-methods,
# allow few methods
too-many-arguments
# allow many args

[FORMAT] # formatting rules
max-line-length=100
# max line length

میتونین با مراجعه به صفحه کانفیگ ها از داکیومنت رسمی pylint کانفیگ های بیشتری رو ببینین.

جمع بندی✍️
با استفاده از این ابزار میتونین هماهنگی بی نظیری توی کدهاتون ایجاد کنید و اگه توی تیم کار میکنین باعث میشه کل تیم یک سری قواعد و اصول یکپارچه رو رعایت کنن و کد کلی ساختار مشخصی داشته باشه.🏗️ میتونین Pylint رو به IDE ای که استفاده میکنین اضافه کنین تا استفاده ازش ساده تر بشه.

#️⃣ #programming #python


🥷🏻 CHANNEL | GROUP
👍131
خب خب خب، تفاوت Entrypoint و CMD توی داکر🐳
اگه با Dockerfile یا docker compose کار کرده باشین، احتمالا دوتا دستور CMD و Entrypoint برخورد کردین ولی تاحالا به تفاوتشون فکر کردین؟ اینکه هرکدوم چه کاری انجام میدن و کجا کاربرد دارن؟

CMD
برای مشخص کردن دستور پیشفرضی استفاده میشه که اگه هنگام اجرای کانتینر هیچ آرگومانی ندیم اجرا بشه. CMD باعث میشه که با خیلی راحت بتونین فقط با docker run image_name کاری که میخواین رو انجام بدین(فقط وقتی که Entrypoint وجود نداشته باشه). ولی اگه توی docker run آرگومان بدین اون آرگومان های جدید جای CMD توی Dockerfile رو میگیرن.
CMD ["python3", "app.py"]

توی این حالت، دستور نهایی ای که با docker run اجرا میشه این شکلیه:
python3 app.py

ولی اگه بنویسین docker run image_name echo hello دستور نهایی این شکلی میشه:
echo hello


Entrypoint
برای تعیین دستور اصلی کانتیر استفاده میشه. یه جورایی میشه گفت دستور غیرقابل تغییر کانتینر رو میشه باهاش تعیین کرد. حتی اگه موقع اجرای کانتینر بیایم از آرگومان ها استفاده کنیم اون آرگومان ها به عنوان ورودی به Entrypoint پاس داده میشن. در نتیجه Entrypoint رفتار اصلی کانتینر رو تعیین میکنه.
ENTRYPOINT ["python3", "app.py"]

حالا میتونین با docker run اجراش کنید و البته که میتونین با پاس دادن آرگومان به docker run اونهارو به Entrypoint اضافه کنید.
دستور docker run image_name --option باعث میشه که دستور نهایی ای که برای اجرا کانتینر استفاده بشه این شکلی بشه:
python3 app.py --option

شما حتی میتونید همزمان ازشون استفاده کنید و با CMD آرگومان های مختلفی به دستور اصلیتون بفرستین. اینجوری دستتون برای اجرای کانتینر خیلی باز میشه.
ENTRYPOINT ["python3", "app.py"]
CMD ["--option"]

و حالا اگه بخواین آرگومان های دستور رو تغییر بدین فقط کافیه اونهارو توی docker run به کانتینر پاس بدین.

جمع بندی✍️
از CMD برای تنظیم پیش فرض ها و حالت های مختلف استفاده کنید.
از Entrypoint برای تعیین رفتار اصلی و ثابت کانتینر استفاده کنید.
و البته که میتونین با ترکیبشون و استفاده ی درست از هردوتاشون کارای خفنی انجام بدین.

#️⃣ #programming #devops


🥷🏻 CHANNEL | GROUP
🔥13👍41
بندر عباس تسلیت 🖤
💔23❤‍🔥2
خب خب خب، Volume توی داکر🐳
‏Volume ها توی داکر یه راه استاندارد برای ذخیره ی داده ها به شکل پایدار(persistent data) هستن. یعنی وقتی که یه کانتینر خاموش یا پاک میشه، داده هایی که داخل Volume ذخیره شده باشن از بین نمیرن و دوباره قابل استفاده هستن. که این یعنی Volume ها جدا از لایه ی فایل سیستم کانتینر عمل میکنن و توی /var/lib/docker/volumes/ نگهداری میشن. کاربردشون معمولا برای دیتابیس ها، فایل های کاربر، یا هر داده ای که نباید با حذف کانتینر از دست بره هست.

چطور ازشون استفاده کنیم؟🤔
میتونید با استفاده از دستور زیر Volumeها رو مدیریت کنید.
docker volume ls            
# List all existing volumes
docker volume create NAME
# Create a new volume
docker volume inspect NAME
# View detailed information about a volume
docker volume rm NAME
# Remove a specific volume
docker volume prune
# Remove all unused volumes

نکته⚠️: اگه یه Volume هنوز به یه کانتینر متصل باشه، نمیشه مستقیم با rm حذفش کرد.

بعد از ساختن Volume های مورد نظرتون میتونید به این شکل وصلشون کنید به کانتینر هاتون:
docker run -v my_volume:/app/data my_image

یا توی فایل compose:
services:
app:
image: my_image
container_name: my_container
volumes:
- my_volume:/app/data

volumes:
my_volume:

خب همونطور که دیدین، اسم Volume رو سمت چپ دو نقطه و مسیری که میخوایم توی کانتینر بهش وصل بشیم رو سمت راست میذاریم.
با اینکار هر تغییری که توی مسیر /app/data/ توی فایل سیستم کانتینر رخ بده توی Volume هم ذخیره میشه و حتی با خاموش شدن کانتینر هم در دسترس و قابل استفاده هست.

یه نکته ی مهم⚠️
احتمالا توی بعضی جاها دیده باشین که از سینتکس زیر استفاده میشه:
services:
app:
image: my_image
container_name: my_container
volumes:
- .:/app/data

توی این روش سمت راست دونقطه به جای اسم Volume، مسیر فعلی توی سیستم قرار داده شده. توی این روش اصلا از Volume استفاده نمیشه و اسمش Bind Mount هست. درواقع اگه سمت راست دو نقطه به جای اسم Volume یه مسیر توی فایل سیستمتون رو بنویسید، Bind Mount اتفاق میوفته.
اینجا به جای اینکه یه Volume رو به فایل سیستم کانتینر وصل کرده باشیم، پوشه فعلی از فایل سیستم اصلی خودمون رو به فایل سیستم کانتینر وصل کردیم. این کار باعث بروز یه سری مشکلات میشه:

1️⃣ اگه اطلاعات توی کانتینر از دست برن توی فایل سیستم اصلی هم از دست میرن
یعنی اگه شما پروژه رو توی کانتینر حذف کنید، از روی سیستم خودتون هم حذف میشه. درواقع هر تغییری که توی کانتینر ایجاد کنید توی فایل سیستم اصلیتون هم ایجاد میشه.
2️⃣ عدم تطابق نسخه ی فایل ها
وقتی چند تا کانتینر همزمان یه مسیر رو Bind کردن، ممکنه فایل ها تصادفی توسط یکی از کانتینر ها تغییر کنه و هماهنگی بین فایل های پروژه به هم بریزه و باعث خرابی بشه.
3️⃣ ریسک های امنیتی
اگه داخل کانتینر دسترسی root باشه و به پوشه های حساسی Bind Mount شده باشه، کانتینر میتونه مستقیما به فایل های سیستمی آسیب بزنه.
4️⃣ انتقال ناخواسته ی فایل های حساس
اگه اشتباهی کل home/ یا / رو mount کنید داخل کانتینر، ممکنه فایل های حساس(مثل SSH Keyها، توکن ها، رمزها و...) هم توی محیط کانتینر قابل دسترس باشه.

جمع بندی✍️
‏Volume ها بشدت کاربردی هستن و میتونن برنامه نویس و کد رو نجات بدن. فقط باید دقت کنید که مسیر درستی رو به Volume بدین.
همچنین Bind Mount هم میتونه توی فاز توسعه کاربردی باشه. چون خیلی راحت میشه تغییرات توی کد رو روی کانتینر مشاهده و بررسی کرد ولی برای محیط پروداکشن خیلی خطرناک هستن و میتونن کلا محصول شمارو خراب کنن.

#️⃣ #programming #devops


🥷🏻 CHANNEL | GROUP
👍13
خب خب خب، ‏Middleware های FastAPI🚀
خب middleware یه کد واسط بین دریافت درخواست و پاسخ دادن توی یه اپلیکیشن وبه. یعنی هر ریکوئستی که به سرور میرسه، قبل از رسیدن به route اصلی، از middleware رد میشه و همچنین هر درخواستی هم قبل از رسیدن به کلاینت از middleware عبور میکنه تا تغییر داده بشه، لاگ بشه و ...

چطور توی FastAPI ازشون استفاده کنیم؟🤔
‌‏Middleware ها توی FastAPI با دکوریتور app.middleware تعریف میشن و معمولا ساختارشون این شکلیه:
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def my_middleware(request: Request, call_next):
# Before reaching route
print("Before route")

# Executing View
response = await call_next(request)

# After view did its thing
print("After route")

return response

همونطور که توی مثال بالا دیدید، هر کدی که قبل از اجرای call_next باشه مربوط به درخواست، و هر کدی که بعد از اجرای call_next نوشته بشه مربوط به پاسخ میشه.
توی این مثال قبل از رسیدن درخواست به route اصلی، عبارت 'Before route' چاپ میشه و بعد اینکه route پردازشش با درخواست تموم شد و پاسخ آماده ی برگشت به کلاینت بود، عبارت 'After route' چاپ میشه و بعد از اون پاسخ به کلاینت میرسه.


چندتا مثال ساده برای درک کاربرداش🛠️
از چندتا مثال ساده میتونیم استفاده کنیم
لاگ گیری ساده درخواست ها:
@app.middleware("http")
async def log_requests(request: Request, call_next):
print(f"New request: {request.iss.onethod} {request.url}")
response = await call_next(request)
return response


اضافه کردن Header به پاسخ:
@app.middleware("http")
async def add_custom_header(request: Request, call_next):
response = await call_next(request)
response.headers["X-App-Version"] = "1.0.0"
return response


سنجش مدت زمان اجرای درخواست:
import time

@app.middleware("http")
async def measure_time(request: Request, call_next):
start = time.time()
response = await call_next(request)
duration = time.time() - start
response.headers["X-Process-Time"] = str(duration)
return response


چندتا نکته📎
1️⃣کلاس Middleware که از FastAPI ایمپورت شده درواقع همون کلاس Middleware توی Starlette هست و برای راحتی میتونیم از FastAPI ایمپورتش کنیم.

2️⃣اگه dependency ای داشته باشیم که با yield تعریف شدن، بخش خرجی اون ها بعد از اجرای middleware اجرا میشه.

3️⃣اگه BackgrounTask ای وجود داشته باشه، اون ها بعد از اجرای همه ی middleware ها اجرا میشن.

جمع بندی✍️
با استفاده از middleware ها میتونید درخواست و پاسخ هارو تمیز کنید، یا قبل از پردازش شدنشون توسط route کارایی که میخواین رو انجام بدین. درواقع با تعریف middleware یه تابع بین client و route اصلی قرار میدیم.

#️⃣ #fastapi #python #backend


🥷🏻 CHANNEL | GROUP
14
Forwarded from CBE ARCHIVE
🤍 خبر داریم چه خبری !

بروبچ سلام 👋

افتتاحیه کامیونیتی CS12 در 05-05-2025 یعنی 15 اردیبهشت ماه سال 1404 از ساعت 14:00 تا 17:00 در لوکیشن "شهر زیبا" در شهر تهران برگزار میشه.


🔴لینک ثبت نام فردا در ساعت 12:00 ظهر براتون گذاشته میشه.

🟣در افتتاحیه ما میزبان 112 نفر از شما عزیزان خواهیم بود.

🟡حضور در این رویداد رایگان خواهد بود.

💦 cbe_archive

💦 ccismywife
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92🔥1
خب خب خب، تسک های CPU Bound🔧
احتمالا CPU Bound به گوشتون خورده، همون تسک هایی که بار پردازشی سنگینی دارن. یعنی دیگه منتظر عملیات I/O(خوندن از فایل یا دیتابیس، API خارجی و...) نیستن و عملا انجام شدنشون توسط CPU طول میکشه.

‏CPU Bound
🧮
خب وقتی که به صورت عادی برناممون رو توسعه میدیم، برنامه ی ما فقط توی یک Process و یک هسته ی CPU اجرا میشه. اگه برنامه کار سنگینی مثل پردازش تصویر، محاسبات ریاضی فوق سنگین، الگوریتم های رمزنگاری و فشرده سازی و... داشته باشه، نتیجه اجرا شدنش توی یک Process چیزی بجز کندی و فشار روی CPU نیست. برای مثال شما یه CPU با ۸ هسته دارید ولی برنامه ای که نوشتید فقط روی یک هسته اجرا میشه.
توی این موقعیت میتونیم از Multi Processing استفاده کنیم.

‏Multi Processing یعنی چی؟
🧐
میتونیم با استفاده از Multi Processing برنامه ای که نوشتیم رو توی چند Process و روی چند هسته اجرا کنیم. اینجوری از تمام توان CPU استفاده میشه و در نتیجه هم برنامه ما سریع تر میشه و هم فشار روی هسته های CPU تقسیم میشه.

چرا Multi Threading مناسب نیست؟
💈
توی پایتون برای تسک های CPU ‌‌‌Bound نمیتونیم از Multi Threading استفاده کنیم. چون پایتون یه چیزی به اسم GIL داره که باعث میشه فقط یک Thread بتونه در لحظه اجرا بشه.
یعنی اگه برای تسک های CPU Bound ازش استفاده کنیم در عمل فقط یک Thread داره واقعا اجرا میشه.

استفاده از Multi Processing
🛠
با استفاده از ماژول multiprocessing میتونیم از محدودیت GIL عبور کنیم و چند process داشته باشیم.
یه مثال ساده:
from multiprocessing import Process

def cpu_bound_task():
# مثلاً محاسبه‌ی یک عدد بزرگ
total = 0
for i in range(10**7):
total += i
print(total)

if __name__ == '__main__':
processes = []
for _ in range(4):
p = Process(target=cpu_bound_task)
p.start()
processes.append(p)

for p in processes:
p.join()

این کد تابع cpu_bound_task رو همزمان توی ۴ تا process اجرا میکنه. هر process حافظه، thread و هسته ی CPU خودش رو داره. با اینکار میتونیم واقعا تسک های CPU Bound رو موازی اجرا کنیم و از مزایایی مثل سرعت بهتر بهره مند شیم.
اگه پروژتون بزرگه بهتره تسک های سنگین رو به سیستم هایی مثل Celery بسپرین و از worker های process-based استفاده کنید.

جمع بندی✍️
در نهایت، وقتی با برنامه‌ای سروکار داریم که CPU-bound هست، خیلی مهمه که درست تشخیص بدیم چه راه‌حلی برای بهینه‌سازی استفاده از منابع لازم داریم. توی پایتون، وقتی از multi threading استفاده می‌کنیم، به دلیل محدودیت GIL، همه‌ی پردازش‌ها روی یه هسته و یه thread اجرا می‌شن.
برای این‌که بتونیم از چند هسته‌ی CPU استفاده کنیم و پردازش‌های سنگین رو سریع‌تر انجام بدیم، باید از multi processing بهره بگیریم. با این روش، می‌تونیم هر بخش از برنامه رو به یک process جداگانه اختصاص بدیم که به طور مستقل و هم‌زمان روی هسته‌های مختلف CPU اجرا بشه.

#️⃣ #programmin #python


🥷🏻 CHANNEL | GROUP
👍102
خب خب خب، ‏Background Task ها توی FastAPI🚀
گاهی اوقات نیاز داریم که یه کاری بعد از ارسال پاسخ به کاربر انجام بشه. مثل ارسال ایمیل خوشامد گویی، ثبت لاگ یا آمار توی دیتابیس، پردازش فایل آپلود شده و .... توی این شرایط میتونیم از Background Task ها استفاده کنیم، اینجوری میتونیم بدون معطل کردن کاربر اون کارهارو جداگانه انجام بدیم.

استفاده از Background Task ها🛠
خب اول باید کلاس BackgroundTasks رو ایمپورت کنیم و یه پارامتر از همین نوع برای فانکشن route بنویسیم.
from fastapi import BackgroundTasks, FastAPI

app = FastAPI()


def write_notification(email: str, message=""):
with open("log.txt", mode="w") as email_file:
content = f"notification for {email}: {message}"
email_file.write(content)


@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, email, message="some notification")
return {"message": "Notification sent in the background"}

حالا FastAPI میاد یه آبجکت با نوع BackgroundTasks برامون ایجاد میکنه و به اون پارامتر پاس میده.
بعد از اینکه فانکشن تسکمون رو ایجاد کردیم میتونیم با استفاده از متود ()add_task از همون پارامتر اون فانکشن رو به صف اجرا اضافه کنیم. همچنین میتونیم آرگومان های مورد نیازمون رو هم با استفاده از همین متود به تسکمون پاس بدیم.

‏Background Tasks و Dependency injection💉
‏Background Tasks به خوبی با سیستم تزریق وابستگی FastAPI سازگاره. میتونیم توی سطح های مختلف برنامه(فانکشن route، یه وابستگی و...) از Background Task استفاده کنیم.
from typing import Annotated

from fastapi import BackgroundTasks, Depends, FastAPI

app = FastAPI()


def write_log(message: str):
with open("log.txt", mode="a") as log:
log.write(message)


def get_query(background_tasks: BackgroundTasks, q: str | None = None):
if q:
message = f"found query: {q}\n"
background_tasks.add_task(write_log, message)
return q


@app.post("/send-notification/{email}")
async def send_notification(
email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
):
message = f"message to {email}\n"
background_tasks.add_task(write_log, message)
return {"message": "Message sent"}

توی این مثال بعد از اینکه پاسخ به کلاینت ارسال شد، یه تسک میاد ایمیل کاربر رو توی فایل log.txt مینویسه. اگه یه کوئری پارامتر هم به API ارسال بشه یه تسک دیگه اون رو هم توی فایل مینویسه.

نکته مهم⚠️
این ابزار فقط برای کارهای سبک وسریع مناسبه. مثل همین لاگ نوشتن، ارسال ایمیل یا پردازش های خیلی کوچیک و سبک. برای کارهای سنگین تر مثل پردازش تصویر بهتره که از سیستم هایی مثل Celery استفاده بشه.

جمع بندی✍️
‏Background Task یه ابزار ساده ولی کاربردیه. میتونه توی پروژه هایی که تسک های سنگینی ندارن از Celery بی نیازتون کنه و کارهارو بعد از پاسخ دهی به صورت غیرهمزمان انجام بده.

#️⃣ #fastapi #python #backend


🥷🏻 CHANNEL | GROUP
👍116